<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8821846818714029393</id><updated>2012-01-28T15:02:23.965+01:00</updated><category term='staticpython'/><category term='ruby'/><category term='DPMS'/><category term='outside'/><category term='inside'/><category term='perl'/><category term='panasonic'/><category term='mariadb'/><category term='digital camera'/><category term='concurrence'/><category term='delay'/><category term='zte blade'/><category term='cookie'/><category term='planet-python'/><category term='binary'/><category term='gnome'/><category term='prolog'/><category term='portable'/><category term='announcement'/><category term='sex'/><category term='panel'/><category term='python'/><category term='gevent'/><category term='lumix'/><category term='haskell'/><category term='battery pack'/><category term='X.Org'/><category term='c++'/><category term='X11'/><category term='menu'/><category term='logout'/><category term='java'/><category term='mysql'/><category term='workaround'/><category term='charger'/><category term='cyanogenmod'/><category term='gtk'/><category term='program'/><category term='battery'/><category term='kitchen'/><category term='user inactivity.'/><category term='Switzerland'/><category term='non-geek'/><category term='mysqld'/><category term='android'/><category term='appengine'/><category term='multilingual'/><category term='fake'/><category term='Linux'/><category term='unix'/><category term='li-ion'/><category term='operator definition'/><category term='source code'/><category term='screen blanking'/><category term='screen saver'/><category term='syncless'/><category term='fun'/><category term='ubuntu'/><category term='model'/><category term='beginner'/><title type='text'>pts.blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default?start-index=101&amp;max-results=100'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>136</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-8542901405488463364</id><published>2012-01-24T14:11:00.000+01:00</published><updated>2012-01-24T14:11:32.692+01:00</updated><title type='text'>Guess the programming language with array and dictionary addition</title><content type='html'>&lt;p&gt;Guess the programming language.&lt;ol&gt;&lt;li&gt;In which programming language are all of these true?&lt;ul&gt;&lt;li&gt;&lt;code&gt;[] + []&lt;/code&gt; is an empty string.&lt;li&gt;&lt;code&gt;[] + {}&lt;/code&gt; is an empty object.&lt;li&gt;&lt;code&gt;{} + []&lt;/code&gt; is 0.&lt;li&gt;&lt;code&gt;{} + {}&lt;/code&gt; is not-a-number.&lt;/ul&gt;&lt;li&gt;In which programming language are all of these true?&lt;ul&gt;&lt;li&gt;&lt;code&gt;[] + []&lt;/code&gt; is an empty list.&lt;li&gt;&lt;code&gt;[] + {}&lt;/code&gt; raises TypeError.&lt;li&gt;&lt;code&gt;{} + []&lt;/code&gt; raises TypeError&lt;li&gt;&lt;code&gt;{} + {}&lt;/code&gt; raises TypeError.&lt;/ul&gt;&lt;li&gt;In which programming language are all of these true?&lt;ul&gt;&lt;li&gt;&lt;code&gt;[] + []&lt;/code&gt; is an empty list.&lt;li&gt;&lt;code&gt;[] + {}&lt;/code&gt; raises TypeError.&lt;li&gt;&lt;code&gt;{} + []&lt;/code&gt; raises NoMethodError&lt;li&gt;&lt;code&gt;{} + {}&lt;/code&gt; raises NoMethodError.&lt;/ul&gt;&lt;li&gt;In which programming language are all of these true?&lt;ul&gt;&lt;li&gt;&lt;code&gt;[] + []&lt;/code&gt; is a positive number, e.g. 19806432.&lt;li&gt;&lt;code&gt;[] + {}&lt;/code&gt; is a positive number, e.g. 20142304.&lt;li&gt;&lt;code&gt;{} + []&lt;/code&gt; is a positive number, e.g. 58300640.&lt;li&gt;&lt;code&gt;{} + {}&lt;/code&gt; is a positive number, e.g. 27597024.&lt;/ul&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-8542901405488463364?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/8542901405488463364/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=8542901405488463364' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/8542901405488463364'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/8542901405488463364'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2012/01/guess-programming-language-with-array.html' title='Guess the programming language with array and dictionary addition'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-3359003609193212400</id><published>2012-01-16T22:20:00.003+01:00</published><updated>2012-01-16T22:20:44.587+01:00</updated><title type='text'>How to put the window close button to the right on Ubuntu Lucid</title><content type='html'>&lt;p&gt;This blog post explains how to put the the window close button to the top right corner of the window on Ubuntu Lucid, instead of the top left corner, where new Ubuntu versions tend to put it by default.&lt;p&gt;To put the window close button to the top right corner, and to arrange the other buttuns in the classic (2008 or earlier) layout, run the following command in a terminal window (without the leading &lt;i&gt;$&lt;/i&gt; sign):&lt;pre&gt;$ gconftool-2 --type=string --set /apps/metacity/general/button_layout \&lt;br /&gt;  menu:minimize,maximize,close&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-3359003609193212400?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/3359003609193212400/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=3359003609193212400' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/3359003609193212400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/3359003609193212400'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2012/01/how-to-put-window-close-button-to-right.html' title='How to put the window close button to the right on Ubuntu Lucid'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-8187775258312540777</id><published>2012-01-08T15:37:00.000+01:00</published><updated>2012-01-08T15:37:52.649+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='operator definition'/><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='outside'/><category scheme='http://www.blogger.com/atom/ns#' term='inside'/><title type='text'>C++ operator definitions inside and outside the class are not equivalent</title><content type='html'>&lt;p&gt;This blog post presents some example code which demonstrates that having an operator outside a class is not equivalent to having it inside the class. As shown below, some implicit casts are applied only if the operator definition is outside the class.&lt;p&gt;It compiles when the operator definition is outside:&lt;pre class="syntax"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;C&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;C&lt;/span&gt; &lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;masik&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;C&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Does not compile.&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;It compiles if the operator definition is outside:&lt;pre class="syntax"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;C&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;&lt;br /&gt; &lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;C&lt;/span&gt; &lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;C&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-8187775258312540777?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/8187775258312540777/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=8187775258312540777' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/8187775258312540777'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/8187775258312540777'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2012/01/c-operator-definitions-inside-and.html' title='C++ operator definitions inside and outside the class are not equivalent'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-2461308482086728832</id><published>2011-12-18T20:55:00.001+01:00</published><updated>2011-12-18T20:56:12.134+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='logout'/><category scheme='http://www.blogger.com/atom/ns#' term='cookie'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='workaround'/><category scheme='http://www.blogger.com/atom/ns#' term='planet-python'/><category scheme='http://www.blogger.com/atom/ns#' term='appengine'/><title type='text'>How to log out from an AppEngine app only</title><content type='html'>&lt;p&gt;This blog post explains how to add a logout page to an AppEngine Python application, which will log out of the application only, without logging out of all of Google (e.g. Gmail, Calendar, Picasa, YouTube).&lt;p&gt;The default AppEngine &lt;code&gt;users.create_logout_url(...)&lt;/code&gt; crates a logout URL which would log out from all of Google. To log out from the AppEngine app only, remove the SACSID and ACSID session cookies, which AppEngine has set right after logging in. Here is how to do it in Python:&lt;pre class="syntax"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Cookie&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;google.appengine.api&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;google.appengine.ext&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;webapp&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LogoutPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webapp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestHandler&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;target_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;referer&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;SERVER_SOFTWARE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Development/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;      &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_logout_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br /&gt;      &lt;span class="k"&gt;return&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="c"&gt;# On the production instance, we just remove the session cookie, because&lt;/span&gt;&lt;br /&gt;    &lt;span class="c"&gt;# redirecting users.create_logout_url(...) would log out of all Google&lt;/span&gt;&lt;br /&gt;    &lt;span class="c"&gt;# (e.g. Gmail, Google Calendar).&lt;/span&gt;&lt;br /&gt;    &lt;span class="c"&gt;#&lt;/span&gt;&lt;br /&gt;    &lt;span class="c"&gt;# It seems that AppEngine is setting the ACSID cookie for http:// ,&lt;/span&gt;&lt;br /&gt;    &lt;span class="c"&gt;# and the SACSID cookie for https:// . We just unset both below.&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;cookie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Cookie&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SimpleCookie&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ACSID&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ACSID&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;expires&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;86400&lt;/span&gt;  &lt;span class="c"&gt;# In the past, a day ago.&lt;/span&gt;&lt;br /&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;: &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;cookie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Cookie&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SimpleCookie&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;SACSID&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;SACSID&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;expires&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;86400&lt;/span&gt;&lt;br /&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;: &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br /&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webapp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WSGIApplication&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/logout&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LogoutPage&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;run_wsgi_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;After adding the &lt;i&gt;/logout&lt;/i&gt; page as indicated above, offer the logout link like this:&lt;pre class="syntax"&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&amp;lt;a href=&amp;quot;/logout&amp;quot;&amp;gt;Logout&amp;lt;/a&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;Please note that adding a cookie which expires in the past makes the browser forget about the cookie immediately.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-2461308482086728832?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/2461308482086728832/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=2461308482086728832' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2461308482086728832'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2461308482086728832'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/12/how-to-log-out-from-appengine-app-only.html' title='How to log out from an AppEngine app only'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-1360185710114687724</id><published>2011-12-11T11:35:00.000+01:00</published><updated>2011-12-11T11:35:59.472+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='non-geek'/><category scheme='http://www.blogger.com/atom/ns#' term='Switzerland'/><title type='text'>How to turn off voicemail for Swisscom (.ch) mobiles</title><content type='html'>&lt;p&gt;This blog post explains how to turn off the voicemail service (named COMBOX) provided (and enabled by default) by the Swiss mobile carrier Swisscom.&lt;p&gt;According to &lt;a href="http://www.swisscom-fixnet.ch/FxRes/Files/Combox/Spickzettel_Combox_Mobile_en.pdf"&gt;this PDF&lt;/a&gt;, lined from &lt;a href="http://www.swisscom.ch/res/mobile/combox/index.htm"&gt;http://www.swisscom.ch/res/mobile/combox/index.htm&lt;/a&gt;, dial the following numbers:&lt;ul&gt;&lt;li&gt;##61#&lt;li&gt;##62#&lt;li&gt;##67#&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-1360185710114687724?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/1360185710114687724/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=1360185710114687724' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1360185710114687724'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1360185710114687724'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/12/how-to-turn-off-voicemail-for-swisscom.html' title='How to turn off voicemail for Swisscom (.ch) mobiles'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-5312036117996194991</id><published>2011-11-18T22:34:00.005+01:00</published><updated>2011-11-19T09:15:41.086+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Measure your reaction time using Python</title><content type='html'>&lt;p&gt;Run this in a terminal window (without the leading &lt;code&gt;$&lt;/code&gt;):&lt;pre&gt;$ python -c 'import random, time; time.sleep(2 + 8 * random.random()); \&lt;br /&gt;  print 1; t = time.time(); raw_input(); print time.time() - t'&lt;/pre&gt;&lt;p&gt;Press &lt;i&gt;Enter&lt;/i&gt; as soon as the number &lt;i&gt;1&lt;/i&gt; appears. Your reaction time (in seconds) will be printed. For best results, don't do it over an SSH connection. If you can go below .2 second, then you are most probably not human.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-5312036117996194991?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/5312036117996194991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=5312036117996194991' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/5312036117996194991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/5312036117996194991'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/11/measure-your-reaction-time-using-python.html' title='Measure your reaction time using Python'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-7563479290725352091</id><published>2011-11-13T17:58:00.000+01:00</published><updated>2011-11-13T17:58:10.684+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='binary'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='portable'/><category scheme='http://www.blogger.com/atom/ns#' term='mariadb'/><title type='text'>Announcing Portable MariaDB: Small, portable binary MariaDB distribution for Linux</title><content type='html'>&lt;p&gt;&lt;i&gt;Portable MariaDB&lt;/i&gt; is a small, portable binary distribution of the SQL server MariaDB (Monty's fork of MySQL) for Linux i386 (32-bit). Only the mysqld binary and a versatile init script are included. Portable MariaDB can be run by any user in any directory, it doesn't try to access any mysqld data or config files outside its directory. Portable MariaDB can coexist with regular mysqld (MySQL or MariaDB) and other instances of Portable MariaDB on a single machine, as long as they are not configured to listen on the same TCP port. The only dependency of Portable MariaDB is glibc 2.4 (available in Ubuntu Hardy or later).&lt;p&gt;The most up-to-date documentation of Portable MariaDB is &lt;a href="http://code.google.com/p/pts-mini-gpl/wiki/Portable_MariaDB"&gt;here&lt;/a&gt;.&lt;p&gt;The sources are &lt;a href="http://code.google.com/p/pts-mini-gpl/source/browse/#svn/trunk/portable-mariadb"&gt;here&lt;/a&gt;.&lt;h3&gt;Why use Portable MariaDB?&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;It's small (not bloated). Fast to dowload, fast to extract, fast to install. Quick size comparison: mariadb-5.2.9-Linux-i686.tar.gz is 144 MB, the corresponding Portable MariaDB .tbz2 is less than 6 MB.&lt;li&gt;It's portable: does not interfere with other MySQL server installations on the same machine.&lt;li&gt;It's self-contained and consistent: copy the database and the configuration in a single directory from one machine to another.&lt;/ul&gt;&lt;h3&gt;Installation&lt;/h3&gt;&lt;p&gt;To run Portable MariaDB, you need a Linux system with glibc 2.4 (e.g. Ubuntu Hardy) or later. 32-bit and 64-bit systems are fine. For 64-bit systems you need the 32-bit compatibility libraries installed. You also need Perl.&lt;pre&gt;  $ cd /tmp  # Or any other with write access.&lt;br /&gt;  $ BASE=http://pts-mini-gpl.googlecode.com/svn/trunk/portable-mariadb.release/ &lt;br /&gt;  $ wget -O portable-mariadb.tbz2 $BASE/portable-mariadb.tbz2&lt;br /&gt;  $ tar xjvf portable-mariadb.tbz2&lt;br /&gt;  $ chmod 700 /tmp/portable-mariadb  # For security.&lt;br /&gt;  $ /tmp/portable-mariadb/mariadb_init.pl stop-set-root-password&lt;/pre&gt;&lt;h3&gt;Usage&lt;/h3&gt;&lt;p&gt;For security, don't do anything as root.&lt;pre&gt;  $ cd /tmp/portable-mariadb&lt;br /&gt;  $ ./mariadb_init.pl restart&lt;br /&gt;  Connect with: mysql --socket=/tmp/portable-mariadb/mysqld.sock --user=root --database=test --password&lt;br /&gt;  Connect with: mysql --host=127.0.0.1 --user=root --database=test --password&lt;/pre&gt;&lt;p&gt;Feel free to take a look at &lt;i&gt;/tmp/portable-mariadb/my.cnf&lt;/i&gt;, make modifications, and restart mysqld so that the modifications take effect.&lt;h3&gt;Security&lt;/h3&gt;&lt;p&gt;By default, connections are accepted from localhost (Unix domain socket and TCP) only, all MySQL users are refused (except if a password has been set for root above), and root has unrestricted access. Unix permissions (such as the chmod 700 above) are protecting against data theft and manipulation on the file level.&lt;p&gt;It is strongly recommended to change the password of root to a non-empty, strong password before populating the database.&lt;h3&gt;Java support&lt;/h3&gt;&lt;p&gt;Java clients with JDBC (MySQL Connector/J) are fully supported. Please note that Java doesn't support Unix doman socket, so make sure in &lt;i&gt;my.cnf&lt;/i&gt; that mysqld listens on a TCP port. Please make sure you have &lt;code&gt;?characterEncoding=UTF8&lt;/code&gt; specified in your JDBC connection URL, otherwise some non-ASCII, non-Latin-1 characters would be converted to &lt;code&gt;?&lt;/code&gt;.&lt;h3&gt;Unicode support&lt;/h3&gt;&lt;p&gt;Just as with MariaDB. All encodings and collations are supported. The latin1 encoding is the default, which can be changed in &lt;i&gt;my.cnf&lt;/i&gt;.&lt;h3&gt;Language support&lt;/h3&gt;&lt;p&gt;All natural languages (of MariaDB) are supported for error messages. Set the `language' flag in my.cnf accordingly. English is the default.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-7563479290725352091?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/7563479290725352091/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=7563479290725352091' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7563479290725352091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7563479290725352091'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/11/announcing-portable-mariadb-small.html' title='Announcing Portable MariaDB: Small, portable binary MariaDB distribution for Linux'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-2572006805592994335</id><published>2011-11-10T14:57:00.003+01:00</published><updated>2011-11-10T19:47:49.457+01:00</updated><title type='text'>How to simply compress a C++ string with LZMA</title><content type='html'>&lt;p&gt;This blog post explains how to simply compress C++ with LZMA compression, using liblzma.&lt;p&gt;Use the following functions:&lt;pre class="syntax"&gt;&lt;span class="cp"&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cp"&gt;#include &amp;quot;lzma.h&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="cp"&gt;#include &amp;lt;string&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="c1"&gt;// Level is between 0 (no compression), 9 (slow compression, small output).&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;CompressWithLzma&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;out_pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LZMA_OK&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;lzma_easy_buffer_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LZMA_CHECK_CRC32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class="k"&gt;reinterpret_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;uint8_t&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;())),&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;br /&gt;      &lt;span class="k"&gt;reinterpret_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;uint8_t&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;out_pos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out_pos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;DecompressWithLzma&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;kMemLimit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// 1 GB.&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;lzma_stream&lt;/span&gt; &lt;span class="n"&gt;strm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LZMA_STREAM_INIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8192&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;result_used&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;lzma_ret&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lzma_stream_decoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;strm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kMemLimit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LZMA_CONCATENATED&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;LZMA_OK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;avail0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;strm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next_in&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;reinterpret_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;uint8_t&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;strm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avail_in&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;strm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next_out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;reinterpret_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;uint8_t&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;strm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avail_out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;avail0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lzma_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;strm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avail_in&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;LZMA_FINISH&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;LZMA_RUN&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;LZMA_STREAM_END&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;result_used&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;avail0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;strm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avail_out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;strm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avail_in&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Guaranteed by lzma_stream_decoder().&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result_used&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;lzma_end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;strm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br /&gt;      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;LZMA_OK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avail_out&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;result_used&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;avail0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;strm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avail_out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;strm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next_out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;reinterpret_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;uint8_t&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;result_used&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;strm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avail_out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;avail0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;result_used&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;Please note that in some use cases there may exist a solution which uses less memory.&lt;p&gt;See the &lt;i&gt;liblzma/container.&lt;/i&gt; for documentation of &lt;i&gt;lzma_easy_buffer_encode()&lt;/i&gt;.&lt;p&gt;The decompression code was based on &lt;i&gt;xzdec.c&lt;/i&gt; in &lt;i&gt;xz-utils&lt;/i&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-2572006805592994335?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/2572006805592994335/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=2572006805592994335' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2572006805592994335'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2572006805592994335'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/11/how-to-simply-compress-c-string-with.html' title='How to simply compress a C++ string with LZMA'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-7119090786846714725</id><published>2011-10-27T08:58:00.001+02:00</published><updated>2011-10-27T08:59:03.566+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='battery'/><category scheme='http://www.blogger.com/atom/ns#' term='cyanogenmod'/><category scheme='http://www.blogger.com/atom/ns#' term='zte blade'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Long standby time for Cyanogenmod 7.1 on ZTE Blade phones</title><content type='html'>&lt;p&gt;This is a testimonial of the Cyanogenmod 7.1 Android spinoff operating system on the ZTE Blade phone.&lt;p&gt;I've recently installed Cyanogenmod 7.1 to my ZTE Blade. Prevously I had Cyanogenmod 7.0.3 on it, and the battery life was terrible. It didn't last more than 48 hours in standby (3G, mobile data, wifi, GPS, background synchronization switched off, only receiving a few text messages). But after installing 7.1, the battery lasted for 12 days plus 23 hours in standby mode. Awesome! Finally I have a small and cheap Android phone with long battery life.&lt;p&gt;The phone user interface also feels much snappier now, and 3D games (e.g. Falldown 3D) which lagged and were unplayable with 7.0.3 are fast and playable now.&lt;p&gt;Unfortunately I wasn't able to upgrade 7.0.3 to 7.1, but I had to wipe the phone (keeping only the SD card contents) before installing 7.1.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-7119090786846714725?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/7119090786846714725/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=7119090786846714725' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7119090786846714725'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7119090786846714725'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/10/long-standby-time-for-cyanogenmod-71-on.html' title='Long standby time for Cyanogenmod 7.1 on ZTE Blade phones'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-7707507185556624080</id><published>2011-10-18T13:55:00.003+02:00</published><updated>2011-10-30T18:55:01.323+01:00</updated><title type='text'>Getting started with IntelliJ to write Android applications on Linux</title><content type='html'>This blog post gives instructions to get started with Android application development with IntelliJ on Linux.&lt;ol&gt;&lt;li&gt;Install the Java runtime environment (JRE) and the Java compiler (in the JDK). Command to to it on Ubuntu Lucid: &lt;code&gt;sudo apt-get install openjdk-6-jdk&lt;/code&gt; . Please note that the JRE without the JDK is not enough, IntelliJ needs the JDK.&lt;li&gt;You will need about 1.5 GB of free disk space.&lt;li&gt;Download IntelliJ (either the Ultimate edition or the Community edition; please note that you have to pay for the Ultimate edition after the evaluation period expires) from from. http://www.jetbrains.com/idea/download/ . I've downloaded the file from http://download.jetbrains.com/idea/ideaIU-10.5.2.tar.gz , it was about 160 MB.&lt;li&gt;Download the Android SDK tools from http://developer.android.com/sdk/ . I've downloaded the file from http://dl.google.com/android/android-sdk_r13-linux_x86.tgz . It was about 160 MB.&lt;li&gt;If you ever want to connect a real phone via USB, then follow the instructions http://ptspts.blogspot.com/2011/10/how-to-fix-adb-no-permissions-error-on.html do create and install the &lt;i&gt;android.rules&lt;/i&gt; udev rule. Please also restart the udev service.&lt;li&gt;Extract the downloaded archive &lt;i&gt;android-sdk_r13-linux_x86.tgz&lt;/i&gt; .&lt;li&gt;Run the &lt;i&gt;android-sdk-linux_x86/tools/android&lt;/i&gt; tool.&lt;li&gt;On the &lt;i&gt;Available packages&lt;/i&gt; tab, find and install the following packages:&lt;ul&gt;&lt;li&gt;Android SDK Tools&lt;li&gt;Android SDK Platform-tools&lt;li&gt;Documentation for Android SDK (the latest one)&lt;li&gt;SDK Platform Android 2.2, API 8 (or whichever Android version you are developing for).&lt;li&gt;Samples for SDK API 8 (or whichever Android version you are developing for).&lt;li&gt;Google APIs by Google Inc., Android API 8 (or whichever Android version you are developing for).&lt;li&gt;Android Compatibility package&lt;/ul&gt;&lt;li&gt;In the Virtual devices tab, create a virtual device. Use these settings (make sure to enabling snapshots and disabling audio playback and recording):&lt;div class="separator" style="clear: both; text-align: center; margin:0.5em"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-IJf261Bqrms/Tp1YRiktkWI/AAAAAAAABkI/H-4Rxj7zu8c/s1600/barvirt.png" width="400" height="547" /&gt;&lt;/div&gt;&lt;li&gt;Start the virtual device, play with it (it's an emulated Android phone), watch how it eats your CPU capacity, and stop it by closing the emulator window.&lt;li&gt;Please note that the emulator is very slow. It will happily eat 100% even if the virtual device is idle. When you disable sound playback and sound recording, it still eats about 800 MHz (tested on Intel(R) Core(TM)2 Duo CPU P9500 @ 2.53GHz).&lt;li&gt;A possible bug in the Android emulator: The &lt;i&gt;Launch from snapshot&lt;/i&gt; functionality didn't work for me in the emulator, even though the snapshot was present.&lt;li&gt;In the file &lt;i&gt;~/Downloads/idea-IU-107.587/bin/idea.sh&lt;/i&gt; (the actual filename may depend on where you have downloaded and extracted IntelliJ to), change the line containing &lt;code&gt;OPEN_JDK=$?&lt;/code&gt; to &lt;code&gt;OPEN_JDK=1&lt;/code&gt; . This will disable the startup warning.&lt;li&gt;Start IntelliJ. Enter license data (or choose evaluation), accept the license agreement, just click OK in the &lt;i&gt;Select VCS Integration&lt;/i&gt; dialog (or select a superset of the version control systems you are planning to use), unselect all Web/JavaEE plugins (they are not needed for Android development), unselect all the HTML/JavaScript plugins, in the Other plugins dialog select at least these: Android, GenerateToString, Inspection Gadgets, Intention Power Pack, JUnit, Remote Hosts Access, SpellChecker, Structural Search, Task Management, Type Migration; make sure Android is checked; finish the installation.&lt;li&gt;File / New project. Create project from scratch. Next. Name: afirst. Select type: Android Module. Next. Create source... src. Next. Project JDK / Configure. &lt;i&gt;/usr/lib/jvm/java-6-openjdk&lt;/i&gt; . OK. Next. Android SDK: ... . In the top left corner of the window, click +, and select Android SDK. Specify &lt;i&gt;/home/USERNAME/Downloads/android-sdk-linux_x86&lt;/i&gt; (where you have downloaded and extracted the Android SDK to). Select internal JDK: 1.6. OK. Select build target: Android 2.2 (or the Android version of your choice). OK. OK. Now you are back in the Create project wizard, with the Android SDK: selection containing &lt;i&gt;Android 2.2 Platform&lt;/i&gt;. Finish.&lt;li&gt;Wait a few minutes until the project tree &lt;i&gt;afirst&lt;/i&gt; appears. Open afirst. Open src. Open com.example. Double click on MyActivity. The MyActivity.java source file appears.&lt;li&gt;Make sure the virtual device barvirt is running in the Android emulator. Play it safe and restart the emulator.&lt;li&gt;Stop adb: &lt;code&gt;sudo ~/Downloads/android-sdk-linux_x86/platform-tools/adb kill-server&lt;/code&gt;&lt;li&gt;Restart adb: &lt;code&gt;sudo ~/Downloads/android-sdk-linux_x86/platform-tools/adb devices&lt;/code&gt;&lt;li&gt;In IntelliJ Run / Edit configurations, set up devices and virtual devices like this:&lt;div class="separator" style="clear: both; text-align: center; margin:0.5em"&gt;&lt;img border="0" width="525" height="504" src="http://1.bp.blogspot.com/-LT_GdhhJHIQ/Tp1ufTuMg9I/AAAAAAAABkU/WrdTxHE27nM/s1600/runconf.png" /&gt;&lt;/div&gt;&lt;li&gt;In IntelliJ: Run / Run. Wait a minute. The app should start on the emulator.&lt;li&gt;Connect your phone with USB debugging enabled (in Settings / Applications / Development). In IntelliJ: Run / Run. Wait a minute. The app should start on the phone.&lt;/ol&gt;&lt;p&gt;Typical IntelliJ message for starting the app on the phone:&lt;pre&gt;Waiting for device.&lt;br /&gt;Target device: 1234567890ABCDEF&lt;br /&gt;Uploading file&lt;br /&gt; local path: /home/pts/IdeaProjects/afirst/out/production/afirst/afirst.apk&lt;br /&gt; remote path: /data/local/tmp/com.example&lt;br /&gt;Installing com.example&lt;br /&gt;DEVICE SHELL COMMAND: pm install -r "/data/local/tmp/com.example"&lt;br /&gt;pkg: /data/local/tmp/com.example&lt;br /&gt;Success&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Launching application: com.example/com.example.MyActivity.&lt;br /&gt;DEVICE SHELL COMMAND: am start -n "com.example/com.example.MyActivity"&lt;br /&gt;Starting: Intent { cmp=com.example/.MyActivity }&lt;/pre&gt;&lt;p&gt;Typical IntelliJ message for starting the app on the emulator:&lt;pre&gt;Waiting for device.&lt;br /&gt;Target device: emulator-5554 (barvirt)&lt;br /&gt;Uploading file&lt;br /&gt; local path: /home/pts/IdeaProjects/afirst/out/production/afirst/afirst.apk&lt;br /&gt; remote path: /data/local/tmp/com.example&lt;br /&gt;Installing com.example&lt;br /&gt;DEVICE SHELL COMMAND: pm install -r "/data/local/tmp/com.example"&lt;br /&gt;pkg: /data/local/tmp/com.example&lt;br /&gt;Success&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Launching application: com.example/com.example.MyActivity.&lt;br /&gt;DEVICE SHELL COMMAND: am start -n "com.example/com.example.MyActivity"&lt;br /&gt;Starting: Intent { cmp=com.example/.MyActivity }&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-7707507185556624080?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/7707507185556624080/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=7707507185556624080' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7707507185556624080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7707507185556624080'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/10/getting-started-with-intellij-to-write.html' title='Getting started with IntelliJ to write Android applications on Linux'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-IJf261Bqrms/Tp1YRiktkWI/AAAAAAAABkI/H-4Rxj7zu8c/s72-c/barvirt.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-4934794540250765582</id><published>2011-10-06T12:08:00.000+02:00</published><updated>2011-10-06T12:08:48.037+02:00</updated><title type='text'>Named return value optimization in gcc</title><content type='html'>&lt;p&gt;This blog post demonstrates that GCC 4.1 does &lt;a href="http://en.wikipedia.org/wiki/Return_value_optimization"&gt;Named return value optimization&lt;/a&gt;, i.e. it omits creating a temporary object in a function returning an object if all &lt;code&gt;return&lt;/code&gt; statements in the function return the same local variable.Example code:&lt;pre class="syntax"&gt;&lt;span class="cp"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;C&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;+&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;-&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;=&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;C&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;C&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;C&lt;/span&gt; &lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;C&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;C&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;~~~&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;The output, as expected, even without &lt;code&gt;-O...&lt;/code&gt; compiler optimization flags:&lt;pre&gt;$ g++ test_return_object.cc &amp;&amp; ./a.out&lt;br /&gt;+&lt;br /&gt;-&lt;br /&gt;~~~&lt;br /&gt;+&lt;br /&gt;:&lt;br /&gt;-&lt;br /&gt;-&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-4934794540250765582?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/4934794540250765582/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=4934794540250765582' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/4934794540250765582'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/4934794540250765582'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/10/named-return-value-optimization-in-gcc.html' title='Named return value optimization in gcc'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-1569764969189740275</id><published>2011-10-04T11:34:00.000+02:00</published><updated>2011-10-04T11:34:44.036+02:00</updated><title type='text'>How to initiate and receive voice and video calls from within Gmail?</title><content type='html'>&lt;p&gt;This blog post explains how to set up Gmail so it will be able to initiate and receive voice and video calls.&lt;ol&gt;&lt;li&gt;Download and install the &lt;i&gt;Google Talk Plugin&lt;/i&gt; from &lt;a href="http://www.google.com/chat/video"&gt;here&lt;/a&gt;.&lt;li&gt;Restart your browser, preferably Google Chrome.&lt;li&gt;Log into gmail in your browser.&lt;li&gt;In the top right corner click on the cogwheel icon, and then select &lt;i&gt;Mail settings&lt;/i&gt;.&lt;li&gt;In the &lt;i&gt;Chat&lt;/i&gt; tab, set up the settings of &lt;i&gt;Voice and video chat&lt;/i&gt;.&lt;li&gt;Click on &lt;i&gt;Verify your settings&lt;/i&gt; and make sure it works properly.&lt;li&gt;Save the settings (&lt;i&gt;Save Changes&lt;/i&gt;).&lt;li&gt;Select a friend in the chat list, open a chat window. In the chat window there will be a phone or camera icon, with which you can start the voice or video chat.&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-1569764969189740275?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/1569764969189740275/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=1569764969189740275' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1569764969189740275'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1569764969189740275'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/10/how-to-initiate-and-receive-voice-and.html' title='How to initiate and receive voice and video calls from within Gmail?'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-4307245725081075919</id><published>2011-10-02T14:59:00.002+02:00</published><updated>2011-12-15T01:37:18.589+01:00</updated><title type='text'>How to fix the adb no permissions error on Ubuntu Lucid</title><content type='html'>&lt;p&gt;This blog post explains how to fix the &lt;i&gt;no permissions&lt;/i&gt; error the Android Debugger displays when running the &lt;i&gt;adb devices&lt;/i&gt; command Linux. The solutions presented here have been tested and found working on Ubuntu Lucid, but they should also work on other Ubuntu and Linux versions as well.&lt;p&gt;This &lt;a href="http://www.google.com/support/forum/p/android/thread?tid=08945730bbd7b22b"&gt;official help center page&lt;/a&gt; has many working and non-working answers to the problem, and many comments. The root cause of the problem is that the current user doesn't have sufficient permissions to access the USB device file created when the phone was connected in USB debug mode.&lt;p&gt;Killing all running &lt;i&gt;adb&lt;/i&gt; server instances with &lt;i&gt;sudo killall adb&lt;/i&gt;, disconnecting the phone, reconnecting the phone, and then running &lt;i&gt;sudo adb devices&lt;/i&gt; instead (so &lt;i&gt;adb&lt;/i&gt; gets run as root) fixes the problem.&lt;p&gt;Alternatively, it is possible to implement a long-term fix which doesn't require &lt;i&gt;sudo&lt;/i&gt;, thus it works with e.g. IntelliJ IDE integration:&lt;ul&gt;&lt;li&gt;Create a file named &lt;i&gt;/tmp/android.rules&lt;/i&gt; with the following contents (hex vendor numbers were taken from the &lt;a href="http://developer.android.com/guide/developing/device.html#VendorIds"&gt;vendor list page&lt;/a&gt;):&lt;pre&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="0bb4", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="0502", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="0b05", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="413c", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="0489", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="091e", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="18d1", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="0bb4", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="12d1", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="24e3", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="2116", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="0482", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="17ef", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="1004", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="22b8", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="0409", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="2080", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="0955", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="2257", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="10a9", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="1d4d", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="0471", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="04da", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="05c6", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="1f53", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="04e8", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="04dd", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="0fce", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="0930", MODE="0666"&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="19d2", MODE="0666"&lt;/pre&gt;&lt;li&gt;Run the following commands (without the leading &lt;code&gt;$&lt;/code&gt;):&lt;pre&gt;$ sudo cp /tmp/android.rules /etc/udev/rules.d/51-android.rules&lt;br /&gt;$ sudo chmod 644   /etc/udev/rules.d/51-android.rules&lt;br /&gt;$ sudo chown root. /etc/udev/rules.d/51-android.rules&lt;br /&gt;$ sudo service udev restart&lt;br /&gt;$ sudo killall adb&lt;/pre&gt;&lt;li&gt;Disconnect the USB cable between the phone and the computer.&lt;li&gt;Reconnect the phone.&lt;li&gt;Run &lt;i&gt;adb devices&lt;/i&gt; to confirm that now it has permission to access the phone.&lt;/ul&gt;&lt;p&gt;Please note that it's possible to use &lt;code&gt;, USER="$LOGINNAME"&lt;/code&gt; instead of &lt;code&gt;, MODE="0666"&lt;/code&gt; in the .rules file, substituting &lt;code&gt;$LOGINNAME&lt;/code&gt; for your login name, i.e. what &lt;i&gt;id -nu&lt;/i&gt; prints.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-4307245725081075919?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/4307245725081075919/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=4307245725081075919' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/4307245725081075919'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/4307245725081075919'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/10/how-to-fix-adb-no-permissions-error-on.html' title='How to fix the adb no permissions error on Ubuntu Lucid'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-6519185096345637941</id><published>2011-09-09T19:01:00.000+02:00</published><updated>2011-09-09T19:01:33.501+02:00</updated><title type='text'>How to install kradview on Ubuntu Lucid</title><content type='html'>&lt;p&gt;This blog post explains how to install and run &lt;i&gt;kradview&lt;/i&gt; on Ubuntu Lucid.&lt;p&gt;Compiling and installing:&lt;pre&gt;$ sudo apt-get install libqt3-headers kdelibs4-dev&lt;br /&gt;$ wget -O /tmp/kradview-1.1.0.tgz http://www.orcero.org/irbis/kradview/kradview-1.1.0.tgz&lt;br /&gt;$ (cd /tmp &amp;&amp; tar xzvf kradview-1.1.0.tgz)&lt;br /&gt;$ cd /tmp/kradview-1.1.0&lt;br /&gt;$ ./configure --without-arts&lt;br /&gt;$ make&lt;br /&gt;$ sudo make install&lt;br /&gt;$ sudo ln -sf ../kde/bin/kradview /usr/local/bin/kradview&lt;/pre&gt;&lt;p&gt;Running:&lt;pre&gt;$ kradview&lt;/pre&gt;&lt;p&gt;Running with a file preopened:&lt;pre&gt;$ kradview FILENAME&lt;/pre&gt;&lt;p&gt;Please note that it might not be necessary to install &lt;i&gt;kradview,&lt;/i&gt; because the &lt;i&gt;display&lt;/i&gt; utility of ImageMagick may be able to display the image. Installation: &lt;code&gt;$ sudo apt-get install imagemagick&lt;/code&gt; . Usage: &lt;code&gt;$ display FILENAME&lt;/code&gt; .&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-6519185096345637941?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/6519185096345637941/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=6519185096345637941' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/6519185096345637941'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/6519185096345637941'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/09/how-to-install-kradview-on-ubuntu-lucid.html' title='How to install kradview on Ubuntu Lucid'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-7723991495156355426</id><published>2011-08-06T15:58:00.001+02:00</published><updated>2011-08-06T15:59:23.308+02:00</updated><title type='text'>How to set up Skype notifications on Linux to be non-distruptive</title><content type='html'>&lt;p&gt;This blog post presents my Skype notification setup on Linux. This setup contains no audio notifications and only a few visual notifications which don't disturb my regular work.&lt;p&gt;In the Skype &lt;i&gt;Options&lt;/i&gt; dialog box, select the &lt;i&gt;Chat&lt;/i&gt; tab, and set it up like this:&lt;ul&gt;&lt;li&gt;When somebody starts a chat with me...: Create a minimised chat window&lt;li&gt;Show emoticons: yes&lt;li&gt;Show animated emoticons: no&lt;/ul&gt;&lt;p&gt;In the Skype &lt;i&gt;Options&lt;/i&gt; dialog box, select the &lt;i&gt;Notifications&lt;/i&gt; tab, and set it up like this:&lt;ul&gt;&lt;li&gt;Skype Login: no Enable Event&lt;li&gt;Skype Logout: no Enable Event&lt;li&gt;Skype Login Failed: Enable Event, no sound file&lt;li&gt;Contact Came Online: no Enable Event&lt;li&gt;Contact Went Offline: no Enable Event&lt;li&gt;First Chat Message Received: Enable Event, no sound file, Display pop-up notification&lt;li&gt;Chat Message Received: Enable Event, no sound file, Display pop-up notification&lt;li&gt;Chat Message Sent: no Enable Event&lt;/ul&gt;&lt;p&gt;Apply the settings, and close the &lt;i&gt;Options&lt;/i&gt; dialog box.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-7723991495156355426?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/7723991495156355426/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=7723991495156355426' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7723991495156355426'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7723991495156355426'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/08/how-to-set-up-skype-notifications-on.html' title='How to set up Skype notifications on Linux to be non-distruptive'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-6287920945707159631</id><published>2011-08-06T15:44:00.002+02:00</published><updated>2012-01-08T21:09:32.794+01:00</updated><title type='text'>How to set up a compact desktop theme on Ubuntu Lucid</title><content type='html'>&lt;p&gt;This blog post explains how to set up a compact GNOME desktop theme on Ubuntu Lucid, i.e. such a theme which consumes little screen real estate, leaving space for the contents you work on.&lt;p&gt;Install and activate the necessary small fonts (FixedSC and Helvetica), as described in this &lt;a href="http://ptspts.blogspot.com/2010/06/how-to-enable-bitmap-fonts-on-ubuntu.html"&gt;blog post&lt;/a&gt;.&lt;p&gt;Select the FixedSC font in GNOME Terminal.&lt;p&gt;Run this command (without the $) to install GNOME themes:&lt;pre&gt;$ sudo apt-get install gnome-themes{,-extras,-more,-selected,-ubuntu}&lt;/pre&gt;&lt;p&gt;In &lt;i&gt;System / Preferences / Appearance / Theme / Customize&lt;/i&gt;, select the following themes:&lt;ul&gt;&lt;li&gt;Controls: &lt;i&gt;Simple&lt;/i&gt;&lt;li&gt;Window Border: &lt;i&gt;Mist&lt;/i&gt;&lt;li&gt;Icons: &lt;i&gt;Mist&lt;/i&gt;&lt;/ul&gt;&lt;p&gt;Some of the changes take effect immediately, but you may have to restart some applications.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-6287920945707159631?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/6287920945707159631/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=6287920945707159631' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/6287920945707159631'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/6287920945707159631'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/08/how-to-set-up-compact-desktop-theme-on.html' title='How to set up a compact desktop theme on Ubuntu Lucid'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-1929873753993874461</id><published>2011-08-06T15:28:00.001+02:00</published><updated>2011-08-06T15:29:17.606+02:00</updated><title type='text'>How to set up nicely hinted default fonts on Linux</title><content type='html'>&lt;p&gt;This blog post explains how to set up a per-user default font configuration under Linux (tested on Ubuntu Lucid), which contains easy-to-read fonts in small sizes and properly hinted rendering.&lt;p&gt;Install the Microsoft core fonts (e.g. Times New Roman, Arial, Courier New), using the following command (without the $ sign):&lt;pre&gt;$ sudo apt-get install msttcorefonts&lt;/pre&gt;&lt;p&gt;Create (or overwrite) the file &lt;code&gt;~/.fonts.conf&lt;/code&gt; with the following contents:&lt;pre&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE fontconfig SYSTEM "fonts.dtd"&amp;gt;&lt;br /&gt;&amp;lt;fontconfig&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- Accept bitmap fonts --&amp;gt;&lt;br /&gt;  &amp;lt;selectfont&amp;gt;&lt;br /&gt;    &amp;lt;acceptfont&amp;gt;&lt;br /&gt;    &amp;lt;pattern&amp;gt;&lt;br /&gt;      &amp;lt;patelt name="scalable"&amp;gt;&amp;lt;bool&amp;gt;false&amp;lt;/bool&amp;gt;&amp;lt;/patelt&amp;gt;&lt;br /&gt;    &amp;lt;/pattern&amp;gt;&lt;br /&gt;    &amp;lt;/acceptfont&amp;gt;&lt;br /&gt;  &amp;lt;/selectfont&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!--  Enable proper hinting (medium) and disable subpixel rendering (rgba=none)&lt;br /&gt;      for the Microsoft Core fonts (msttcorefonts) with high quality hints.&lt;br /&gt;  --&amp;gt; &lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;Andale mono&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;Arial&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;Arial Black&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;Comic Sans MS&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;Courier New&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;Georgia&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;Impact&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;Times New Roman&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;Trebouchet MS&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;Verdana&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;Webdings&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!--  Just a safe bet: enable proper hinting for the DejaVu font family.&lt;br /&gt;      Bitstream Vera is not shipped on Ubuntu Lucid anymore (but there was a&lt;br /&gt;      package on Ubuntu Hardy).&lt;br /&gt;  --&amp;gt; &lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;DejaVu Sans&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;DejaVu Sans Mono&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;DejaVu Sans,DejaVu Sans Condensed&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;DejaVu Sans Condensed&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;DejaVu Sans,DejaVu Sans Light&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;DejaVu Sans Light&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;DejaVu Serif&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;DejaVu Serif,DejaVu Serif Condensed&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;  &amp;lt;match target="font"&amp;gt;&lt;br /&gt;    &amp;lt;test name="family"&amp;gt;&amp;lt;string&amp;gt;DejaVu Serif Condensed&amp;lt;/string&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;test name="pixelsize" compare="more"&amp;gt;&amp;lt;double&amp;gt;7.5&amp;lt;/double&amp;gt;&amp;lt;/test&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hinting"&amp;gt;&amp;lt;bool&amp;gt;true&amp;lt;/bool&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="hintstyle"&amp;gt;&amp;lt;const&amp;gt;hintmedium&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;    &amp;lt;edit name="rgba"&amp;gt;&amp;lt;const&amp;gt;none&amp;lt;/const&amp;gt;&amp;lt;/edit&amp;gt;&lt;br /&gt;  &amp;lt;/match&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- Set font family preferences for Firefox. Chrome seems to ignore these.&lt;br /&gt;     Please note that /etc/fonts/conf.d/60-latin.conf has more defaults, which&lt;br /&gt;     we don't have to repeat here.&lt;br /&gt;  --&amp;gt;&lt;br /&gt;  &amp;lt;alias&amp;gt;&amp;lt;family&amp;gt;serif&amp;lt;/family&amp;gt;&amp;lt;prefer&amp;gt;&lt;br /&gt;    &amp;lt;family&amp;gt;Times New Roman&amp;lt;/family&amp;gt;&lt;br /&gt;  &amp;lt;/prefer&amp;gt;&amp;lt;/alias&amp;gt;&lt;br /&gt;  &amp;lt;alias&amp;gt;&amp;lt;family&amp;gt;sans-serif&amp;lt;/family&amp;gt;&amp;lt;prefer&amp;gt;&lt;br /&gt;    &amp;lt;family&amp;gt;Arial&amp;lt;/family&amp;gt;&lt;br /&gt;  &amp;lt;/prefer&amp;gt;&amp;lt;/alias&amp;gt;&lt;br /&gt;  &amp;lt;alias&amp;gt;&amp;lt;family&amp;gt;monospace&amp;lt;/family&amp;gt;&amp;lt;prefer&amp;gt;&lt;br /&gt;    &amp;lt;family&amp;gt;DejaVu Sans Mono&amp;lt;/family&amp;gt;&lt;br /&gt;  &amp;lt;/prefer&amp;gt;&amp;lt;/alias&amp;gt;&lt;br /&gt;&amp;lt;/fontconfig&amp;gt;&lt;/pre&gt;&lt;p&gt;The &lt;i&gt;hintmedium&lt;/i&gt; setting above is especially important, because it turns on the proper hinting for Times New Roman etc., which makes these fonts easy to read at small sizes. The default is &lt;i&gt;slight&lt;/i&gt; hinting (instead of &lt;i&gt;medium&lt;/i&gt;), which is wrong, and it remains wrong (because of a bug) even if you select it at &lt;i&gt;System / Preferences / Appearance / Fonts / Details / Hinting / Medium&lt;/i&gt;. The proper way to get the &lt;i&gt;medium&lt;/i&gt; hinting is to write a &lt;i&gt;~/.fonts.conf&lt;/i&gt; file, as above.&lt;p&gt;After changing &lt;i&gt;~/.fonts.conf&lt;/i&gt; log out and back in, or restart all applications for the changes to take effect.&lt;p&gt;Google Chrome doesn't pay attention to the default fonts specified in &lt;i&gt;~/.fonts.conf&lt;/i&gt;. In Chrome, visit &lt;a href="chrome://settings/fonts"&gt;chrome://settings/fonts&lt;/a&gt;, and change the defaults to:&lt;ul&gt;&lt;li&gt;Standard Font: &lt;i&gt;Times New Roman&lt;/i&gt;&lt;li&gt;Serif Font: &lt;i&gt;Times New Roman&lt;/i&gt;&lt;li&gt;Sans Serif Font: &lt;i&gt;Arial&lt;/i&gt;&lt;li&gt;Fixed-Width Font: &lt;i&gt;DejaVu Sans Mono&lt;/i&gt;&lt;/ul&gt;&lt;p&gt;You may want to change the window title and dialog box fonts as well. You can do that in &lt;i&gt;System / Preferences / Appearance / Fonts&lt;/i&gt;. See this &lt;a href="http://ptspts.blogspot.com/2010/06/how-to-enable-bitmap-fonts-on-ubuntu.html"&gt;blog post&lt;/a&gt; for some crisp (i.e. non-antialiased), small font size defaults. Don't forget to install the FixedSC and Helxetica fonts first, as documented there.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-1929873753993874461?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/1929873753993874461/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=1929873753993874461' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1929873753993874461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1929873753993874461'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/08/how-to-set-up-nicely-hinted-default.html' title='How to set up nicely hinted default fonts on Linux'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-5111181831070754669</id><published>2011-08-06T13:58:00.001+02:00</published><updated>2011-08-06T13:58:47.694+02:00</updated><title type='text'>How to set up English search in Google Chrome</title><content type='html'>&lt;p&gt;This blog post explains how to set up the default search engine to Google in English language in Google Chrome.&lt;p&gt;By default, if Google is the default search engine in Google Chrome, it returns the search result in the language of the country which is autodetected as the location of the computer. This is bad behavior for most English-speaking travelers, who always want the search results in English, no matter which country they are visiting.&lt;p&gt;To fix it for yourself, go to &lt;a href="chrome://settings/searchEngines"&gt;chrome://settings/searchEngines&lt;/a&gt; in Chrome, and add a new search engine named &lt;i&gt;Google in English&lt;/i&gt;, the shortcut (second column) being &lt;i&gt;gg&lt;/i&gt; , and the URL being &lt;i&gt;http://www.google.com/search?hl=en&amp;q=%s&lt;/i&gt; . Save it, make it the default, and remove all other search engines with &lt;i&gt;Google&lt;/i&gt; in their name.&lt;p&gt;From now on, you can type a search query to the address bar (optionally prefixed by &lt;i&gt;gg&lt;/i&gt; and a space), and you will get Google results in English.&lt;p&gt;Unfortunately the search engine setting is not synchronized between your Google Chrome installations, so you have to configure it manually on each machine and login account.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-5111181831070754669?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/5111181831070754669/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=5111181831070754669' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/5111181831070754669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/5111181831070754669'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/08/how-to-set-up-english-search-in-google.html' title='How to set up English search in Google Chrome'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-2493733414755027611</id><published>2011-08-04T20:23:00.002+02:00</published><updated>2011-08-07T12:34:41.384+02:00</updated><title type='text'>How to disable cursor blinking in GNOME applications</title><content type='html'>&lt;p&gt;This blog post explains how to make the cursor not blink in text input and text area widgets in GNOME applications (including GNOME Terminal). The settings have been tested and found working on Ubuntu Lucid.&lt;p&gt;Run the following commands (without the leading &lt;code&gt;$&lt;/code&gt;) in a terminal window:&lt;pre&gt;$ gconftool-2 --set /desktop/gnome/interface/cursor_blink --type boolean False&lt;br /&gt;$ gconftool-2 --set /apps/gnome-terminal/profiles/Default/cursor_blink --type boolean False&lt;br /&gt;$ gconftool-2 --set /apps/gnome-terminal/profiles/Default/cursor_blink_mode --type string off&lt;/pre&gt;&lt;p&gt;Changes take effect immediately, there is no need to restart running applications.&lt;p&gt;These changes also affect Google Chrome (including the address bar and input fields and textarea fields on the page). However, changes don't take effect within a pages in existing tabs, so you should close them, and create new tabs.&lt;p&gt;If some cursors still Please see this &lt;a href="http://www.jurta.org/en/prog/noblink"&gt;noblink page&lt;/a&gt; to disable blinking in Emacs, XEmacs, GVIM, GTK, Gimp, Qt, LessTif, Mozilla Firefox, Mozilla Thunderbird, Google Chrome, TCL/Tk, Linux console and Microsoft Windows.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-2493733414755027611?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/2493733414755027611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=2493733414755027611' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2493733414755027611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2493733414755027611'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/08/how-to-disable-cursor-blinking-in-gnome.html' title='How to disable cursor blinking in GNOME applications'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-2737430587231999625</id><published>2011-08-04T11:28:00.000+02:00</published><updated>2011-08-04T11:28:28.250+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='multilingual'/><title type='text'>How to write hello-world in both Java and C++</title><content type='html'>&lt;p&gt;This blog post explains hwo to write a hello-world program which compiles in both Java and C++.&lt;p&gt;The following solution makes use of the language difference that &lt;code&gt;//...\&lt;/code&gt; continues the one-line comment in C++, but not in Java.&lt;pre&gt;//\&lt;br /&gt;class t{public static void main(String[]a){System.out.print/*&lt;br /&gt;#include&amp;lt;stdio.h&amp;gt;&lt;br /&gt;int main(){if(1){return!printf//*/&lt;br /&gt;("Hello, World!\n");}}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-2737430587231999625?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/2737430587231999625/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=2737430587231999625' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2737430587231999625'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2737430587231999625'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/08/how-to-write-hello-world-in-both-java.html' title='How to write hello-world in both Java and C++'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-6611268500018229472</id><published>2011-06-24T23:52:00.000+02:00</published><updated>2011-06-24T23:52:42.099+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='staticpython'/><category scheme='http://www.blogger.com/atom/ns#' term='planet-python'/><title type='text'>Python 3.2 binaries released in StaticPython for Linux</title><content type='html'>&lt;p&gt;This blog post is to announce that &lt;a href="http://code.google.com/p/pts-mini-gpl/wiki/StaticPython"&gt;StaticPython&lt;/a&gt;, a binary distribution of Python, has just released Python 3.2 binaries for Linux. (Previously StaticPython contained only Python 2.7 binaries.) Download links for the binaries:&lt;ul&gt;&lt;li&gt;&lt;a href="http://pts-mini-gpl.googlecode.com/svn/trunk/staticpython/release/python3.2-static"&gt;python3.2&lt;/a&gt;: almost all built-in Python modules, C extensions (including &lt;i&gt;sqlite3&lt;/i&gt;) and &lt;i&gt;greenlet&lt;/i&gt;&lt;li&gt;&lt;a href="http://pts-mini-gpl.googlecode.com/svn/trunk/staticpython/release/stackless3.2-static"&gt;stackless3.2&lt;/a&gt;: ditto, but with Stackless Python&lt;li&gt;&lt;a href="http://pts-mini-gpl.googlecode.com/svn/trunk/staticpython/release/stacklessxl3.2-static"&gt;stacklessxl3.2&lt;/a&gt;: ditto, and also OpenSSL (with the &lt;i&gt;_ssl&lt;/i&gt; and &lt;i&gt;_hashlib&lt;/i&gt; modules)&lt;/ul&gt;&lt;p&gt;The Python 3.2 binaries of StaticPython can be useful on Linux and FreeBSD systems where Python 3.2 distribution packages are not available, and recompiling from source would be too inconvenient. They can also be used to demo the features of Python 3 for users with a little time and patience, and without a commitment to install it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-6611268500018229472?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/6611268500018229472/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=6611268500018229472' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/6611268500018229472'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/6611268500018229472'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/06/python-32-binaries-released-in.html' title='Python 3.2 binaries released in StaticPython for Linux'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-1331084042550200155</id><published>2011-06-05T18:56:00.000+02:00</published><updated>2011-06-05T18:56:19.813+02:00</updated><title type='text'>PTetriS/HTML: A minimalistic, but correct Tetris-clone in HTML + JavaScript</title><content type='html'>&lt;p&gt;This blog post is to announce &lt;i&gt;PTetriS/HTML&lt;/i&gt;, a minimalistic, but correct Tetris-clone in HTML + JavaScript. &lt;a href="http://pts.szit.bme.hu/ptetrishtml.html"&gt;Play PTetriS/HTML here&lt;/a&gt;, with a JavaScript-enabled browser.&lt;p&gt;PTetris/HTML was born to celebrate the coming 10-year anniversary of &lt;i&gt;PTetris&lt;/i&gt;, the same Tetris-clone implemented as a Java applet and application. &lt;a href="http://pts.szit.bme.hu/ptetris/"&gt;Play PTetriS here&lt;/a&gt;, with a Java-enabled browser.&lt;p&gt;Please note that the PTetriS games are not feature rich (e.g. they don't count the score and they don't show the next brick, and they don't have multiple levels). This is intentional, so they can work as a reference implementation of a correct Tetris game. By correct I mean that the board size is correct, bricks rotate in the correct direction, and the rotation pixel pattern of the bricks is correct (e.g. they don't jump up or down when changing the rotation phase). These properties are copied from the old game FUXOFT's Tetris2 (architecture: ZX Spectrum). There are many Tetris-clones available nowadays which are incorrect.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-1331084042550200155?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/1331084042550200155/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=1331084042550200155' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1331084042550200155'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1331084042550200155'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/06/ptetrishtml-minimalistic-but-correct.html' title='PTetriS/HTML: A minimalistic, but correct Tetris-clone in HTML + JavaScript'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-2956403428860063116</id><published>2011-06-04T02:11:00.000+02:00</published><updated>2011-06-04T02:11:03.313+02:00</updated><title type='text'>How to download a https:// page in Ruby 1.8</title><content type='html'>&lt;p&gt;This blog post shows an example low-level implementation of downloading a https:// page in Ruby 1.8. The reason why is this blog post was born is that the documentation of the &lt;i&gt;openssl&lt;/i&gt; and &lt;i&gt;socket&lt;/i&gt; Ruby modules didn't contain a working end-to-end example.&lt;pre class="syntax"&gt;&lt;span class="c1"&gt;#! /usr/bin/ruby1.8&lt;/span&gt;&lt;br /&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;socket&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;openssl&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span class="c1"&gt;# Returns a HTTP response header + body.&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;download_https&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;suburl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;TCPSocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;www.gmail.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;begin&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;ss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;OpenSSL&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SSL&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SSLSocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;begin&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;ss&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;GET &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;suburl&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; HTTP/1.0&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;Host: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;ensure&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;ensure&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="n"&gt;download_https&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;www.gmail.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;Please note that this doesn't check the authenticity of the server, i.e. it will happily and silently accept self-signed certificates.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-2956403428860063116?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/2956403428860063116/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=2956403428860063116' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2956403428860063116'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2956403428860063116'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/06/how-to-download-https-page-in-ruby-18.html' title='How to download a https:// page in Ruby 1.8'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-4093695559660152550</id><published>2011-05-19T15:00:00.002+02:00</published><updated>2011-05-19T15:21:28.214+02:00</updated><title type='text'>jtty-builder: easy-to-install JSP web server for Unix</title><content type='html'>&lt;p&gt;This blog post is an announcement for &lt;i&gt;jtty-builder&lt;/i&gt;, an easy-to-install, lightweight webserver with a JSP container for Unix. More specifically, jtty-builder is just a set of shell scripts for Unix which automate downloading and building a lightweight Java web and application server for serving JSP (and Java servlets). The container used is &lt;a href="https://github.com/stephenh/jtty"&gt;Jtty&lt;/a&gt;, which uses &lt;a href="http://jetty.codehaus.org/jetty/"&gt;Jetty&lt;/a&gt;, which uses parts of &lt;a href="http://tomcat.apache.org/"&gt;Apache Tomcat&lt;/a&gt; (mostly &lt;a href="http://tomcat.apache.org/tomcat-6.0-doc/jasper-howto.html"&gt;Jasper&lt;/a&gt;). Most steps are automated. There is no need to write configuration files.&lt;p&gt;See the most recent documentation of jtty-builder &lt;a href="http://pts-mini-gpl.googlecode.com/svn/trunk/jtty-builder/README.txt"&gt;here&lt;/a&gt;.&lt;p&gt;To start serving a hello-world JSP page on Unix, do this:&lt;ol start=0&gt;&lt;li&gt;   As a shortcut, you can use a prebuilt jttyp.jar instead of building one   using jtty-builder. To do that, run the following command, and skip   steps 1 to 5 (inclusive):&lt;pre&gt;$ wget -O jttyp.jar \&lt;br /&gt;    http://pts-mini-gpl.googlecode.com/svn/trunk/jtty-prebuilt/jttyp.jar&lt;/pre&gt;&lt;li&gt;Download jtty-builder:&lt;pre&gt;$ svn co http://pts-mini-gpl.googlecode.com/svn/trunk/jtty-builder&lt;/pre&gt;&lt;li&gt;Install java and javac. Example command on Ubuntu Lucid:&lt;pre&gt;$ sudo apt-get install openjdk-6-jdk&lt;/pre&gt;&lt;li&gt;Use jtty-builder to download the sources of Jtty, Jetty and Tomcat:&lt;pre&gt;(cd jtty-builder &amp;&amp; ./download_jttyp.jar)&lt;/pre&gt;&lt;li&gt;Use jtty-builder to build jttyp.jar:&lt;pre&gt;$ (cd jtty-builder &amp;&amp; ./build_jttyp.jar)&lt;/pre&gt;&lt;li&gt;Copy jttyp.jar to the application directory:&lt;pre&gt;$ cp jtty-builder/jttyp.jar .&lt;/pre&gt;&lt;li&gt;Create your .war file or application directory. A simple example:&lt;pre&gt;$ mkdir Hello-World&lt;br /&gt;$ (echo '&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;JSP Test&amp;lt;/title&amp;gt;'&lt;br /&gt;   echo '&amp;lt;%! String message = "Hello, World."; %&amp;gt;'&lt;br /&gt;   echo '&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h2&amp;gt;&amp;lt;%= message %&amp;gt;&amp;lt;/h2&amp;gt;'&lt;br /&gt;   echo '&amp;lt;%= new java.util.Date() %&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;') &amp;gt;Hello-World/hi.jsp&lt;br /&gt;$ mkdir Hello-World/WEB-INF&lt;br /&gt;$ (echo '&amp;lt;web-app&amp;gt;'&lt;br /&gt;   echo '&amp;lt;display-name&amp;gt;Hello World&amp;lt;/display-name&amp;gt;'&lt;br /&gt;   echo '&amp;lt;/web-app&amp;gt;') &amp;gt;Hello-World/WEB-INF/web.xml&lt;/pre&gt;&lt;li&gt;Start the Java application server running your Hello-World application:&lt;pre&gt;java -jar jttyp.jar 8765 Hello-World&lt;/pre&gt;&lt;p&gt;(Keep the java application running.)&lt;li&gt;Try the web page in your web browser by visiting http://127.0.0.1:8765/   Reload it to get the time updated.&lt;p&gt;If you modify hi.jsp and reload the page, it gets autmatically recompiled   and the new version will run.&lt;/ol&gt;See &lt;a href="https://github.com/stephenh/jtty"&gt;the Jtty project page&lt;/a&gt; for more information about using &lt;i&gt;jtty.jar&lt;/i&gt; and &lt;i&gt;jttyp.jar&lt;/i&gt; for staring Java web applications from the command line.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-4093695559660152550?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/4093695559660152550/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=4093695559660152550' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/4093695559660152550'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/4093695559660152550'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/05/jtty-builder-easy-to-install-jsp-web.html' title='jtty-builder: easy-to-install JSP web server for Unix'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-7096742313461266057</id><published>2011-04-27T15:29:00.001+02:00</published><updated>2011-04-27T15:30:32.237+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='beginner'/><title type='text'>How to write a simple echo and chat server in Ruby 1.8</title><content type='html'>&lt;p&gt;This blog post is an introduction to TCP socket server programming and thread programming in Ruby 1.8. It also illustrates how compact and expressive Ruby code can be. The intended audience is Ruby beginners.&lt;pre class="syntax"&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;socket&amp;#39;&lt;/span&gt;  &lt;span class="c1"&gt;# TCPServer&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;ss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;TCPServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1233&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="kp"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class="no"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;begin&lt;/span&gt;&lt;br /&gt;      &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gets&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# Returns nil on EOF.&lt;/span&gt;&lt;br /&gt;        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;You wrote: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt;&lt;br /&gt;      &lt;span class="k"&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;rescue&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;bt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vg"&gt;$!&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backtrace&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  &amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;$stderr&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;error: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vg"&gt;$!&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;bt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;ensure&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;Use &lt;code&gt;telnet 127.0.0.1 1233&lt;/code&gt; to connect to the echo server as a new participant, and then type your chat message(s) terminated by &lt;i&gt;Enter&lt;/i&gt; (newline). The echo server sends back each message it receives with the &lt;i&gt;You wrote&lt;/i&gt; boilerplate around it. Multiple independent clients can connect to the chat server at a time.&lt;p&gt;The chat server:&lt;pre class="syntax"&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;socket&amp;#39;&lt;/span&gt;  &lt;span class="c1"&gt;# TCPServer&lt;/span&gt;&lt;br /&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;thread&amp;#39;&lt;/span&gt;  &lt;span class="c1"&gt;# Queue&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;ssock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;TCPServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1234&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;msgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;participants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;&lt;br /&gt;&lt;span class="no"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="c1"&gt;# Send chat messages to participants.&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# Always true.&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;participants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;br /&gt;      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt; &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;IOError&lt;/span&gt;&lt;br /&gt;    &lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="kp"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class="no"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ssock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;participants&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;begin&lt;/span&gt;&lt;br /&gt;      &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gets&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# Returns nil on EOF.&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;msgs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chomp!&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class="k"&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;rescue&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;bt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vg"&gt;$!&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backtrace&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  &amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;$stderr&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;error: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vg"&gt;$!&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;bt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;ensure&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;participants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;Use &lt;code&gt;telnet 127.0.0.1 1234&lt;/code&gt; to connect to the chat server as a new participant, and then type your chat message(s) terminated by &lt;i&gt;Enter&lt;/i&gt; (newline). The chat server sends each message (with a colon prepended) to all connected participants.&lt;p&gt;The Ruby source files above demonstrate the following:&lt;ul&gt;&lt;li&gt;how to create a thread&lt;li&gt;how to use thread-local variables (e.g. sock)&lt;li&gt;how to report exceptions in a thread&lt;li&gt;how to ignore IOError&lt;li&gt;how to read a line from a socket&lt;li&gt;how to use the Queue class for synchronization between threads&lt;li&gt;how to clean up using an &lt;i&gt;ensure&lt;/i&gt; block&lt;li&gt;how to pass values to a newly created thread&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-7096742313461266057?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/7096742313461266057/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=7096742313461266057' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7096742313461266057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7096742313461266057'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/04/how-to-write-simple-echo-and-chat.html' title='How to write a simple echo and chat server in Ruby 1.8'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-629817682297036633</id><published>2011-04-09T17:53:00.000+02:00</published><updated>2011-04-09T17:53:37.865+02:00</updated><title type='text'>python-xattr-compat: portable Python module to query and set POSIX extended attributes of files</title><content type='html'>&lt;p&gt;This blog post is an announcement of &lt;i&gt;python-xattr-compat&lt;/i&gt;, a portable Python 2.x module to query and set POSIX extended attributes of files.&lt;p&gt;&lt;i&gt;python-xattr-compat&lt;/i&gt; is a wrapper around the &lt;a href="http://pypi.python.org/pypi/xattr/"&gt;xattr&lt;/a&gt; Python package, but if&lt;i&gt;xattr&lt;/i&gt; is not available, &lt;i&gt;python-xattr-compat&lt;/i&gt; provides compatible replacement implementations (using the &lt;i&gt;dl&lt;/i&gt; or &lt;i&gt;ctypes&lt;/i&gt; modules)for some systems (currently Linux), so we have a pure Python implementationfor extended attribute manipulations.&lt;p&gt;How it works: Many scripting languages have a &lt;i&gt;syscall&lt;/i&gt; function to call arbitrary system calls (like &lt;i&gt;lsetxattr(2)&lt;/i&gt;). Python doesn't have &lt;i&gt;syscall&lt;/i&gt; built in, but it has the &lt;i&gt;dl&lt;/i&gt; and &lt;i&gt;ctypes&lt;/i&gt; modules, which let the programmer call functions in any C library, lincluding &lt;i&gt;libc&lt;/i&gt;. Since &lt;i&gt;libc&lt;/i&gt; on Linux has wrappers for &lt;i&gt;syscall&lt;/i&gt; and &lt;i&gt;lsetxattr&lt;/i&gt; etc., we can call these to get system-specific extended attribute manipulation without installing non-built-in Python extensions like &lt;i&gt;xattr&lt;/i&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-629817682297036633?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/629817682297036633/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=629817682297036633' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/629817682297036633'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/629817682297036633'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/04/python-xattr-compat-portable-python.html' title='python-xattr-compat: portable Python module to query and set POSIX extended attributes of files'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-904224384462281078</id><published>2011-04-03T22:53:00.009+02:00</published><updated>2011-06-01T16:58:22.622+02:00</updated><title type='text'>How to install CyanogenMod onto the ZTE Blade</title><content type='html'>&lt;p&gt;This blog post explains how I managed to install &lt;a href="http://www.cyanogenmod.com/"&gt;CyanogenMod&lt;/a&gt; to a &lt;a href="http://www.gsmarena.com/zte_blade-3391.php"&gt;ZTE Blade phone&lt;/a&gt; (both Gen 1 and Gen 2). Please note that there can be multiple solutions, some of them working only on some phone submodels. The solution I give here did work on the model I had.&lt;p&gt;Pick one of the methods below.&lt;h3&gt;Method one: without rooting the phone (recommended)&lt;/h3&gt;&lt;p&gt;This method is recommended, because it is the more straightforward and safer method. Although its description is longer than of method two, doing method one is faster.&lt;p&gt;You will need a USB cable to connect the phone to a computer and an SD card in the phone.&lt;p&gt;Instructions:&lt;ol&gt;&lt;li&gt;Make a backup of your data on the phone, &lt;a href="http://wiki.cyanogenmod.com/index.php?title=ZTE_Blade:_Full_Update_Guide"&gt;this page&lt;/a&gt; has some suggestions how (don't use Titanium Backup though, because that needs a rooted phone). You may safely skip this step if you don't have any SMS, phone call log entry, application data, application configuration etc. to save (e.g. because the phone is new and you haven't customized it yet).&lt;li&gt;Make sure you know your wifi connection credentials (e.g. network name, security type, passphrase).&lt;li&gt;Make sure you know your Google account name (e-mail address) and password.&lt;li&gt;On the phone: Settings » Applications » Development » enable USB Debugging.&lt;li&gt;On the phone: Settings » Applications » enable Unknown sources – Allow installation of non-Market applications&lt;li&gt;Install the &lt;i&gt;Ask Mr Pigfish&lt;/i&gt; application from the &lt;i&gt;Market&lt;/i&gt;, run &lt;i&gt;Ask Mr Pigfish&lt;/i&gt;, and see it displaying the generation number of your phone (gen1 or gen2). Take a not on paper containing the generation number.&lt;li&gt;Install the &lt;i&gt;adb&lt;/i&gt; and the &lt;i&gt;fastboot&lt;/i&gt; tools to your computer. For Linux, see &lt;i&gt;How to install&lt;/i&gt; instructions below. For Windows or Mac, see &lt;a href="http://wiki.cyanogenmod.com/index.php?title=ADB"&gt;this page&lt;/a&gt;. Another download for fastboot is on &lt;a href="http://developer.htc.com/google-io-device.html"&gt;this page&lt;/a&gt;.&lt;li&gt;The command lines in following instructions are for Linux. Do it similarly on Mac and Windows (e.g. instead of &lt;i&gt;wget&lt;/i&gt;, use your browser or download manager to download the file).&lt;li&gt;Download the ClockworkMod recovery with &lt;code&gt;wget -O /tmp/recovery-clockwork-3.0.1.4-blade.img http://android.d3xt3r01.tk/cyanogen/blade/recovery/recovery-clockwork-3.0.1.4-blade.img&lt;/code&gt;&lt;li&gt;Download the latest version of CyanogenMod from &lt;a href="http://wiki.cyanogenmod.com/index.php?title=Latest_Version#ZTE_Blade"&gt;this page&lt;/a&gt;. When these instructions were written, the equivalent download command was: &lt;code&gt;wget -O /tmp/update-cm-7.0.0-RC4-Blade-signed.zip http://mirror.cyanogenmod.com/get/update-cm-7.0.0-RC4-Blade-signed.zip&lt;/code&gt;&lt;li&gt;Download the latest version of Google Apps from &lt;a href="http://wiki.cyanogenmod.com/index.php?title=Latest_Version#Google_Apps"&gt;this page&lt;/a&gt;. When these instructions were written, the equivalent download command was: &lt;code&gt;wget -O /tmp/gapps-gb-20110307-signed.zip http://android.d3xt3r01.tk/cyanogen/gapps/gapps-gb-20110307-signed.zip&lt;/code&gt;&lt;li&gt;If already connected, disconnect the phone from the computer.&lt;li&gt;Remove the SIM card from the phone if you don't have a data plan. This is to prevent the unconfigured CyanogenMod from making expensive data transfers before the wifi is configured. This needs powering off your phone first.&lt;li&gt;Power the phone back on and wait for it to start up.&lt;li&gt;Connect the phone to the computer using the USB cable. The phone should display a notification that an USB cable is connected (and possibly another notification that USB debugging is enabled).&lt;li&gt;Run &lt;code&gt;adb devices&lt;/code&gt; on the computer, it should display something like&lt;pre&gt;List of devices attached &lt;br /&gt;Blade-CM7       device&lt;/pre&gt;&lt;li&gt;Copy the CyanogenMod ZIP file to the SD card by running &lt;code&gt;adb push /tmp/update-cm-7.0.0-RC4-Blade-signed.zip /sdcard/cm.zip&lt;/code&gt;&lt;li&gt;Copy the Google Apps ZIP file to the SD card by running &lt;code&gt;adb push /tmp/gapps-gb-20110307-signed.zip /sdcard/gapps.zip&lt;/code&gt;&lt;li&gt;To prevent data loss below, make sure the phone is fully charged. You can charge it quickly if you connect it to a wall socket instead of a computer.&lt;li&gt;If you have a gen1 phone and you want to install CyanogenMod 7.0.1 or later, then upgrade your phone to gen2 by following the &lt;i&gt;How to upgrade a gen1 phone to gen2 and start ClockworkMod recovery&lt;/i&gt; below. Otherwise, follow these instructions:&lt;ol&gt;&lt;li&gt;Reboot the phone to &lt;i&gt;fastboot&lt;/i&gt; mode by running &lt;code&gt;adb reboot bootloader&lt;/code&gt;&lt;li&gt;Wait for about 20 seconds until the phone reboots into bootloader mode, showing only the green android logo on the screen. (If your phone boots normally a few seconds later, then this method has failed for you, please choose another method to install CyanogenMod to your phone. You may try removing the battery, reinserting the battery, holding the &lt;i&gt;Volume Up&lt;/i&gt; key on the phone, and powering on the phone while &lt;i&gt;Volume Up&lt;/i&gt; is still held.)&lt;li&gt;Run &lt;code&gt;fastboot flash recovery /tmp/recovery-clockwork-3.0.1.4-blade.img&lt;/code&gt;&lt;li&gt;Run &lt;code&gt;fastboot reboot&lt;/code&gt;&lt;li&gt;Wait for the phone to start up and detect that the USB cable is connected.&lt;li&gt;Run &lt;code&gt;adb reboot recovery&lt;/code&gt; (this should take about 5 seconds).&lt;li&gt;Wait for about 5 seconds until the phone reboots into recovery mode, running the ClockworkMod recovery.&lt;/ol&gt;&lt;li&gt;Your phone should be running &lt;i&gt;ClockworkMod recovery&lt;/i&gt; now. It should display &lt;i&gt;ClockworkMod Recovery v3.0.1.4&lt;/i&gt; (or a larger version number) and a menu below, starting with &lt;i&gt;reboot system now&lt;/i&gt;. Use the &lt;i&gt;Volume Up&lt;/i&gt; and &lt;i&gt;Volume Down&lt;/i&gt; keys to navigate the menu up or down. Navigate to the &lt;i&gt;advanced&lt;/i&gt; item, use the &lt;i&gt;Home&lt;/i&gt; button to select it. Use the &lt;i&gt;Back&lt;/i&gt; button to go back to the main menu.&lt;li&gt;Select the main menu option &lt;i&gt;Wipe data/factory reset&lt;/i&gt;&lt;li&gt;Select the main menu option &lt;i&gt;Wipe cache partition&lt;/i&gt;&lt;li&gt;Select the main menu option &lt;i&gt;Install zip from sdcard&lt;/i&gt;&lt;li&gt;Select the menu option &lt;i&gt;Choose zip from sdcard&lt;/i&gt;&lt;li&gt;Select &lt;i&gt;cm.zip&lt;/i&gt; . This will install CyanogenMod.&lt;li&gt;Go back to the main menu. Select the main menu option &lt;i&gt;Install zip from sdcard&lt;/i&gt;&lt;li&gt;Select the menu option &lt;i&gt;Choose zip from sdcard&lt;/i&gt;&lt;li&gt;Select &lt;i&gt;gapps.zip&lt;/i&gt; . This will install Google Apps.&lt;li&gt;Go back to the main menu.&lt;li&gt;Select the main menu option &lt;i&gt;reboot system now&lt;/i&gt;&lt;li&gt;CyanogenMod should be booting now. Configure everything for your needs.&lt;li&gt;Use the &lt;i&gt;Menu&lt;/i&gt; button to configure the wifi first (i.e. below you enter your Google account password).&lt;li&gt;CyanogenMod might ask you which Google applications to install. If unsure, select all of them. After you make your selection, CyanogenMod will take you the Market page of all these applications. Accept and install them one by one.&lt;li&gt;If you don't have a data plan, make sure you configure the phone so it won't accidentally make data transfers.&lt;li&gt;Reinsert the SIM card. This needs powering off your phone first.&lt;/ol&gt;&lt;h4&gt;How to install &lt;i&gt;adb&lt;/i&gt; and &lt;i&gt;fastboot&lt;/i&gt; on Linux&lt;/h4&gt;&lt;pre&gt;&lt;br /&gt;# You might need to use anoter package manager for installation:&lt;br /&gt;$ sudo apt-get install wget unzip&lt;br /&gt;$ wget -O /tmp/linux_adb_fastboot.zip \&lt;br /&gt;  http://android.d3xt3r01.tk/cyanogen/tools/linux_adb_fastboot.zip&lt;br /&gt;$ (cd /usr/local/bin &amp;&amp; sudo unzip /tmp/linux_adb_fastboot.zip)&lt;br /&gt;$ sudo killall -9 adb&lt;br /&gt;# This starts the daemon. `sudo' is not necessary on some systems.&lt;br /&gt;$ sudo /usr/local/bin/adb devices&lt;/pre&gt;&lt;h4&gt;How to upgrade a gen1 phone to gen2 and start ClockworkMod recovery&lt;/h4&gt;&lt;p&gt;Don't follow these steps unless you are asked to by another step in this howto.&lt;p&gt;Please note that these instructions apply only to gen1 (1st generation) &lt;i&gt;ZTE Blade&lt;/i&gt; models. Doing it on any other phone (i.e. on a gen2 &lt;i&gt;ZTE Blade&lt;/i&gt; or any phone other than a &lt;i&gt;ZTE Blade&lt;/i&gt;) will most probably make the device useless beyond repair. You can use the &lt;i&gt;Ask Mr Pigfish&lt;/i&gt; application (available from the Android Market) to check if you have a gen1 &lt;i&gt;ZTE Blade&lt;/i&gt;.&lt;p&gt;Please note that by following these instructions, not only the configuration and user data, but the operating system will also be removed from the phone. (But the contents of the SD card will remain intact.) To make your (gen2) device useful after these instructions, you should already have an operating system installer ZIP file (e.g. &lt;i&gt;cm.zip&lt;/i&gt; above) already on the SD card.&lt;p&gt;Instructions:&lt;ol&gt;&lt;li&gt;Download the ZIP file &lt;i&gt;Gen1-to-Gen2-TPT-v2.zip&lt;/i&gt; from &lt;a href="http://www.mediafire.com/?w6y938c2wxncywa#1"&gt;here&lt;/a&gt;. The download link can also be found in the section &lt;i&gt;Update to Gen2 Radio&lt;/i&gt; of &lt;a href="http://wiki.cyanogenmod.com/index.php?title=ZTE_Blade:_Full_Update_Guide"&gt;this page&lt;/a&gt;.&lt;li&gt;Unzip the contents of the ZIP file to the SD card, so there should be a folder named &lt;i&gt;image&lt;/i&gt; in the root folder of the SD card, and that folder should contain 17 files, from &lt;i&gt;amss.mbn&lt;/i&gt; to &lt;i&gt;userdata.img&lt;/i&gt; . Make sure that the &lt;i&gt;image&lt;/i&gt; folder is in the root folder of the SD card. The easiest way to do this is connecting your phone to the computer using the USB cable, mounting the SD card (using the notification area of the phone), and running a ZIP file extractor on the computer. Disconnect the drive from the computer, and umount the SD card when done.&lt;li&gt;Make sure the phone is fully charged.&lt;li&gt;Disconnect the phone from the computer and the charger.&lt;li&gt;Turn off the phone (by long pressing the &lt;i&gt;power&lt;/i&gt; button).&lt;li&gt;Remove the battery.&lt;li&gt;Reinsert the battery.&lt;li&gt;Hold the &lt;i&gt;volume up&lt;/i&gt; and &lt;i&gt;menu&lt;/i&gt; buttons. Don't release them yet.&lt;li&gt;(Before doing this, read the next instruction step.) Push the &lt;i&gt;power&lt;/i&gt; button to turn the phone on.&lt;li&gt;Text in green would start appearing on a black background. Release the &lt;i&gt;volume up&lt;/i&gt; and &lt;i&gt;menu&lt;/i&gt; buttons.&lt;li&gt;More text in green would start appearing with some indication of progress percentage. Wait for 30 seconds until its done.&lt;li&gt;The phone boots to &lt;i&gt;ClockworkMod Recovery&lt;/i&gt; .&lt;/ol&gt;&lt;h3&gt;Method two: rooting the phone first&lt;/h3&gt;&lt;p&gt;You will need an SD card in the phone.&lt;p&gt;Outline (see the detailed instructions in the links below):&lt;ol&gt;&lt;li&gt;Make a backup of your data on the phone. (See in method two below.)&lt;li&gt;Make sure you know your wifi connection credentials (e.g. network name, security type, passphrase).&lt;li&gt;Make sure you know your Google account name (e-mail address) and password.&lt;li&gt;Root the phone.&lt;li&gt;Install the &lt;i&gt;ROM Manager&lt;/i&gt; application (from the Android Market).&lt;li&gt;Install &lt;i&gt;ClockworkMod recovery&lt;/i&gt; using the &lt;i&gt;ROM Manager&lt;/i&gt; application. (This step needs a rooted phone.)&lt;li&gt;Download the &lt;i&gt;CyanogenMod update&lt;/i&gt; ZIP file (and possibly the &lt;i&gt;Google Apps&lt;/i&gt; ZIP file) to the &lt;code&gt;/sdcard&lt;/code&gt;.&lt;li&gt;To prevent data loss below, make sure the phone is fully charged. You can charge it quickly if you connect it to a wall socket instead of a computer.&lt;li&gt;Remove the SIM card from the phone if you don't have a data plan. This is to prevent the unconfigured CyanogenMod from making expensive data transfers before the wifi is configured. This needs powering off your phone first.&lt;li&gt;Use the &lt;i&gt;ROM Manager&lt;/i&gt; application to start the &lt;i&gt;ClockworkMod&lt;/i&gt; recovery.&lt;li&gt;Within &lt;i&gt;ClockworkMod&lt;/i&gt; recovery, wipe the phone.&lt;li&gt;Within &lt;i&gt;ClockworkMod&lt;/i&gt; recovery, install the &lt;i&gt;CyanogenMod update&lt;/i&gt; ZIP file (and possibly the &lt;i&gt;Google Apps&lt;/i&gt; ZIP file)&lt;li&gt;Within &lt;i&gt;ClockworkMod&lt;/i&gt; recovery, reboot the phone. &lt;li&gt;CyanogenMod should be booting now. Configure everything for your needs.&lt;li&gt;If you don't have a data plan, make sure you configure the phone so it won't accidentally make data transfers.&lt;li&gt;Reinsert the SIM card. This needs powering off your phone first.&lt;/ol&gt;&lt;p&gt;All these steps worked for me as explained in detail on &lt;a href="http://wiki.cyanogenmod.com/index.php?title=ZTE_Blade:_Full_Update_Guide"&gt;the official install CyagnogenMod to ZTE Blade page&lt;/a&gt;, except for rooting the phone. That page and also most other web sites instruct the user to reboot the &lt;i&gt;fastboot&lt;/i&gt; mode by holding the Volume Up key while powering up the phone. This didn't work for me, because my ZTE Blade had &lt;i&gt;fastboot&lt;/i&gt; disabled (so it always booted normally). So I had to find another way to root the phone. The instructions on &lt;a href="http://orangesanfrancisco.co.uk/android/how-to-root-the-orange-san-francisco-zte-blade/"&gt;this page&lt;/a&gt; (those containing &lt;i&gt;tinyurl.com/urooted&lt;/i&gt;) worked for me. These instructions use a version of the &lt;i&gt;Universal Androot&lt;/i&gt; application specialized to the ZTE Blade. Please note that Universal Androot claims that the phone is already rooted &amp;mdash; just ignore this message and root it anyway. Please also note that during the installation process you have to re-root the phone using &lt;i&gt;Universal Androot&lt;/i&gt; each time you reboot the phone. So if &lt;i&gt;ROM Manager&lt;/i&gt; complains that your phone is not rooted, then just run &lt;i&gt;Universal Androot&lt;/i&gt; again, and then retry in &lt;i&gt;ROM Manager&lt;/i&gt;.&lt;h3&gt;Performance&lt;/h3&gt;&lt;p&gt;If the phone feels slow and games are not enjoyable, then tune the performance settings:&lt;ol&gt;&lt;li&gt;Make sure that the latest version of CyanogenMod (at least 7.0.0 without RC in the version number) is installed. Get the newest version of the ZIP file from &lt;a href="http://wiki.cyanogenmod.com/index.php?title=Latest_Version#ZTE_Blade"&gt;here&lt;/a&gt;. Copy the ZIP file to the (root of the) SD card. Reboot the phone to recovery mode (using &lt;code&gt;adb reboot recovery&lt;/code&gt; or the &lt;i&gt;ROM Manager&lt;/i&gt; application). In recovery mode, clear the cache and then select the update file (the ZIP file), install it, and reboot the phone.&lt;li&gt;Make sure that &lt;i&gt;Application / Settings / CyanogenMOD Settings / Performance / Enable surface dithering&lt;/i&gt; is off.&lt;li&gt;In &lt;i&gt;Application / Spare Parts&lt;/i&gt; make sure that all animations are disabled.&lt;li&gt;There seems to be no need for enabling GPU acceleration (&lt;code&gt;debug.sf.hw=1&lt;/code&gt; in &lt;code&gt;/system/build.prop&lt;/code&gt;), CyanogenMod seems to be fast without it.&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-904224384462281078?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/904224384462281078/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=904224384462281078' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/904224384462281078'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/904224384462281078'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/04/how-to-install-cyanogenmod-to-zte-blade.html' title='How to install CyanogenMod onto the ZTE Blade'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-3524357053115976938</id><published>2011-03-25T18:32:00.001+01:00</published><updated>2011-03-25T18:33:37.673+01:00</updated><title type='text'>How to automatically synchronize the shell history between terminal windows</title><content type='html'>&lt;p&gt;This blog post explains how to automatically synchronize the Unix shell command-line history between multiple shell instances running on the same computer (but possibly different terminal windows), without requiring any manual action (such as running &lt;code&gt;history -w&lt;/code&gt; or exiting from the shell) from the user, and also how to make commands be saved to the history file right at the point when the command is executed. The solutions described here work with bash 4.1 (tested with 4.1.5) or newer and zsh (tested with 4.3.4 and 4.3.10), run on Ubuntu Lucid. No attempt was made to synchronize the zsh history and the bash history.&lt;h3&gt;Instructions for zsh&lt;/h3&gt;&lt;p&gt;Put (append) this command to your &lt;code&gt;~/.zshrc&lt;/code&gt; and reopen your terminal windows so that the changes take effect:&lt;pre&gt;setopt hist_ignore_dups share_history inc_append_history extended_history&lt;/pre&gt;&lt;p&gt;The change takes effect in terminal windows and incoming SSH connections you open from now on. Close your old windows if necessary to avoid confusion. You can also run the &lt;code&gt;source ~/.zshrc&lt;/code&gt; to make the change take effect.&lt;p&gt;Optionally, set your &lt;code&gt;HISTSIZE&lt;/code&gt; and &lt;code&gt;SAVEHIST&lt;/code&gt; to large enough values, e.g. put &lt;code&gt;HISTSIZE=500000 SAVEHIST=5000000&lt;/code&gt; in your &lt;code&gt;~/.zshrc&lt;/code&gt;.&lt;p&gt;Once the change took effect, you can start running a command in one terminal window, then just press &lt;i&gt;Enter&lt;/i&gt; in another terminal window, then press &lt;i&gt;Up&lt;/i&gt; in the other terminal window to get the command running in the other terminal window. Your shell history lines are now synchronized. Synchronization happens whenever you press &lt;i&gt;Enter&lt;/i&gt; in a terminal window.&lt;h3&gt;Instructions for bash&lt;/h3&gt;&lt;p&gt;Since bash doesn't have the history sharing feature by default, you need to use a helper script for bash. Download it using the following command (without the first &lt;code&gt;$&lt;/code&gt;):&lt;pre&gt;$ wget -O ~/merge_history.bash http://www.math.bme.hu/~pts/cvsget.cgi/u=zsh/p=/M=zsh/c=f1/n=/zsh/merge_history.bash&lt;/pre&gt;&lt;p&gt;Run&lt;pre&gt;$ touch ~/.merged_bash_history&lt;/pre&gt;&lt;p&gt;to signify to the helper script that you want to use the new history feature.&lt;p&gt;Put (append) this to your &lt;code&gt;~/.bashrc&lt;/code&gt; so the helper script gets loaded at shell startup:&lt;pre&gt;source "$HOME"/merge_history.bash&lt;/pre&gt;&lt;p&gt;Optionally, set &lt;code&gt;HISTSIZE&lt;/code&gt; and &lt;code&gt;HISTFILESIZE&lt;/code&gt; to large enough values, e.g. append the following to your &lt;code&gt;~/.bashrc&lt;/code&gt;:&lt;pre&gt;HISTSIZE=500000 HISTFILESIZE=5000000&lt;/pre&gt;&lt;p&gt;The change takes effect in terminal windows and incoming SSH connections you open from now on. Close your old windows if necessary to avoid confusion. You can also run the &lt;code&gt;source&lt;/code&gt; command above to make the change take effect.&lt;p&gt;Once the change took effect, you can start running a command in one terminal window, then just press &lt;i&gt;Enter&lt;/i&gt; in another terminal window, then press &lt;i&gt;Up&lt;/i&gt; in the other terminal window to get the command running in the other terminal window. Your shell history lines are now synchronized. Synchronization happens whenever you press &lt;i&gt;Enter&lt;/i&gt; in a terminal window.&lt;p&gt;If you want your old shell history to be reused, please copy it any time, and then press &lt;i&gt;Enter&lt;/i&gt;:&lt;pre&gt;cp ~/.bash_history ~/.merged_bash_history&lt;/pre&gt;&lt;h3&gt;Explanation of the bash solution&lt;/h3&gt;&lt;p&gt;Bash doesn't have support for manual or automatic synchronization of history files. By default, bash reads the history file &lt;code&gt;~/.bash_history&lt;/code&gt; (can be changed by setting the &lt;code&gt;HISTFILE&lt;/code&gt; bash special variable) at startup, adds newly executed commands to its in-memory history buffer, and simply writes (or appends) the contents of the buffer to the history file upon clean exit. With this strategy, commands can be lost for good if the shell is killed with &lt;code&gt;kill -9&lt;/code&gt;, or multiple shells are exiting (the last one wins, lines from all previous ones get irrecoverably lost). It's possible to affect this behavior with &lt;code&gt;shopt -s histappend&lt;/code&gt; to force appending instead of overwriting, but that's still much less synchronization with command sorting by timestamp. The commands &lt;code&gt;history -w&lt;/code&gt;, &lt;code&gt;history -a&lt;/code&gt; &lt;code&gt;history -c&lt;/code&gt; and &lt;code&gt;history -r&lt;/code&gt; can be useful for managing the bash history files, but they may still cause data loss (see above).&lt;p&gt;To solve these problems, the helper script &lt;code&gt;merge_history.bash&lt;/code&gt; above uses the following techniques:&lt;ul&gt;&lt;li&gt;It uses &lt;code&gt;HISTTIMEFORMAT&lt;/code&gt; bash special variable to make sure timestamps are saved into the history file.&lt;li&gt;It contains a Perl script to merge history files (possibly created by concurrently running bash instances), sorting the results by timestamp and removing duplicates.&lt;li&gt;Before displaying the prompt (using the &lt;code&gt;PROMPT_COMMAND&lt;/code&gt; bash special variable) loads the merged history file from disk.&lt;li&gt;When the user presses &lt;i&gt;Enter&lt;/i&gt; to run a command, before the command is executed, it saves the in-memory history buffer to a file, and merges that file using the Perl script to the merged history file. It uses &lt;code&gt;trap ... DEBUG&lt;/code&gt; (and various black magic trickery) to install its hook before the command is executed. &lt;a href="http://stackoverflow.com/questions/103944/real-time-history-export-amongst-bash-terminal-windows"&gt;Other solutions&lt;/a&gt; for bash history synchronization don't use this technique, so they suffer from the shortcoming of saving the most recently executed command too late (only when it finishes).&lt;/ul&gt;&lt;code&gt;merge_history.bash&lt;/code&gt; was inspired by the &lt;a href="http://hints.macworld.com/dlfiles/preexec.bash.txt"&gt;bash preexec emulation script&lt;/a&gt;.&lt;p&gt;Get the most recent version of &lt;code&gt;merge_history.bash&lt;/code&gt; from &lt;a href="http://www.math.bme.hu/~pts/cvsget.cgi/u=zsh/p=/M=zsh/c=f1/n=/zsh/merge_history.bash"&gt;http://www.math.bme.hu/~pts/cvsget.cgi/u=zsh/p=/M=zsh/c=f1/n=/zsh/merge_history.bash&lt;/a&gt; . For your studying convenience, here is a (possibly outdated) copy:&lt;pre&gt;MRG_DONEI=":$SHELLOPTS:"&lt;br /&gt;if test "${MRG_DONEI#*:history:}" != "$PTS_DONEI" &amp;amp;&amp;amp;&lt;br /&gt;   (test "${BASH_VERSION#[5-9].}" != "$BASH_VERSION" ||&lt;br /&gt;    test "${BASH_VERSION#4.[1-9].}" != "$BASH_VERSION") &amp;amp;&amp;amp;&lt;br /&gt;   test "$HOME" &amp;amp;&amp;amp;&lt;br /&gt;   test -f "$HOME/.merged_bash_history"; then&lt;br /&gt;&lt;br /&gt;# Merge the timestamped .bash_history files specified in $@ , remove&lt;br /&gt;# duplicates, print the results to stdout.&lt;br /&gt;function _mrg_merge_ts_history() {&lt;br /&gt;  PERL_BADLANG=x perl -wne '&lt;br /&gt;    use integer;&lt;br /&gt;    use strict;&lt;br /&gt;    use vars qw($prefix @lines);&lt;br /&gt;    if (/^#(\d+)\n/) {&lt;br /&gt;      $prefix = sprintf("%030d ", $1);&lt;br /&gt;    } else {&lt;br /&gt;      chomp; $prefix = sprintf("%030d ", time) if !defined $prefix;&lt;br /&gt;      push @lines, "$prefix$_\n"; undef $prefix;&lt;br /&gt;    }&lt;br /&gt;    END {&lt;br /&gt;      my $prev = "";&lt;br /&gt;      for (sort @lines) {&lt;br /&gt;        s@^(\d+) @@; my $ts = $1 + 0; my $cur = "#$ts\n$_";&lt;br /&gt;        print $cur if $cur ne $prev;&lt;br /&gt;        $prev = $cur;&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  ' -- "$@"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# Read history from $HISTFILE_MRG, &lt;br /&gt;function _rdh() {&lt;br /&gt;  test "$HISTFILE_MRG" || return&lt;br /&gt;  local HISTFILE="$HISTFILE_MRG"&lt;br /&gt;  # Make `history -w' prefix "$TIMESTAMP\n" to $HISTFILE&lt;br /&gt;  local HISTTIMEFORMAT=' '&lt;br /&gt;  history -c  # Clear the in-memory history.&lt;br /&gt;  history -r  # Append the contents of $HISTFILE to the in-memory history.&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;export -n HISTTIMEFORMAT HISTFILE HISTFILE_MRG&lt;br /&gt;unset HISTFILE  # No history file by default, equivalent to HISTFILE="".&lt;br /&gt;unset HISTTIMEFORMAT&lt;br /&gt;HISTFILE_MRG="$HOME/.merged_bash_history"&lt;br /&gt;history -c  # Discard the current history, whatever it was.&lt;br /&gt;&lt;br /&gt;function hook_at_debug() {&lt;br /&gt;  test "$COMP_LINE" &amp;amp;&amp;amp; return  # Within the completer.&lt;br /&gt;  trap '' DEBUG  # Uninstall debug trap.&lt;br /&gt;  test "$HISTFILE_MRG" || return&lt;br /&gt;  if : &amp;gt;&amp;gt;"$HISTFILE_MRG"; then&lt;br /&gt;    # Make `history -w' prefix "$TIMESTAMP\n" to $HISTFILE&lt;br /&gt;    local HISTTIMEFORMAT=' '&lt;br /&gt;    # TODO(pts): Don't save if nothing changed (i.e. `history -1` prints&lt;br /&gt;    # the same sequence number as before).&lt;br /&gt;    local TMPDIR="${TMPDIR:-/tmp}"&lt;br /&gt;    local HISTFILE="$TMPDIR/whistory.$UID.$$"&lt;br /&gt;    local MHISTFILE="$TMPDIR/mhistory.$UID.$$"&lt;br /&gt;    history -w  # Write to /tmp/whistory.$$ .&lt;br /&gt;    _mrg_merge_ts_history "$HISTFILE_MRG" "$HISTFILE" &amp;gt;"$MHISTFILE"&lt;br /&gt;    command mv -f -- "$MHISTFILE" "$HISTFILE_MRG"&lt;br /&gt;  fi&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# Set these both so hook_at_debug gets called in a subshell.&lt;br /&gt;set -o functrace &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;shopt -s extdebug &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;&lt;br /&gt;# As a side effect, we install our own debug hook. We wouldn't have to do&lt;br /&gt;# that if bash had support for `preexec' (executed just after a command has&lt;br /&gt;# been read and is about to be executed). in zsh.&lt;br /&gt;PROMPT_COMMAND="trap '' DEBUG; _rdh; trap hook_at_debug DEBUG; $PROMPT_COMMAND"&lt;br /&gt;&lt;br /&gt;fi  # End of the file's if guard.&lt;br /&gt;unset MRG_DONEI&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-3524357053115976938?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/3524357053115976938/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=3524357053115976938' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/3524357053115976938'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/3524357053115976938'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/03/how-to-automatically-synchronize-shell.html' title='How to automatically synchronize the shell history between terminal windows'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-7947825481306580572</id><published>2011-02-16T17:57:00.004+01:00</published><updated>2011-02-21T00:02:01.148+01:00</updated><title type='text'>How to dump the full /etc/passwd and /etc/group files when NIS (YP) or LDAP is used</title><content type='html'>&lt;p&gt;This blog post explains how to dump the flattened version of &lt;code&gt;/etc/passwd&lt;/code&gt; and &lt;code&gt;/etc/group&lt;/code&gt; files on a Unix system when some user and group entries are stored in a NIS (YP), LDAP or other server.&lt;p&gt;To dump these fules, run the following commands (not as root, without the leading &lt;code&gt;$&lt;/code&gt;).&lt;pre&gt;$ getent group  &gt;/tmp/group&lt;br /&gt;$ getent passwd &gt;/tmp/passwd&lt;/pre&gt;&lt;p&gt;The equivalent commands in Perl (use them if &lt;i&gt;getent(1)&lt;/i&gt; doesn't work for you):&lt;pre&gt;$ perl -le'$,=":";while(@_=getgrent){$_[3]=~y@ @,@;print@_}'  &gt;/tmp/group&lt;br /&gt;$ perl -le'$,=":";while(@_=getpwent){print@_[0,1,2,3,6,7,8]}' &gt;/tmp/passwd&lt;/pre&gt;&lt;p&gt;For NIS (YP) users and groups only, one can use &lt;code&gt;ypcat passwd&lt;/code&gt; and &lt;code&gt;ypcat group&lt;/code&gt;, respectively.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-7947825481306580572?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/7947825481306580572/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=7947825481306580572' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7947825481306580572'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7947825481306580572'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/02/how-to-dump-full-etcpasswd-and-etcgroup.html' title='How to dump the full /etc/passwd and /etc/group files when NIS (YP) or LDAP is used'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-8791165167251162649</id><published>2011-02-01T18:22:00.002+01:00</published><updated>2011-02-01T22:10:14.411+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='gevent'/><category scheme='http://www.blogger.com/atom/ns#' term='syncless'/><category scheme='http://www.blogger.com/atom/ns#' term='planet-python'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrence'/><title type='text'>How to run Syncless on Linux without installing it?</title><content type='html'>&lt;p&gt;This blog post explains how to run asynchronous, coroutine-based client and server I/O libraries like Syncless, gevent and Concurrence on Linux without installing them.&lt;p&gt;On Linux, it's possible to try Syncless without installation, using the&lt;a href="http://code.google.com/p/pts-mini-gpl/wiki/StaticPython"&gt;StaticPython&lt;/a&gt; binary Python distribution, like this:&lt;pre&gt;$ wget -O stacklessco2.7-static \&lt;br /&gt;  http://pts-mini-gpl.googlecode.com/svn/trunk/staticpython/release/stacklessco2.7-static&lt;br /&gt;$ chmod +x stacklessco2.7-static&lt;br /&gt;$ ./stacklessco2.7-static&lt;br /&gt;Python 2.7.1 Stackless 3.1b3 060516 (release27-maint, Feb  1 2011, 16:57:16)&lt;br /&gt;[GCC 4.1.2] on linux2&lt;br /&gt;Type "help", "copyright", "credits" or "license" for more information.&lt;br /&gt;&gt;&gt;&gt; from syncless import coio&lt;br /&gt;&gt;&gt;&gt; coio.sleep(1.5)&lt;br /&gt;(sleeping for 1.5 second)&lt;br /&gt;&amp;lt;object object at 0xf7709490&amp;gt;&lt;br /&gt;&gt;&gt;&gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Limitations:&lt;ul&gt;&lt;li&gt;This solution requires Linux on x86 (i386) or x86_64 (amd64) architecture. If you have a different Unix system, you have to install Syncless the regular way (e.g. with &lt;code&gt;sudo easy_install syncless&lt;/code&gt;).&lt;li&gt;This solution doesn't give you the newest version of Syncless.&lt;li&gt;You can't use Python extensions written in C, except for those compiled into &lt;i&gt;stacklessco2.7-static&lt;/i&gt;. See the full list on the &lt;a href="http://code.google.com/p/pts mini-gpl/wiki/StaticPython"&gt;StaticPython home page&lt;/a&gt;.&lt;/ul&gt;&lt;p&gt;Please note that StaticPython can run many other I/O frameworks and libraries, which don't require compiling C extensions. Such libraries include Eventlet, Tornado, Twisted, asyncore and circuits.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-8791165167251162649?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/8791165167251162649/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=8791165167251162649' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/8791165167251162649'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/8791165167251162649'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/02/how-to-run-syncless-on-linux-without.html' title='How to run Syncless on Linux without installing it?'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-5741708799814554942</id><published>2011-01-21T20:32:00.003+01:00</published><updated>2011-07-19T15:51:07.452+02:00</updated><title type='text'>How to implement the C printf function in C++ in a typesafe way?</title><content type='html'>&lt;p&gt;This blog post explains how to implement the C &lt;code&gt;printf()&lt;/code&gt; function in C++ in a typesafe and convenient way.&lt;p&gt;The most important advantage of the ANSI standard C &lt;code&gt;printf()&lt;/code&gt; function are its compactness and expressive power. For example: &lt;code class="syntax"&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;The %s answer is %05d.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;best&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/code&gt; means: take the next argument, treat it as a null-terminated string (&lt;code&gt;const char*&lt;/code&gt;), and insert it. The format specifier &lt;code&gt;%05d&lt;/code&gt; means: take the next argument as a signed integer, pad it with leading zeros to at least 5 digits, and insert it. Please note that &lt;code&gt;printf()&lt;/code&gt; is not typesafe: the format specifier has to match the type of the argument. For example, &lt;code&gt;%d&lt;/code&gt; wouldn't work for a &lt;code&gt;long long&lt;/code&gt; (but &lt;code&gt;%lld&lt;/code&gt; would be needed), and &lt;code&gt;%d&lt;/code&gt; or &lt;code&gt;%s&lt;/code&gt; wouldn't work for a &lt;code&gt;double&lt;/code&gt; (but &lt;code&gt;%g&lt;/code&gt; would be needed, and &lt;code&gt;%Lg&lt;/code&gt; would be needed for a &lt;code&gt;long double&lt;/code&gt;). On a mismatch, some compilers would indicate a compile error, others would generate misbehaving (i.e. with undefined behavior) code.&lt;p&gt;There is no equally expressive message formatting functionality in C++ with a similarly compact syntax. Of course, &lt;code&gt;printf()&lt;/code&gt; as it is can be used in C++, but it isn't integrated conveniently with the C++ standard library: e.g. it's not possible to insert an &lt;code&gt;std::string&lt;/code&gt;, it's not possible to write to an &lt;code&gt;std::ostream&lt;/code&gt;, and it's not possible to append to an existing &lt;code&gt;std::string&lt;/code&gt;. C++ streams (e.g. &lt;code&gt;cout &amp;lt;&amp;lt; "The " &amp;lt;&amp;lt; "best" &amp;lt;&amp;lt; " answer is " &amp;lt;&amp;lt; 42 &amp;lt;&amp;lt; ".\n";&lt;/code&gt;) bring type safety (e.g. no matter which integer, floating point or string type &lt;code&gt;42&lt;/code&gt; and other arguments have, they will be inserted properly), but they don't provide compact and powerful formatting capabilities (e.g. how to specify to pad &lt;code&gt;42&lt;/code&gt; with zeros to at lest 5 digits).&lt;p&gt;Would it be possible to combine the compactness and expressive power of &lt;code&gt;printf()&lt;/code&gt; with the typesafe behavior of C++ streams? It isn't too hard to create a class named &lt;code&gt;Print&lt;/code&gt; and implement an overloaded &lt;code&gt;operator&amp;lt;&amp;lt;&lt;/code&gt; so that &lt;code class="syntax"&gt;&lt;span class="n"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;The %s answer is %05d.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;best&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;/code&gt; would work in a typesafe way (raising a run-time error reliably if the type of the argument doesn't match the format specifier, and converting the the size and type of the argument if needed, e.g. &lt;code&gt;%d&lt;/code&gt; would work for both &lt;code&gt;int&lt;/code&gt; and &lt;code&gt;long long&lt;/code&gt;). But is it possible to do it while keeping the original syntax, like this: &lt;code class="syntax"&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;The %s answer is %05d.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;best&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/code&gt;?&lt;p&gt;Yes, that's possible, using two tricks: overloading &lt;code&gt;operator,&lt;/code&gt; (the comma operator), and using a GCC feature of macro expansion with any number of arguments. The macro &lt;code&gt;Printf&lt;/code&gt; would expand so that &lt;code&gt;Printf("The %s answer is %05d.\n", "best", 42);&lt;/code&gt; expands to &lt;code&gt;(C("The %s answer is %05d.\n"), "best", 42);&lt;/code&gt;, which is equivalent to &lt;code&gt;operator,(operator,(C("The %s answer is %05d.\n", "best"), 42);&lt;/code&gt;. Here &lt;code&gt;C&lt;/code&gt; is a helper class, who has a constructor &lt;code&gt;C(const char* fmt)&lt;/code&gt; for the format string, and the relevant &lt;code&gt;const C&amp; operator,(const C&amp;, const char*)&lt;/code&gt; and &lt;code&gt;const C&amp; operator,(const C&amp;, int)&lt;/code&gt; comma operators are overloaded to do the actual printing, consuming a few more characters in the meantime from the format string, and using that format specifier to format the argument. Type safety is provided by the built-in overloading features of the C++ language (i.e. a different &lt;code&gt;operator,&lt;/code&gt; is called based on the type of the argument).&lt;p&gt;One more trick is needed to get an compile-time error when printing of values of unsupported type is attempted, e.g. &lt;code&gt;class Bad {}; Printf("%s", Bad());&lt;/code&gt;. By default, since there is no &lt;code&gt;operator,&lt;/code&gt; overridden for the class &lt;code&gt;Bad&lt;/code&gt;, the default comma operator is used silently, which is quite useless (compute the first argument, discard it, compute the second argument, return it), and effectively prevents the rest of the arguments from being printed. The solution here is to define &lt;code&gt;template&amp;lt;typename T&amp;gt;void operator,(const C&amp;, T t) { ... }&lt;/code&gt;, which would match all types (which are not matched by the non-template version of &lt;code&gt;operator,&lt;/code&gt;), and if we write &lt;code&gt;...&lt;/code&gt; so that it produces a type error, then the problem is solved.&lt;p&gt;The source code of such a typesafe &lt;code&gt;printf()&lt;/code&gt; implementation for C++ is available at &lt;a href="http://code.google.com/p/pts-mini-gpl/source/browse/#svn/trunk/pts-printf"&gt;http://code.google.com/p/pts-mini-gpl/source/browse/#svn/trunk/pts-printf&lt;/a&gt;. For the convenience of the programmer, it implements all these:&lt;pre class="syntax"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;  &lt;span class="c1"&gt;// To stdout.&lt;/span&gt;&lt;br /&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FILE&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;&lt;br /&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ostream&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;&lt;br /&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ostringstream&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;&lt;br /&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ofstream&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;&lt;br /&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;  &lt;span class="c1"&gt;// Append to string.&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;SPrintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;Please note that the implementation is not optimized for speed. Mostprobably it's not possible to implement a typesafe version of &lt;code&gt;printf()&lt;/code&gt;which is also as fast.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-5741708799814554942?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/5741708799814554942/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=5741708799814554942' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/5741708799814554942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/5741708799814554942'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/01/how-to-implement-c-printf-function-in-c.html' title='How to implement the C printf function in C++ in a typesafe way?'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-7068633042415792736</id><published>2011-01-06T14:58:00.000+01:00</published><updated>2011-01-06T14:58:17.364+01:00</updated><title type='text'>How to drop caches on Linux?</title><content type='html'>&lt;p&gt;This blog post explains how to drop in-memory cache of data on disk (pagecache, dentries, inodes) on Linux. Dropping the cache is useful if one wants to run filesystem benchmarks in a reproducible way.&lt;p&gt;To drop the caches, run&lt;pre&gt;$ echo 3 | sudo tee /proc/sys/vm/drop_caches&lt;/pre&gt;&lt;p&gt;The solution above is from &lt;a href="http://www.kernel.org/doc/Documentation/sysctl/vm.txt"&gt;http://www.kernel.org/doc/Documentation/sysctl/vm.txt&lt;/a&gt;. Some other useful commands mentioned there:&lt;pre&gt;$ echo 1 | sudo tee /proc/sys/vm/drop_caches  # drop pagecache&lt;br /&gt;$ echo 2 | sudo tee /proc/sys/vm/drop_caches  # drop dentries and inodes&lt;br /&gt;$ echo 3 | sudo tee /proc/sys/vm/drop_caches  # drop pagecache, dentries and inodes&lt;/pre&gt;Note: As this is a non-destructive operation and dirty objects are not freeable, the user should run &lt;code&gt;sync&lt;/code&gt; first.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-7068633042415792736?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/7068633042415792736/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=7068633042415792736' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7068633042415792736'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7068633042415792736'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/01/how-to-drop-caches-on-linux.html' title='How to drop caches on Linux?'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-6677852533571006310</id><published>2011-01-05T18:09:00.005+01:00</published><updated>2011-01-05T19:51:51.436+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='kitchen'/><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><category scheme='http://www.blogger.com/atom/ns#' term='announcement'/><category scheme='http://www.blogger.com/atom/ns#' term='fake'/><category scheme='http://www.blogger.com/atom/ns#' term='unix'/><title type='text'>Announcement from the Unix kitchen staff</title><content type='html'>&lt;p&gt;A restaurant called &lt;i&gt;fork()&lt;/i&gt; has recently been opened in our office building. The name was suggested and chosen by engineers. I imagine what kind of e-mail announcements they would be sending if the kitchen was run by Unix engineers.&lt;p&gt;fork() will be close()d this week, but it will not beshutdown(), we'll open() it again, but you have to wait() a couple ofdays. In the meantime, our hard-working and prof()essional kitchenstaff is not idle(): they are learning new Asian recipes. Pleaseread() the signs before coming to check if fork() is open(). We hope you'llhave a great time() eating Peking duck, a broad select()ion ofsandwiches, and ricEAGAIN with nice(), un-break()able chopsticks, 5times() a week. We have installed a new smoke extinguisher, which issplice()d to the oven, so it won't signal() the fire alarm() anymoreunnecessarily. If you have feedback, please write() to us. Or fill ourpoll() from (see the new link() on the home page) to help us keep insync() with the employees' taste. Your creat()ive ideas are alsowelcome to improve the furniture decoration &amp;ndash; it can also be aclone() of a restaurant in popular culture, with some geek flavoradded. Please note you don't have access() to the building from theexit() on the 3rd floor, so enter at the reception, but lock() yourbike first outside, to one of the pipe()s. There is no need to pause()in break() 3 for coffee, there is a grinder in fork() now.&lt;p&gt;**environ-mentalist disclaimer: No silkworms were kill()ed for theoutfit of our cooks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-6677852533571006310?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/6677852533571006310/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=6677852533571006310' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/6677852533571006310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/6677852533571006310'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2011/01/announcement-from-unix-kitchen-staff.html' title='Announcement from the Unix kitchen staff'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-1938171360694421313</id><published>2010-12-19T20:07:00.005+01:00</published><updated>2010-12-19T20:18:14.909+01:00</updated><title type='text'>How to write a C++ program without libstdc++</title><content type='html'>&lt;p&gt;This blog post explains how to write a C++ program and compile with GCC (&lt;code&gt;g++&lt;/code&gt;) so that the resulting binary doesn't depend on libstdc++. The reason for avoiding libstdc++ can be purity (don't depend on libraries you don't really need) and statically linking small tools (e.g. for Unix or Win32 console applications with MinGW).&lt;p&gt;The limitations are:&lt;ul&gt;&lt;li&gt;The standard C++ STL (e.g. &lt;code&gt;#include &amp;lt;string&amp;gt;&lt;/code&gt; and &lt;code&gt;#include &amp;lt;vector&amp;gt;&lt;/code&gt;) cannot be used. This functionality has to be reimplemented in the program.&lt;li&gt;The standard C++ streams (e.g. &lt;code&gt;#include &amp;lt;iostream&amp;gt;&lt;/code&gt;) cannot be used. The standard C I/O library (e.g. &lt;code&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/code&gt;) is a smaller and faster replacement. A disadvantage: there is no polymorphic &lt;code&gt;operator&amp;lt;&amp;lt;(ostream&amp;amp;, ...)&lt;/code&gt; method for convenient, type-agnostic output.&lt;li&gt;Exceptions cannot be used (i.e. &lt;code&gt;try&lt;/code&gt;, &lt;code&gt;catch&lt;/code&gt; and &lt;code&gt;throw&lt;/code&gt; are disallowed).&lt;li&gt;RTTI (run-time type information) cannot be used.&lt;li&gt;&lt;code&gt;dynamic_cast&amp;lt;...&amp;gt;(...)&lt;/code&gt; cannot be used (because it requires RTTI).&lt;/ul&gt;&lt;p&gt;Here is how to do it:&lt;ul&gt;&lt;li&gt;Add the following C++ code to your program (can be in a separate source file):&lt;pre&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;#include &amp;lt;unistd.h&amp;gt;  /* for write(), also available on Windows */&lt;br /&gt;extern "C" void* emulate_cc_new(unsigned len) { \&lt;br /&gt;  void *p = malloc(len);&lt;br /&gt;  if (p == 0) {&lt;br /&gt;    /* Don't use stdio (e.g. fputs), because that may want to allocate more&lt;br /&gt;     * memory.&lt;br /&gt;     */&lt;br /&gt;    (void)!write(2, "out of memory\n", 14);&lt;br /&gt;    abort();&lt;br /&gt;  }&lt;br /&gt;  return p;&lt;br /&gt;}&lt;br /&gt;extern "C" void emulate_cc_delete(void* p) {&lt;br /&gt;  if (p != 0)&lt;br /&gt;    free(p);&lt;br /&gt;}&lt;br /&gt;void* operator new  (unsigned len) __attribute__((alias("emulate_cc_new")));&lt;br /&gt;void* operator new[](unsigned len) __attribute__((alias("emulate_cc_new")));   &lt;br /&gt;void  operator delete  (void* p)   __attribute__((alias("emulate_cc_delete")));&lt;br /&gt;void  operator delete[](void* p)   __attribute__((alias("emulate_cc_delete")));&lt;br /&gt;void* __cxa_pure_virtual = 0;&lt;/pre&gt;&lt;li&gt;Compile your program with &lt;code&gt;g++ -c&lt;/code&gt; to create individual &lt;code&gt;.o&lt;/code&gt; files. Add flags &lt;code&gt;-fno-rtti -fno-exceptions&lt;/code&gt; to get compile errors for disabled features (exceptions and RTTI).&lt;li&gt;Link your executable with &lt;code&gt;gcc -o prog code1.o code2.o ...&lt;/code&gt; It's important that you use &lt;code&gt;gcc&lt;/code&gt; here instead of &lt;code&gt;g++&lt;/code&gt; because &lt;code&gt;g++&lt;/code&gt; would link against libstdc++.&lt;/ul&gt;&lt;p&gt;This method has been tested and found working with GCC 3.2, GCC 4.2.1 and GCC 4.4.1 (both native Linux compilation and MinGW compilation), and it probably works with other GCC versions as well.&lt;p&gt;If you need &lt;code&gt;dynamic_cast&lt;/code&gt;, add &lt;code&gt;void* __gxx_personality_v0 = 0;&lt;/code&gt;, don't use &lt;code&gt;-fno-rtti&lt;/code&gt;, and add &lt;code&gt;dyncast.a&lt;/code&gt; to the &lt;code&gt;gcc -o ...&lt;/code&gt; command-line. Here is how to create &lt;code&gt;dyncast.a&lt;/code&gt; (about 55kB) for GCC 4.4.1:&lt;pre&gt;$ ar x /usr/lib/gcc/i486-linux-gnu/4.4/libstdc++.a \&lt;br /&gt;  dyncast.o class_type_info.o si_class_type_info.o pointer_type_info.o \&lt;br /&gt;  pbase_type_info.o tinfo.o fundamental_type_info.o&lt;br /&gt;$ ar crs dyncast.a \&lt;br /&gt;  dyncast.o class_type_info.o si_class_type_info.o pointer_type_info.o \&lt;br /&gt;  pbase_type_info.o tinfo.o fundamental_type_info.o&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-1938171360694421313?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/1938171360694421313/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=1938171360694421313' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1938171360694421313'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1938171360694421313'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/12/how-to-write-c-program-without-libstdc.html' title='How to write a C++ program without libstdc++'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-8407639038860011392</id><published>2010-12-19T13:35:00.001+01:00</published><updated>2011-02-17T03:14:27.496+01:00</updated><title type='text'>How to boot GRUB from SysLinux</title><content type='html'>&lt;p&gt;This blog post explains how to boot GRUB from SysLinux. Only GRUB1 is covered, the solution explained doesn't support GRUB2.&lt;p&gt;Older versions of SysLinux (such as 3.83) don't support booting GRUB, i.e. they cannot load and boot the &lt;code&gt;stage2&lt;/code&gt; file of GRUB. The newest version of SysLinux contains &lt;code&gt;chain.c32&lt;/code&gt;, which can boot many operating systems and bootloaders, including GRUB. The solution explained here doesn't use this feature, so it works with old versions of SysLinux as well.&lt;p&gt;The fundamental idea is to convert the GRUB &lt;code&gt;stage2&lt;/code&gt; file to a format which SysLinux can boot directly. This format is &lt;i&gt;bzimage&lt;/i&gt;, the big variant of the Linux kernel image. &lt;code&gt;grub.exe&lt;/code&gt;, part of &lt;a href="http://download.gna.org/grub4dos/"&gt;GRUB4DOS&lt;/a&gt; is already in this format, so adding the following lines to &lt;code&gt;syslinux.cfg&lt;/code&gt; works:&lt;pre&gt;label grub4dos&lt;br /&gt;menu label GRUB4DOS&lt;br /&gt;kernel grub.exe&lt;/pre&gt;&lt;p&gt;However, one might wish to use the original GRUB instead, because GRUB4DOS has some features missing, e.g. it doesn't support GPT (GUID Partition Table) and UUID on reisrefs partitions. Converting the original GRUB &lt;code&gt;stage2&lt;/code&gt; file to bzimage format is easy: just append it to the first 20480 bytes of &lt;code&gt;grub.exe&lt;/code&gt;. SysLinux can boot this hybrid, but then GRUB wouldn't be able to find its &lt;code&gt;configfile&lt;/code&gt; (&lt;code&gt;menu.lst&lt;/code&gt;). To fix that, the full pathname of the configuration file has to be embedded to the boot image. The Perl script &lt;a href="http://pts-mini-gpl.googlecode.com/svn-history/r183/trunk/grub2bzimage/grub2bzimage.pl"&gt;grub2bzimage.pl&lt;/a&gt; automates this.&lt;p&gt;&lt;a href="http://code.google.com/p/pts-mini-gpl/source/browse/#svn/trunk/grub2bzimage"&gt;grub2bzimage&lt;/a&gt; is a Perl script which converts the GRUB bootloader code(&lt;code&gt;stage2&lt;/code&gt;) to bzimage format, which can be booted directly by SysLinux andother bootloaders. grub2bzimage.pl doesn't support GRUB2.&lt;p&gt;Example use to create &lt;code&gt;grubzimg&lt;/code&gt;:&lt;pre&gt;$ perl ./grub2bzimage.pl stage2 grubzimg '(hd0,0)/boot/grub/menu.lst'&lt;/pre&gt;Write this into &lt;code&gt;syslinux.cfg&lt;/code&gt;:&lt;pre&gt;label grub&lt;br /&gt;menu label GRUB&lt;br /&gt;kernel grubzimg&lt;/pre&gt;&lt;p&gt;Please note that it's not possible to specify the name of the configfile(&lt;code&gt;menu.lst&lt;/code&gt;) in &lt;code&gt;syslinux.cfg&lt;/code&gt; (using &lt;code&gt;append&lt;/code&gt;). The configfile has to be specified when &lt;code&gt;grubzimg&lt;/code&gt; is created.&lt;p&gt;grub2bzimage.pl has been tested with SysLinux 3.83. Please note that newerversions of SysLinux contain chain.c32 which supports loading GRUB stage2 files directly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-8407639038860011392?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/8407639038860011392/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=8407639038860011392' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/8407639038860011392'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/8407639038860011392'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/12/how-to-boot-grub-from-syslinux.html' title='How to boot GRUB from SysLinux'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-4488919275557711509</id><published>2010-12-14T16:02:00.000+01:00</published><updated>2010-12-14T16:02:28.657+01:00</updated><title type='text'>How to get multiple clickable desktop notifications on Ubuntu Lucid</title><content type='html'>&lt;p&gt;This blog post explains how to get multiple clickable desktop notifications (i.e. those that were present on Ubuntu Hardy) on the default GNOME desktop of Ubuntu Lucid.&lt;p&gt;Desktop notifications are short messages displayed by programs for a short time in one of the corners of the screen. In Ubuntu Lucid, by default, they are displayed in the top right corner, their background is black, they are not clickable (i.e. it's not possible to click them away), they disappear while the mouse is over them, and at least 1 of them is visible at the same time. In Ubuntu Hardy, they are displayed in the bottom right corner of the screen, their background is similar to light grey, they are clickable (i.e. they disappear for good if the user clicks on them), they don't disappear while the mouse is over them, and if more than one of them can be on screen without overlap.&lt;p&gt;Ubuntu Lucid uses the &lt;i&gt;notify-osd&lt;/i&gt; backend for displaying notifications. It's not possible to configure the &lt;i&gt;notify-osd&lt;/i&gt; backend to make it work like Ubuntu Hardy. However, it's possible to install &lt;i&gt;notification-daemon&lt;/i&gt;, which was the default backend in Ubuntu Hardy to for displaying notifications. Here is how to make it work in Ubuntu Lucid:&lt;pre&gt;$ sudo apt-get install notification-daemon&lt;br /&gt;$ sudo perl -pi -e 's@^Exec=.*@Exec=/usr/lib/notification-daemon/notification-daemon@' /usr/share/dbus-1/services/org.freedesktop.Notifications.service&lt;br /&gt;$ sudo killall notify-osd&lt;/pre&gt;&lt;p&gt;Try it with:&lt;pre&gt;$ notify-send foo; notify-send bar&lt;/pre&gt;&lt;p&gt;Optional change to disable &lt;i&gt;notify-osd&lt;/i&gt; completely: (It may screw up volume notifications etc., so don't use it unless it doesn't work without it.)&lt;pre&gt;$ sudo rm -f /usr/share/dbus-1/services/org.freedesktop.Notifications.service.*&lt;/pre&gt;&lt;p&gt;See &lt;a href="http://superuser.com/questions/221905/command-line-desktop-notifications-on-on-ubuntu-lucid"&gt;this discussion&lt;/a&gt; with some links for other &lt;i&gt;notify-osd&lt;/i&gt; improvements and alternatives.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-4488919275557711509?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/4488919275557711509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=4488919275557711509' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/4488919275557711509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/4488919275557711509'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/12/how-to-get-multiple-clickable-desktop.html' title='How to get multiple clickable desktop notifications on Ubuntu Lucid'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-2790041274834392781</id><published>2010-12-11T18:14:00.002+01:00</published><updated>2010-12-11T18:18:53.796+01:00</updated><title type='text'>A dramatic colored picture of a tiger's head</title><content type='html'>&lt;p&gt;This blog post documents my unsuccessful software archeology attempt to find the origin and the author of the famous &lt;a href="http://commons.wikimedia.org/wiki/File:Ghostscript_Tiger.svg"&gt;PostScript tiger&lt;/a&gt; colorful vector graphics. Get the (mostly unchanged) EPS file from the Ghostscript SVN repository, &lt;a href="http://svn.ghostscript.com/viewvc/trunk/gs/examples/tiger.eps"&gt;here&lt;/a&gt;.&lt;p&gt;The earliest Ghostscript version containing the tiger I could dig up is version 2.6.1 (5/28/93) &lt;a href="http://ftp.se.scene.org/pub/slackware/slackware-1.1.2/ap2/ghostscr.tgz"&gt;[download]&lt;/a&gt; in Slackware Linux 1.1.2. FYI The earliest Ghostscript version in Debian is 2.6.1 as well &lt;a href="http://archive.debian.org/debian/dists/Debian-0.93R6/source/text/ghostscript-2.6.1pl4-5.tar.gz"&gt;[download]&lt;/a&gt;.&lt;p&gt;The image itself contains the comment &lt;code&gt;%%CreationDate: 4/12/90 3:20 AM&lt;/code&gt;, so the earliest possible Ghostscript version that can contain it is 2.0 (released on 9/12/90) &amp;mdash; but I wasn't able to find a download link for that Ghostscript. The author and the copyright is not indicated. The only description is found in the Ghostscript &lt;code&gt;history.doc&lt;/code&gt; file, saying &lt;i&gt;tiger.ps - A dramatic colored picture of a tiger's head&lt;/i&gt;.&lt;p&gt;Even Wikipedia doesn't specify the origin of the tiger graphics. All I could find is &lt;a href="http://en.wikipedia.org/wiki/Talk:Ghostscript#Origin_of_tiger.eps.3F_.28aka_.22cubic_spline_tiger.22.29"&gt;this question&lt;/a&gt; asking where it comes from.&lt;p&gt;Here is the relevant part of the EPS header in the &lt;code&gt;tiger.ps&lt;/code&gt; and &lt;code&gt;tiger.eps&lt;/code&gt; file:&lt;pre&gt;%%Creator: Adobe Illustrator(TM) 1.2d4&lt;br /&gt;%%For: OpenWindows Version 2&lt;br /&gt;%%Title: tiger.eps&lt;br /&gt;%%CreationDate: 4/12/90 3:20 AM&lt;br /&gt;%%DocumentProcSets: Adobe_Illustrator_1.2d1 0 0&lt;br /&gt;%%DocumentSuppliedProcSets: Adobe_Illustrator_1.2d1 0 0&lt;/pre&gt;&lt;p&gt;What I've learned: Linux distributions (especially Debian and Slackware) are very useful sources of the source code of ancient versions of some free software.&lt;p&gt;The origin of the tiger thus remains unsolved.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-2790041274834392781?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/2790041274834392781/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=2790041274834392781' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2790041274834392781'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2790041274834392781'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/12/dramatic-colored-picture-of-tigers-head.html' title='A dramatic colored picture of a tiger&apos;s head'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-1637639729418234244</id><published>2010-12-07T01:59:00.001+01:00</published><updated>2010-12-07T02:00:22.401+01:00</updated><title type='text'>It is a misconception that C++ is a superset of C</title><content type='html'>&lt;p&gt;This blog post shows (with a counterexample) that C++ is not a superset of C, i.e. there is a valid C program which is not a valid C++ program.&lt;p&gt;It's easy to find a counterexample: just use a C++ keyword as a variable name in C. The program is &lt;code&gt;int class;&lt;/code&gt;. The proof:&lt;pre&gt;$ gcc -v&lt;br /&gt;gcc version 4.4.1 (Ubuntu 4.4.1-4ubuntu9)&lt;br /&gt;$ g++ -v&lt;br /&gt;gcc version 4.4.1 (Ubuntu 4.4.1-4ubuntu9)&lt;br /&gt;$ echo 'int class;' | tee t.c t.cc &gt;/dev/null&lt;br /&gt;$ gcc -c -pedantic -ansi -W -Wall t.c&lt;br /&gt;$ g++ -c t.cc&lt;br /&gt;t.cc:1: error: expected identifier before ‘;’ token&lt;br /&gt;t.cc:1: error: multiple types in one declaration&lt;br /&gt;t.cc:1: error: declaration does not declare anything&lt;/pre&gt;&lt;p&gt;There is a counterexample which doesn't contain any C++ keywords. The program is &lt;code&gt;int i=&amp;amp;i;&lt;/code&gt;. The code:&lt;pre&gt;$ echo 'int i=&amp;amp;i;' | tee t.c t.cc &gt;/dev/null&lt;br /&gt;$ gcc -c -pedantic -ansi -W -Wall t.c&lt;br /&gt;t.c:1: warning: initialization makes integer from pointer without a cast&lt;br /&gt;$ g++ -c t.cc&lt;br /&gt;t.cc:1: error: invalid conversion from ‘int*’ to ‘int’&lt;/pre&gt;&lt;p&gt;There is a counterexample which doesn't contain any C++ keywords, and it compiles without a warning as C code. The program is &lt;code&gt;char *p=(void*)0;&lt;/code&gt;&lt;pre&gt;$ echo 'char *p=(void*)0;' | tee t.c t.cc &gt;/dev/null&lt;br /&gt;$ gcc -c -pedantic -ansi -W -Wall t.c&lt;br /&gt;$ gcc -c -pedantic -std=c89 -W -Wall t.c&lt;br /&gt;$ gcc -c -pedantic -std=c99 -W -Wall t.c&lt;br /&gt;$ gcc -c -pedantic -std=c9x -W -Wall t.c&lt;br /&gt;$ gcc -c -pedantic -std=gnu89 -W -Wall t.c&lt;br /&gt;$ gcc -c -pedantic -std=gnu99 -W -Wall t.c&lt;br /&gt;$ gcc -c -pedantic -std=gnu9x -W -Wall t.c&lt;br /&gt;$ tcc -W -Wall -c t.c&lt;br /&gt;$ 8c -c -w t.c&lt;br /&gt;$ g++ -c t.cc&lt;br /&gt;t.cc:1: error: invalid conversion from ‘void*’ to ‘char*’&lt;/pre&gt;&lt;p&gt;As a bonus: there is a program source which compiles in both C and C++, but it does something different. The following example is based on the fact that &lt;code&gt;sizeof('x')&lt;/code&gt; is 1 in C++, but it's at least 2 in C.&lt;pre&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;int main(){return!printf("Hello, C%s!\n", "++"+1%sizeof('x')*2);}&lt;/pre&gt;&lt;p&gt;Another idea to make the same program source do something else in C than C++ is to take advantage of that &lt;code&gt;union t&lt;/code&gt; (etc.) create a type named &lt;code&gt;t&lt;/code&gt; in C++, but not in C.&lt;pre&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;char t; int main(){union t{int u;};&lt;br /&gt;return!printf("Hello, C%s!\n", "++"+(sizeof(t)&amp;lt;2)*2);}&lt;/pre&gt;&lt;p&gt;So the true statement is: C and C++ are similar languages, with a large common subset, and C++ being much larger to the common subset than C is.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-1637639729418234244?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/1637639729418234244/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=1637639729418234244' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1637639729418234244'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1637639729418234244'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/12/it-is-misconception-that-c-is-superset.html' title='It is a misconception that C++ is a superset of C'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-8250449712324343089</id><published>2010-12-05T22:36:00.000+01:00</published><updated>2010-12-05T22:36:53.501+01:00</updated><title type='text'>On browser compatibility issues</title><content type='html'>&lt;p&gt;This blog post lists the browser compatibility issues (with solutions) I've encountered when creating a simple HTML(4) + JavaScript + CSS web page containing &lt;a href="http://syncless.googlecode.com/svn/trunk/doc/slides_2010-11-29/pts_coro_2010-11-29.html"&gt;presentation slides&lt;/a&gt; with a little bit of user interaction.&lt;p&gt;My goal was to make the web page compatible with Google Chrome 8.0 or later, Firefox 3.6 or later, Safari in Leopard or later, Opera 10.63 or later, Konqueror 4.4.2 or later, Internet Explorer 8.0 or later. (I'll call them &lt;i&gt;main browsers&lt;/i&gt; from now on.) Please note that anything stated in this blog post may not be true for earlier web browser versions. There was no plan to make the web page work in any earlier web browser version, but it turned out that it was possible and easy to make the page work with Internet Explorer 7.0 with some small rendering quality degradation, so I happened to add support for that as well.&lt;p&gt;My workflow:&lt;ul&gt;&lt;li&gt;Edit the web page directly in a text editor, as a single HTML file (containing HTML, JavaScript and CSS). Split it to different files only after the prototype is found working and all browser compatibility issues have been registered (and most of them resolved).&lt;li&gt;Make sure the browser renders the page in &lt;i&gt;standards compliant mode&lt;/i&gt;, not in &lt;i&gt;quirks mode&lt;/i&gt; (see below how and why).&lt;li&gt;View the local HTML file in Google Chrome, reload the page after each file save. Try it after major modifications in Firefox. As soon as the web page works in these two browsers, fix it for other browsers as well.&lt;li&gt;When porting to other browsers, especially Internet Explorer, search in the &lt;a href="http://code.jquery.com/jquery.js"&gt;jQuery source code&lt;/a&gt; for the feature (class or method name) that works in one browser. Most probably they jQuery source will contain its alternative implementations for other browsers.&lt;li&gt;Use the &lt;i&gt;Developer Tools&lt;/i&gt; feature of Google Chrome (activate it with Ctrl-Shift-&lt;i&gt;J&lt;/i&gt;) to debug the DOM, the CSS and the JavaScript on the current page. With Firefox, use the &lt;a href="http://www.getfirebug.com"&gt;Firebug&lt;/a&gt; extension and/or the &lt;a href="https://www.squarefree.com/bookmarklets/webdevel.html"&gt;shell bookmarklet&lt;/a&gt; for debugging. Should you need it, use the Tools / &lt;a href="http://en.wikipedia.org/wiki/Internet_Explorer_Developer_Toolbar"&gt;Developer Tools&lt;/a&gt; (activate it with &lt;i&gt;F12&lt;/i&gt;; it is available as an extension called Developer Toolbar for IE7 and earlier) in Internet Explorer 8 for debugging.&lt;li&gt;With Internet Explorer Developer Tools you can verify that the web page is indeed rendered in standards compliant mode, and you can also force a rendering which Internet Explorer 7 would do.&lt;li&gt;After each major change, &lt;a href="http://validator.w3.org/"&gt;validate&lt;/a&gt; the web page that it is valid HTML 4.01 transitional. You can use the &lt;a href="https://chrome.google.com/extensions/detail/cgndfbhngibokieehnjhbjkkhbfmhojo"&gt;HTML Validator&lt;/a&gt; Google Chrome extension.&lt;/ul&gt;&lt;p&gt;My general knowledge and advice on cross-browser compatibility:&lt;ul&gt;&lt;li&gt;All main browsers (Google Chrome, Firefox, Safari, Opera and Konqueror) are very similar to each other except for Internet Explorer.&lt;li&gt;Google Chrome, Safari and Konqueror are even more similar to each other, because they share the same original code base (KHTML in Konqueror, which WebKit in Safari is based on, which WebKit in GoogleChrome is based on).&lt;li&gt;Rendering (application of CSS) in most main browsers in much more similar to each other when they render the web page in &lt;i&gt;standards compliant mode&lt;/i&gt; rather than in &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Quirks_mode"&gt;quirks mode&lt;/a&gt;&lt;/i&gt;. So to get rid of many incompatibilities, just make sure that the browser renders the page in standards compliant mode.&lt;li&gt;To enable standards compliant mode, just start your HTML with a doctype (right at the beginning of the file). To get HTML 4.01 transitional, prepend this to your HTML file:&lt;pre&gt;&amp;lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&lt;br /&gt;    "http://www.w3.org/TR/html4/loose.dtd"&amp;gt;&lt;/pre&gt;&lt;li&gt;Make sure your editor saves the HTML file in UTF-8 encoding (character set), without the byte order mark (BOM).&lt;li&gt;Make sure the character set is indicatied the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;. This is needed and used when the web page is loaded using a &lt;code&gt;file:///&lt;/code&gt; URL or imported to a word processor such as OpenOffice Writer or LibreOffice Writer. Example:&lt;pre&gt;&amp;lt;meta http-equiv="content-type" content="text/html; charset=utf-8"&amp;gt;&lt;/pre&gt;&lt;li&gt;Make sure your webserver returns the proper character set for the web page in the HTTP response headers (e.g. &lt;code&gt;Content-Type: text/html; charset=utf-8&lt;/code&gt;). This setting is used for &lt;code&gt;http://&lt;/code&gt; and &lt;code&gt;https://&lt;/code&gt; URLs. The HTTP response header takes precedence over &lt;code&gt;&amp;lt;meta http-equiv=&lt;/code&gt;. If you use the Apache webserver, you may be able to force the UTF-8 charset by creating a file named &lt;code&gt;.htaccess&lt;/code&gt; (filename starting with a dot) next to the HTML file, containing &lt;pre&gt;AddDefaultCharset UTF-8&lt;/pre&gt;. If it doesn't seem to take effect, then put an error (temporarily) to the &lt;code&gt;.htaccess&lt;/code&gt; file (e.g. &lt;code&gt;nosuchdirective 42&lt;/code&gt;), do a Shift-reload on your web page. If that causes an &lt;i&gt;Internal Server Error&lt;/i&gt;, then &lt;code&gt;.htaccess&lt;/code&gt; is indeed honored by Apache. If you don't get such an error, talk to your webmaster or system administrator (i.e. copy-paste this paragraph to an e-mail in addition to the URL).&lt;li&gt;The corresponding SVN command (for Google Code) for the character set is:&lt;pre&gt;svn propset 'svn:mime-type' 'text/html; charset=utf-8' webpage.html&lt;/pre&gt;&lt;li&gt;Use &lt;a href="http://www.jquery.org/"&gt;jQuery&lt;/a&gt;, and make it take care of most browser compatibility issues. This document assumes, however, that no JavaScript framework is used, so all issues have to be resolved manually.&lt;/ul&gt;&lt;p&gt;Some specific cross-browser compatibility issues I have encountered:&lt;ul&gt;&lt;li&gt;See a cross-browser comparison of all JavaScript browser events &lt;a href="http://en.wikipedia.org/wiki/DOM_events"&gt;here&lt;/a&gt;.&lt;li&gt;Internet Explorer has a different API for installing and handling events.&lt;ul&gt;&lt;li&gt;Event propagation and bubbling semantics are different. You can avoid these issues by installing all event handlers for &lt;code&gt;document.body&lt;/code&gt; and &lt;code&gt;window&lt;/code&gt;. (Sorry, I don't know more about this.)&lt;li&gt;For Internet Explorer, change &lt;code&gt;obj.addEventListener(eventName, handler, false)&lt;/code&gt; to &lt;code&gt;obj.attachEvent('on' + eventName, handler)&lt;/code&gt;.&lt;li&gt;For Internet Explorer, change &lt;code&gt;obj.removeEventListener(eventName, handler, false)&lt;/code&gt; to &lt;code&gt;obj.detachEvent('on' + eventName, handler)&lt;/code&gt;.&lt;li&gt;Internet Explorer supports the &lt;code&gt;DOMContentLoaded&lt;/code&gt; event under a different name (&lt;code&gt;onreadystatechange&lt;/code&gt;) and different semantics, see below.&lt;li&gt;Internet Explorer needs &lt;code&gt;event.preventDefault()&lt;/code&gt; to be specified differently. Here is the cross-browser solution:&lt;pre&gt;event.preventDefault ? event.preventDefault() : (event.returnValue = false)&lt;/pre&gt;&lt;li&gt;Internet Explorer needs &lt;code&gt;event.stopPropagation()&lt;/code&gt; to be specified differently. Here is the cross-browser solution:&lt;pre&gt;event.stopPropagation ? event.stopPropagation() : (event.cancelBubble = true)&lt;/pre&gt;&lt;li&gt;Internet Explorer doesn't pass the &lt;code&gt;event&lt;/code&gt; object to the event handler function. To make it cross browser, write it like this:&lt;pre&gt;function handler(event) { if (!event) event = window.event; ... }&lt;/pre&gt;&lt;/ul&gt;&lt;li&gt;Internet Explorer doesn't have &lt;code&gt;window.getComputedStyle&lt;/code&gt;, so the current (computed) CSS properties have to be queried differently. An example, specific cross-browser solution:&lt;pre&gt;function getBackgroundColor(element) {&lt;br /&gt;  return element.currentStyle ? element.currentStyle.backgroundColor :&lt;br /&gt;         window.getComputedStyle(element, null).&lt;br /&gt;         getPropertyValue('background-color')&lt;br /&gt;}&lt;/pre&gt;&lt;li&gt;Internet Explorer 8 doesn't have &lt;code&gt;elementOrDocument.getElementsByClassName&lt;/code&gt;, so it has to be emulated using a loop and e.g. &lt;code&gt;elementOrDocument.getElementsByTagName&lt;/code&gt; and some manual checking. The emulation is a bit slower.&lt;li&gt;The &lt;code&gt;string.substr&lt;/code&gt; method in Internet Explorer doesn't accept negative values in its first argument, so e.g. &lt;code&gt;myString.substr(-2)&lt;/code&gt; has to be replaced by &lt;code&gt;myString.substr(myString.length - 2)&lt;/code&gt;.&lt;li&gt;The &lt;code&gt;DOMContentLoaded&lt;/code&gt; event is fired as soon as the main HTML and the JavaScript and CSS files it references have finished loading &amp;mdash; but before images and other objects on the page have finished. By that time, the rendering is done and measurements are made, so e.g. &lt;code&gt;document.body.offsetWidth&lt;/code&gt; is valid. In contrast, the &lt;code&gt;onload&lt;/code&gt; even fires as soon as images etc. are also finished loading Here is how to handle &lt;code&gt;DOMContentLoaded&lt;/code&gt; in a cross-browser way:&lt;pre&gt;function onDomReady() {&lt;br /&gt;  ...&lt;br /&gt;}&lt;br /&gt;if (navigator.userAgent.indexOf(' KHTML/') &amp;gt;= 0) {&lt;br /&gt;  document.addEventListener('load', onDomReady, false) &lt;br /&gt;} else if (document.addEventListener) {&lt;br /&gt;  document.addEventListener('DOMContentLoaded', onDomReady, false)&lt;br /&gt;} else if (document.attachEvent) {&lt;br /&gt;  document.attachEvent('onreadystatechange', function() {&lt;br /&gt;    if (document.readyState == 'complete') {&lt;br /&gt;      document.detachEvent('onreadystatechange', onReadyStateChange)&lt;br /&gt;      onDomReady()&lt;br /&gt;    }&lt;br /&gt;  })&lt;br /&gt;}&lt;/pre&gt;Here, the &lt;code&gt;load&lt;/code&gt; event is used instead of &lt;code&gt;DOMContentLoaded&lt;/code&gt;, because Konqueror 4.4.2 doesn't compute element dimensions (e.g. &lt;code&gt;document.body.offsetWidth&lt;/code&gt; and CSS properties) at &lt;code&gt;DOMContentLoaded&lt;/code&gt; time; but it returns bogus default values. For Internet Explorer, &lt;code&gt;onreadystatechange&lt;/code&gt; has to be used instead.&lt;li&gt;There are two keyboard events when a key is pressed or auto-repeated: &lt;code&gt;keydown&lt;/code&gt; and &lt;code&gt;keypress&lt;/code&gt;.&lt;ul&gt;&lt;li&gt;Use &lt;code&gt;keypress&lt;/code&gt; for Google Chrome and Safari (i.e. &lt;code&gt;navigator.userAgent.indexOf(' AppleWebKit/') &amp;gt;= 0&lt;/code&gt;), because they don't send the arrow key (and any other non-letter) events for &lt;code&gt;keypress&lt;/code&gt;.&lt;li&gt;Use &lt;code&gt;keydown&lt;/code&gt; for Firefox (for 3.6), because it doesn't send auto-repeats for &lt;code&gt;keydown&lt;/code&gt; (see more &lt;a href="https://developer.mozilla.org/en/DOM/Event/UIEvent/KeyEvent"&gt;here&lt;/a&gt;).&lt;li&gt;Use &lt;code&gt;onkeydown&lt;/code&gt; on Internet Explorer.&lt;li&gt;Some browsers have a meaningless &lt;code&gt;event.keyCode&lt;/code&gt; (such as 0 for Firefox 3.6 or the same as the &lt;code&gt;event.charCode&lt;/code&gt; for Konqueror 4.4.2) for some keys. In this case, use the &lt;code&gt;event.charCode&lt;/code&gt; instead.&lt;li&gt;The &lt;code&gt;event.charCode&lt;/code&gt; depends on whether &lt;i&gt;Shift&lt;/i&gt; is down (e.g. 65 for &lt;i&gt;A&lt;/i&gt; and 97 for Shift-&lt;i&gt;A&lt;/i&gt;), but it doesn't depend on whether &lt;i&gt;Ctrl&lt;/i&gt; or other modifiers are down. &lt;code&gt;event.charCode&lt;/code&gt; is usually a Unicode code point (character code).&lt;li&gt;See &lt;code&gt;event.keyCode&lt;/code&gt; constants &lt;a href="https://developer.mozilla.org/en/DOM/Event/UIEvent/KeyEvent"&gt;here&lt;/a&gt;.&lt;li&gt;See more &lt;a href="http://www.quirksmode.org/js/keys.html"&gt;here&lt;/a&gt; about keyboard event compatibility.&lt;/ul&gt;&lt;li&gt;Many browsers (such as Firefox 3.6) send multiple &lt;code&gt;resize&lt;/code&gt; events (as part of an animation) when the window is maximized.&lt;li&gt;To get the vertical scroll position, use &lt;code&gt;document.body.scrollTop || document.documentElement.scrollTop&lt;/code&gt;, because Konqueror always returns 0 for just &lt;code&gt;document.body.scrollTop&lt;/code&gt;. Do this respectively for the horizontal scroll position (&lt;code&gt;scrollLeft&lt;/code&gt;).&lt;li&gt;To scroll the page in a cross-browser way (which works in Konqueror as well), use &lt;code&gt;window.scroll(newScrollLeft, newScrollTop)&lt;/code&gt; .&lt;li&gt;Internet Explorer doesn't support &lt;code&gt;window.innerWidth&lt;/code&gt;, use &lt;code&gt;window.innerWidth || document.documentElement.clientWidth&lt;/code&gt; for cross-browser compatibility. Do the same with &lt;code&gt;window.innerHeight&lt;/code&gt; and &lt;code&gt;document.documentElement.clientHeight&lt;/code&gt; as well.&lt;li&gt;Internet Explorer 7 doesn't support an extra comma right before &lt;code&gt;]&lt;/code&gt; and &lt;code&gt;}&lt;/code&gt; in array and object constructors.&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-8250449712324343089?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/8250449712324343089/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=8250449712324343089' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/8250449712324343089'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/8250449712324343089'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/12/on-browser-compatibility-issues.html' title='On browser compatibility issues'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-5891459168355915850</id><published>2010-11-28T23:47:00.000+01:00</published><updated>2010-11-28T23:47:47.802+01:00</updated><title type='text'>Announcing uevalrun: self-contained computation sandbox for Linux</title><content type='html'>&lt;p&gt;This blog post is to announce uevalrun.&lt;p&gt;&lt;i&gt;uevalrun&lt;/i&gt; is a self-contained computation sandbox for Linux, usingUser-mode Linux for both compilation and execution of the program to besandboxed. The program can be written in C, C++, Python, Ruby, Perl or PHP.uevanrun enforces memory limits, timeouts and output size limits in thesandbox. The primary use case for uevalrun is evaluation of solutionprograms submitted by contestants of programming contests: uevalrun compilesthe solution, runs it with the test input, compares its output againstthe expected output, and writes a status report.&lt;p&gt;For your convenience, here is a (non-updated) copy of the documenation of uevalrun. See &lt;a href="http://code.google.com/p/pts-mini-gpl/wiki/uevalrun"&gt;project home page&lt;/a&gt; for the most up-to-date version.&lt;h3&gt;Installation&lt;/h3&gt;&lt;p&gt;A 32-bit (x86, i386) or 64-bit (x86_64, amd64) Linux system is requiredwith enough RAM for both compilation and execution, plus 6 MB memoryoverhead. The Linux distribution doesn't matter, because uevalrun usesstatically linked binaries, and it's self-contained: it contains all thetools it needs, including the C and C++ compilers (from the uClibc gcc-4.1.2toolchain).&lt;p&gt;uevalrun doesn't need root privileges: it runs as a simple user.&lt;p&gt;uevalrun needs about 160MB of disk space, most of which is consumed bythe C compiler (31MB extracted + 17MB compressed), the scripting languageinterpreters (9MB compressed), and the virtual disk images (77MB,uncompressed). After removing all temporary files, 80MB will be enough.&lt;p&gt;Download and compile:&lt;pre&gt;$ svn co http://pts-mini-gpl.googlecode.com/svn/trunk/uevalrun uevalrun&lt;br /&gt;$ cd uevalrun&lt;br /&gt;$ ./make  # This downloads some more files during compilation.&lt;/pre&gt;&lt;p&gt;Try it (the italic parts are displayed by the program):&lt;pre&gt;$ (echo '#! perl'; echo 'print "Hello"x2, "\n"') &gt;foo.pl&lt;br /&gt;$ echo HelloHello &gt;expected.txt&lt;br /&gt;$ ./uevalrun -M 10 -T 9 -E 9 -s foo.pl -t /dev/null -e expected.txt&lt;br /&gt;&lt;i&gt;...&lt;br /&gt;@ result: pass&lt;/i&gt;&lt;br /&gt;$ echo '/**/ int main() { return!printf("HelloHello\n"); }' &gt;foo.c&lt;br /&gt;$ ./uevalrun -M 10 -T 9 -E 9 -U 19 -N 32 -C 9 \&lt;br /&gt;  -s foo.c -t /dev/null -e expected.txt&lt;br /&gt;&lt;i&gt;...&lt;br /&gt;@ result: pass&lt;/i&gt;&lt;/pre&gt;&lt;h3&gt;How to use&lt;/h3&gt;&lt;p&gt;This section has not been written yet. If you have questions, don't hesitate to ask!&lt;h3&gt;Requirements&lt;/h3&gt;&lt;p&gt;Security is the most important requirement of uevalrun, followed by highperformance and usability.&lt;p&gt;The sandboxing must be secure, more specifically:&lt;ul&gt;&lt;li&gt;Programs inside the sandbox must not be able to communicate with    the outside world, except for their stdin and stdout. So they don't have    access to the filesystem (except for some read-only access to some    whitelisted system libraries and binaries), and they can't do network    I/O. If uevalrun is used for programming contest submission evaluation,    this restriction prevents the program from finding and reading the file    containing the expected output.&lt;li&gt;Sandboxed programs must not be able to use more system resources (memory,    disk, CPU) than what was allocated for them.&lt;li&gt;Sandboxed programs must not be running for a longer period of time than    what was allocated.&lt;li&gt;Even the compilation of programs to be run (executed) inside the sandbox    must be sandboxed (possibly with different system resource allocation),    to prevent the attacker from submitting a program source code which    exploits a bug in the compiler.&lt;li&gt;The sandbox must be reverted to its initial state before each compilation    and execution, so sandboxed programs won't be able to gather information    about previous compilations and executions. For programming contests,    this restriction prevents the program from reading other contestants'    submissions or their output.&lt;li&gt;Timeouts (both real time and user time) must be enforced outside the    sandbox, so the program will be reliably killed if it runs for too long    time, even if it tampers with time measurement inside the sandbox.&lt;li&gt;Sanboxed programs must not be able to lie about their success, their    performance or the correctness of their output by writing special marker    characters to their stdout or stderr.&lt;/ul&gt;&lt;p&gt;The sandbox must be fast and waste few resources, more specifically:&lt;ul&gt;&lt;li&gt;Reverting the sandbox to its initial, empty state must be very fast    (preferably faster than 1 second).&lt;li&gt;Starting a program inside the sandbox must be very fast (preferably    faster than 1 second).&lt;li&gt;Running a program inside the sandbox must not be much slower than running    the same program outside the sandbox. If the program is CPU-intensive,    it may run 1.1 times slower (i.e. 10% slower) inside than outside. If    the program is I/O-intensive, it may run 10 times slower inside than    outside. This requirement is intentionally quite loose on I/O    virtualization performance.&lt;li&gt;Running a program inside the sandbox must not need more than 10MB more    memory than running the same program outside.&lt;li&gt;Running a program inside the sandbox must not need any disk space,    except for the disk space needed by the program binary, the test input    and the expected output, all stored as files outside the sandbox.&lt;li&gt;Compilation inside the sandbox must require only a reasonable amount of    temporary disk space (for the file to be compiled, the temporary files,    and the output binary).&lt;/ul&gt;&lt;p&gt;The sandbox must be easy to use and versatile, more specifically:&lt;ul&gt;&lt;li&gt;Sandboxed programs must be able to accept any 8-bit binary input (stdin).&lt;li&gt;Sandboxed programs must be able to write any 8-bit binary output to    their stdout.&lt;li&gt;Multiple sandboxed programs must be able to run at the same time on the    same host system, without affecting each other.&lt;li&gt;If a sandboxed program fails (e.g. because it writes to its stdout    different from what was expected, or it does a memory access violation,    it reaches a timeout, it exceeds its allocated memory etc.), the proper    failure reason has to be reported (e.g. ``wrong answer'' must not be    reported if the program times out or vice versa).&lt;li&gt;The sandboxing software must have as little few system dependencies as    possible. It must be able to run in a restricted (e.g. chroot)    environment, it must not depend on system libraries or configuration.    It must work on 32-bit (x86, i386) and 64-bit (x86_64, amd64) Linux    systems, on any Linux distirubution.&lt;li&gt;Sandboxed programs can be written in C, C++, Python, Ruby, Perl and PHP,    or in any language whose compiler can produce a 32-bit (i386) Linux    statically linked executable binary.&lt;/ul&gt;&lt;h3&gt;Design&lt;/h3&gt;&lt;p&gt;To fullfill the requirements, the following fundamental building blocksare used.&lt;p&gt;&lt;a href="http://user-mode-linux.sourceforge.net/"&gt;User-mode Linux&lt;/a&gt;(UML) is used for virutalization: both compilation and execution isperformed in a UML guest, reading data from the host system using virtualblock devices (&lt;code&gt;ubd&lt;/code&gt;), and writing its output to its&lt;code&gt;/dev/tty1&lt;/code&gt; (&lt;code&gt;con0&lt;/code&gt;), which can be read by a processon the host. A UML guest kernel (currently 2.6.31.1) tailered to thesandboxing requirements (security and performance) is configured andcompiled. Some kernel patches are applied to increase security, reliabilityand performance. (Please note that these patches apply to the UML guestkernel only, so the host remains unpatched, and rebooting is not neededeither.) Networking and the virtual file system are disabled in the UMLguest kernel for increased security. All unnecessary drivers and featuresare removed from the UML guest kernel to get fast boot times and to reducethe overhead.&lt;p&gt;The underlying virtualization technology used by UML is&lt;a href="http://linux.die.net/man/2/ptrace"&gt;ptrace()&lt;/a&gt;, which doesn't needroot privileges or a kernel module or kernel modifications in the host. Asan alternative to UML, &lt;ahref="http://en.wikipedia.org/wiki/Seccomp"&gt;Seccomp&lt;/a&gt; could be used forsendboxing, but that's quite cumbersome, because the sandboxed processcannot allocate memory for itself (see &lt;ahref="http://code.google.com/p/seccompsandbox/"&gt;the Google Chrome Seccompsandbox&lt;/a&gt; for a generic solution), but it's still prohibitively cumbersometo sandbox GCC this way (with its requirements for forking and creatingtemporary files). Most sandboxing approaches on Linux require rootprivileges for a short amount of time (for chroot, PID namespaces (see&lt;a href="http://linux.die.net/man/2/clone"&gt;clone(2)&lt;/a&gt;) and othernamespaces). Most virtualization approaches (like &lt;ahref="http://www.linux-kvm.org/"&gt;KVM&lt;/a&gt;, &lt;ahref="http://en.wikipedia.org/wiki/Xen"&gt;Xen&lt;/a&gt;, &lt;ahref="http://www.virtualbox.org/"&gt;VirtualBox&lt;/a&gt;, except possibly for&lt;a href="http://wiki.qemu.org/"&gt;QEMU&lt;/a&gt;) need loading of kernel modules orpatching the kernel, and support only slow guest boot times.&lt;p&gt;With UML, it's possibly to boot the UML guest, run a hello-world binary,and halt the UML guest in less than 0.02 second (sustained). For that speed,one needs a (guest) kernel patch (included and automatically applied inuevalrun) which skips the &lt;i&gt;Calibrating delay loop&lt;/i&gt; kernel startup step,which usually takes 0.33 second. The memory overhead of UML is also quitelow (6 MB with a stripped-down kernel).&lt;p&gt;All software running inside and outside UML is written in C (for highperformance) and compiled with &lt;a href="http://www.uclibc.org"&gt;uClibc&lt;/a&gt;and linked statically to avoid depending on the libc on the host, and toavoid the need for installing a libc in the guest. (The total size of thesecustom-built binaries is less than 100kB.) There is no Linux distributioninstalled the guest &amp;ndash; only a few custom binaries are copied, like acustom &lt;code&gt;/sbin/init&lt;/code&gt;, which mounts &lt;code&gt;/proc&lt;/code&gt;, sets upfile descriptors and resource limits, and starts the sandboxed program, andthen halts the guest. The &lt;code&gt;/lib&lt;/code&gt; directory in the guest is empty,except for compilation, where &lt;code&gt;/lib&lt;/code&gt; contains&lt;code&gt;libc.a&lt;/code&gt;, &lt;code&gt;libstdc++.a&lt;/code&gt; etc.&lt;p&gt;&lt;a href="http://www.busybox.net/"&gt;BusyBox&lt;/a&gt; (statically linked withuClibc) is used as a Swiss Army Knife tool for scripting and automation (ofthe build and the setup process), both inside and outside UML. Please note,however, that once all the binaries are built and the filesystem images arecreated, BusyBox is not used anymore for running sandboxed programs andevaluating their output (except for temporary filesystem creation) becauseof performance reasons, but work is done by the small and fast custom Ctools just compiled.&lt;p&gt;Sandboxed program sources can be written in C (using a large subset of&lt;a href="http://www.uclibc.org/"&gt;uClibc&lt;/a&gt; as the system library), C++(using &lt;a href="http://www.uclibc.org/"&gt;uClibc&lt;/a&gt; and&lt;a href="http://gcc.gnu.org/libstdc++/"&gt;libstdc++&lt;/a&gt;), Python (usingall the built-in Python modules), Ruby (using just the built-in Rubymodules and classes which are implemented in C), Perl (using only thefew dozen most common modules), or PHP (using just the built-in PHPfunctions which are implemented in C).&lt;p&gt;For C and C++ compilation, a &lt;a href="http://gcc.gnu.org/"&gt;GCC&lt;/a&gt; 4.1.2toolchain is used which is based on&lt;a href="http://www.uclibc.org/"&gt;uClibc&lt;/a&gt; and produces statically linkedexecutables.&lt;p&gt;Interpreters for Python, Ruby, Perl and PHP are provided as precompiled,self-contained, single, statically linked, 32-bit (i386) Linux executables.It's easy to copy them to the &lt;code&gt;/bin&lt;/code&gt; directory of the UML guest.&lt;p&gt;All tools used for building the software are either shipped with thesoftware, or the software downloads them during compilation. All binarytools are statically linked, 32-bit (i386) Linux executables. This providesmaximum host system compatibility and reproducible behavior across systems.&lt;p&gt;In our speed measurements, CPU-intensive programs running inside UML run1% slower than outside UML, but I/O-intensive programs (such as C++compilation with GCC) can be about 6 times slower.&lt;p&gt;The &lt;a href="http://en.wikipedia.org/wiki/MINIX_file_system"&gt;Minix filesystem&lt;/a&gt;is used in the UML guests for both read-only filesystems (e.g. theroot filesystem with the scripting language interpreters) and read-writefilesystems (such as &lt;code&gt;/tmp&lt;/code&gt; for the temporary assembly filescreated by GCC). The Minix filesystem was chosen instead of ext2 and otherusual Linux filesystem, because it has less size overhead, it's codebase issmaller, and it has equally good performance for the small and mostlyread-only filesystems it is used for. &lt;h3&gt;License&lt;/h3&gt;&lt;p&gt;uevanrun has been released under the GNU GPL v2.&lt;h3&gt;Bugs? Problems? Contact the author. Send feedback!&lt;/h3&gt;&lt;p&gt;Please add your feedback to the &lt;ahref="http://code.google.com/p/pts-mini-gpl/issues/entry"&gt;issue tracker&lt;/a&gt;.All feedbacks are welcome.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-5891459168355915850?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/5891459168355915850/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=5891459168355915850' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/5891459168355915850'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/5891459168355915850'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/11/announcing-uevalrun-self-contained.html' title='Announcing uevalrun: self-contained computation sandbox for Linux'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-7865459729677758060</id><published>2010-11-19T11:06:00.001+01:00</published><updated>2010-11-19T11:09:03.082+01:00</updated><title type='text'>How to download Skype without having to register</title><content type='html'>&lt;p&gt;Recently Skype has introduced the requirement of registration or logging in on its web page before downloading the Windows version of their Skype software. This blog post explains how to download Skype without registration or logging in.&lt;p&gt;Follow the link relevant to your operating system:&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.skype.com/intl/en/get-skype/on-your-computer/linux/post-download/"&gt;Linux&lt;/a&gt;&lt;li&gt;&lt;a href="http://www.skype.com/intl/en/get-skype/on-your-computer/windows/post-download/"&gt;Windows&lt;/a&gt;&lt;li&gt;&lt;a href="http://www.skype.com/intl/en/get-skype/on-your-computer/macosx/post-download/"&gt;Mac&lt;/a&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-7865459729677758060?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/7865459729677758060/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=7865459729677758060' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7865459729677758060'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7865459729677758060'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/11/how-to-download-skype-without-having-to.html' title='How to download Skype without having to register'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-4353381901310278645</id><published>2010-11-15T16:52:00.002+01:00</published><updated>2010-11-15T16:52:55.280+01:00</updated><title type='text'>Remote desktop sharing for Linux without software installation and firewall configuration</title><content type='html'>&lt;p&gt;This blog post explains how to share two desktops (screen, keyboard and mouse) without software installation (on Linux) and firewall configuration. The instructions given have been verified on Ubuntu Lucid running on 32-bit (i386) and 64-bit (amd64) architecture -- but they should work on any modern Linux desktop.&lt;p&gt;&lt;a href="http://www.teamviewer.com/"&gt;TeamViewer&lt;/a&gt; is an excellent cross-platform application which provides desktop sharing, file transfer, chat and video conferencing, and it's free for personal use. Its use is straightforward. Installers for Linux, Mac OS X, Windows and iPhone are downloadable &lt;a href="http://www.teamviewer.com/download/"&gt;here&lt;/a&gt;.&lt;p&gt;If you don't want to install anything, you can try the &lt;i&gt;QuickSupport&lt;/i&gt; edition of TeamViewer on Windows and the Mac OS X. (Get it from the same download page.) The QuickSupport edition doesn't let the user initiate a connection (to become a client), but it listens as a server waiting for connections.&lt;p&gt;As of now, there is no official Linux QuickSupport edition of TeamViewer, so I've created one; it downlads and starts the regular TeamViewer for Linux application, without installing it. To use it on a vanilla Ubuntu Lucid box, just press Alt-&lt;F2&gt;, and type (or copy-paste) the following command, and press &lt;i&gt;Enter&lt;/i&gt;:&lt;pre&gt;bash -c 'wget -O- goo.gl/k9imm | bash'&lt;/pre&gt;&lt;p&gt;Please note that the &lt;code&gt;O&lt;/code&gt; between the dashes is a capital O. All other characters are lowercase.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-4353381901310278645?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/4353381901310278645/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=4353381901310278645' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/4353381901310278645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/4353381901310278645'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/11/remote-desktop-sharing-for-linux_15.html' title='Remote desktop sharing for Linux without software installation and firewall configuration'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-4460192522687588488</id><published>2010-11-15T16:52:00.000+01:00</published><updated>2010-11-15T16:52:44.269+01:00</updated><title type='text'>Remote desktop sharing for Linux without software installation and firewall configuration</title><content type='html'>&lt;p&gt;This blog post explains how to share two desktops (screen, keyboard and mouse) without software installation (on Linux) and firewall configuration. The instructions given have been verified on Ubuntu Lucid running on 32-bit (i386) and 64-bit (amd64) architecture -- but they should work on any modern Linux desktop.&lt;p&gt;&lt;a href="http://www.teamviewer.com/"&gt;TeamViewer&lt;/a&gt; is an excellent cross-platform application which provides desktop sharing, file transfer, chat and video conferencing, and it's free for personal use. Its use is straightforward. Installers for Linux, Mac OS X, Windows and iPhone are downloadable &lt;a href="http://www.teamviewer.com/download/"&gt;here&lt;/a&gt;.&lt;p&gt;If you don't want to install anything, you can try the &lt;i&gt;QuickSupport&lt;/i&gt; edition of TeamViewer on Windows and the Mac OS X. (Get it from the same download page.) The QuickSupport edition doesn't let the user initiate a connection (to become a client), but it listens as a server waiting for connections.&lt;p&gt;As of now, there is no official Linux QuickSupport edition of TeamViewer, so I've created one; it downlads and starts the regular TeamViewer for Linux application, without installing it. To use it on a vanilla Ubuntu Lucid box, just press Alt-&lt;F2&gt;, and type (or copy-paste) the following command, and press &lt;i&gt;Enter&lt;/i&gt;:&lt;pre&gt;bash -c 'wget -O- goo.gl/k9imm | bash'&lt;/pre&gt;&lt;p&gt;Please note that the &lt;code&gt;O&lt;/code&gt; between the dashes is a capital O. All other characters are lowercase.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-4460192522687588488?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/4460192522687588488/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=4460192522687588488' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/4460192522687588488'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/4460192522687588488'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/11/remote-desktop-sharing-for-linux.html' title='Remote desktop sharing for Linux without software installation and firewall configuration'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-3977535200014751442</id><published>2010-11-10T12:55:00.002+01:00</published><updated>2011-12-19T18:46:12.227+01:00</updated><title type='text'>How to disable PulseAudio on Ubuntu Lucid and Oneiric without uninstalling it</title><content type='html'>&lt;p&gt;This blog post explains how to disable PulseAudio on Ubuntu Lucid without uninstalling it. The solution described here may work on other Linux distributions as well. Please note that you may lose volume controls integrated to GNOME (e.g. the volume control hotkeys), and you'll have to adjust the volume with &lt;i&gt;alsamixer&lt;/i&gt; or it's GNOME equivalent, &lt;i&gt;gnome-alsamixer&lt;/i&gt;.&lt;p&gt;Install the volume control programs:&lt;pre&gt;$ sudo apt-get install alsa-utils gnome-alsamixer&lt;br /&gt;$ sudo apt-get remove gamix  # Applications / Sound &amp;amp; Video / ALSA Mixer&lt;/pre&gt;&lt;p&gt;Stop the PulseAudio server (&lt;i&gt;pulseaudio&lt;/i&gt;) and remove temporary files:&lt;pre&gt;$ pkill -STOP '^pulseaudio$'&lt;br /&gt;$ rm -rf ~/.pulse&lt;/pre&gt;&lt;p&gt;Make sure all application attempts to connect to the PulseAudio server and/or to start a new PulseAudio server will fail:&lt;pre&gt;$ mkdir -p ~/.pulse&lt;br /&gt;$ (if grep -q \=10 /etc/lsb-release; then&lt;br /&gt;     echo 'default-server = 0.0.0.1'&lt;br /&gt;   else&lt;br /&gt;     echo 'daemon-binary = /dev/null/no-daemon'&lt;br /&gt;   fi&lt;br /&gt;   echo 'autospawn = no') &gt;~/.pulse/client.conf&lt;/pre&gt;&lt;p&gt;Kill the PulseAudio server:&lt;pre&gt;$ pkill -KILL '^pulseaudio$'&lt;/pre&gt;&lt;p&gt;Optionally, to disable PulseAudio for all users, add the following lines to &lt;code&gt;/etc/pulse/client.conf&lt;/code&gt; for Ubuntu Lucid:&lt;pre&gt;default-server = 0.0.0.1&lt;br /&gt;autospawn = no&lt;/pre&gt;The corresponding lines for Ubuntu Oneiric are:&lt;pre&gt;daemon-binary = /dev/null/no-daemon&lt;br /&gt;autospawn = no&lt;/pre&gt;&lt;p&gt;Restart your web browsers (for the Flash Player) and your Skype, and possibly other applications which use sound. To do so, it's best to log out and log in again.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-3977535200014751442?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/3977535200014751442/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=3977535200014751442' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/3977535200014751442'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/3977535200014751442'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/11/how-to-disable-pulseaudio-on-ubuntu.html' title='How to disable PulseAudio on Ubuntu Lucid and Oneiric without uninstalling it'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-1176898836915432321</id><published>2010-11-03T18:30:00.000+01:00</published><updated>2010-11-03T18:30:37.064+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='panel'/><category scheme='http://www.blogger.com/atom/ns#' term='gtk'/><category scheme='http://www.blogger.com/atom/ns#' term='delay'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='menu'/><category scheme='http://www.blogger.com/atom/ns#' term='gnome'/><title type='text'>How to get rid of the GNOME panel menu delay on Ubuntu Lucid</title><content type='html'>&lt;p&gt;This blog post gives instructions how to get rid of the GNOME panel menu delay, i.e. the small delay one experiences when moving the mouse pointer over the &lt;i&gt;System&lt;/i&gt; menu, and the submenus  like &lt;i&gt;Preferences&lt;/i&gt; and &lt;i&gt;Administration&lt;/i&gt; don't open immediately. The solution shown has been tested on Ubuntu Lucid, but it might work on other systems as well.&lt;p&gt;Run the following command to configure newly started applications to omit the delay:&lt;pre&gt;$ echo "gtk-menu-popup-delay = 0" &gt;&gt; ~/.gtkrc-2.0&lt;/pre&gt;&lt;p&gt;Run this command to restart the GNOME panel currently running:&lt;pre&gt;$ killall gnome-panel&lt;/pre&gt;If you are interested speeding up the loading of icons, see more information on &lt;a href="http://www.ubuntugeek.com/how-to-make-gnome-menus-faster-in-ubuntu.html"&gt;http://www.ubuntugeek.com/how-to-make-gnome-menus-faster-in-ubuntu.html&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-1176898836915432321?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/1176898836915432321/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=1176898836915432321' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1176898836915432321'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1176898836915432321'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/11/how-to-get-rid-of-gnome-panel-menu.html' title='How to get rid of the GNOME panel menu delay on Ubuntu Lucid'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-5579546843159040262</id><published>2010-10-30T22:23:00.001+02:00</published><updated>2011-01-22T10:12:52.694+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='planet-python'/><title type='text'>pysshsftp: proof-of-concept SFTP client for Unix which uses the OpenSSH ssh(1) command-line tool</title><content type='html'>&lt;p&gt;This blog post is an announcement for &lt;i&gt;&lt;a href="http://code.google.com/p/pts-mini-gpl/source/browse/#svn/trunk/pysshsftp"&gt;pysshsftp&lt;/a&gt;&lt;/i&gt;, a proof-of-concept, educational SFTP client for Unix, which usesthe OpenSSH ssh(1) command-line tool (for establishing the secureconnection), but it doesn't use the sftp(1) command-line tool (so it cane.g. upload files without truncating them first).&lt;p&gt;Only very little part of the SFTP protocol has been implemented so far(initialization, uploading, and stat()ting files). The SFTP protocol wasreverse-engineered from sftp-client.c in the OpenSSH 5.1 source code.&lt;p&gt;The motivation behind writing &lt;i&gt;pysshsftp&lt;/i&gt; was to have an SFTP client which&lt;ul&gt;&lt;li&gt;supports uploading files without truncating them (the OpenSSH sftp(1) always truncates the file before uplading data bytes);&lt;li&gt;can be easily scripted from Python;&lt;li&gt;uses the OpenSSH(1) command-line tool for establishing the secure connection (other Python libraries like &lt;a href="http://pypi.python.org/pypi/pysftp/"&gt;pysftp&lt;/a&gt; and &lt;a href="http://pypi.python.org/pypi/paramiko/"&gt;paramiko&lt;/a&gt; can't use the user's public key configuration properly by default: they don't support passphrase reading for passphrase-protected keys, they don't support reading keys from &lt;i&gt;ssh-agent&lt;/i&gt;, and they don't support reading &lt;code&gt;~/.ssh/id_rsa&lt;/code&gt; and &lt;code&gt;~/.ssh/id_dsa&lt;/code&gt; exactly the same way as OpenSSH uses them).&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-5579546843159040262?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/5579546843159040262/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=5579546843159040262' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/5579546843159040262'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/5579546843159040262'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/10/pysshsftp-proof-of-concept-sftp-client.html' title='pysshsftp: proof-of-concept SFTP client for Unix which uses the OpenSSH ssh(1) command-line tool'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-2329682449906094802</id><published>2010-10-29T13:11:00.002+02:00</published><updated>2011-01-22T10:12:44.837+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='program'/><category scheme='http://www.blogger.com/atom/ns#' term='multilingual'/><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='prolog'/><category scheme='http://www.blogger.com/atom/ns#' term='source code'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='planet-python'/><title type='text'>Multilingual programs in Haskell, Prolog, Perl and Python</title><content type='html'>&lt;p&gt;This blog posts shows program source codes that work in multiple languages (including Haskell, Prolog, Perl, Perl and Python.&lt;p&gt;Here is a program which works in Haskell, Prolog and Perl:&lt;pre&gt;$ cat &gt;m1.prg &lt;&lt;'END'&lt;br /&gt;foo( {-1/*_} ) if!'*/%'; print "Hello, Perl!\n" if&lt;&lt;'-- */'&lt;br /&gt;}). :- write('Hello, Prolog!'), nl, halt.&lt;br /&gt;/* -} x) = x&lt;br /&gt;main = putStrLn "Hello, Haskell!"&lt;br /&gt;-- */&lt;br /&gt;END&lt;br /&gt;$ perl m1.prg&lt;br /&gt;Hello, Perl!&lt;br /&gt;$ swipl -f m1.prg&lt;br /&gt;Hello, Prolog!&lt;br /&gt;$ cp m1.prg m1.hs&lt;br /&gt;$ ghc m1.hs -o m1&lt;br /&gt;$ ./m1&lt;br /&gt;Hello, Haskell!&lt;/pre&gt;&lt;p&gt;Here is a program which works in Haskell, Prolog and Python:&lt;pre&gt;$ cat &gt;m2.prg &lt;&lt;'END'&lt;br /&gt;len( {-1%2:3} ); print "Hello, Python!"; """&lt;br /&gt;}). :- write('Hello, Prolog!'), nl, halt.&lt;br /&gt;/* -} x) = x&lt;br /&gt;main = putStrLn "Hello, Haskell!"&lt;br /&gt;-- """ # */&lt;br /&gt;END&lt;br /&gt;$ python m2.prg&lt;br /&gt;Hello, Python!&lt;br /&gt;$ swipl -f m2.prg&lt;br /&gt;Hello, Prolog!&lt;br /&gt;$ cp m2.prg m2.hs&lt;br /&gt;$ ghc m2.hs -o m2&lt;br /&gt;$ ./m2&lt;br /&gt;Hello, Haskell!&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-2329682449906094802?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/2329682449906094802/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=2329682449906094802' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2329682449906094802'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2329682449906094802'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/10/multilingual-programs-in-haskell-prolog.html' title='Multilingual programs in Haskell, Prolog, Perl and Python'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-3011697200870735859</id><published>2010-10-26T21:38:00.002+02:00</published><updated>2010-10-26T21:41:34.525+02:00</updated><title type='text'>How to upload a video to Picasa from Linux, Mac OS X and Windows</title><content type='html'>&lt;p&gt;This blog post explains how to upload a video to Google Picasa from Linux, Mac OS X and Windows.&lt;p&gt;It is not possible to upload a video to Picasa Web Albums from your web browser. (However, it is possible to upload images this way.)&lt;p&gt;Please note that the video you upload will be transcoded, most probably to lower quality than the original, and the original video file won't be available for download or watching on Picasa Web Albums.&lt;p&gt;On Windows, use the latest &lt;i&gt;Picasa&lt;/i&gt; desktop application (&lt;a href="http://picasa.google.com/index.html##"&gt;[download]&lt;/a&gt;). Version 3.8 or newer works. Alternatively, you can use GoogleCL (&lt;a href="http://code.google.com/p/googlecl/"&gt;[project page]&lt;/a&gt;).&lt;p&gt;On Mac OS X, use the &lt;i&gt;Picasa Web Albums Uploader&lt;/i&gt;. (&lt;a href="http://picasa.google.com/mac_tools.html"&gt;[download]&lt;/a&gt;)&lt;p&gt;On Linux, use the &lt;i&gt;Google command line tools (GoogleCL)&lt;/i&gt;. &lt;a href="http://code.google.com/p/googlecl/"&gt;[project page]&lt;/a&gt; Example command to upload photos and videos:&lt;pre&gt;$ google picasa create --title album_name&lt;br /&gt;$ google picasa post   --title album_name ~/Photos_and_videos/*&lt;/pre&gt;&lt;p&gt;It might take a few minutes for the video to become transcoded and made available. In the meanwhile, you'll see this image on picasaweb instead:&lt;p&gt;&lt;img src="http://2.bp.blogspot.com/_KsQ12RqjJ4w/TMcub3thc0I/AAAAAAAABTE/J7zPnppIgXI/s1600/video_pending.png"&gt;&lt;p&gt;On Linux, you may have to install the newest &lt;i&gt;googlecl&lt;/i&gt; (0.9.11 works) and the newest &lt;i&gt;python-gdata&lt;/i&gt; (2.0.12 or newer works), and remove your &lt;pre&gt;~/.googlecl&lt;/pre&gt; directory to make it work.&lt;p&gt;Installation instructions for Ubuntu Lucid, before you can run the &lt;pre&gt;google&lt;/pre&gt; command above:&lt;pre&gt;$ sudo apt-get install python-setuptools&lt;br /&gt;$ sudo easy_install gdata&lt;br /&gt;$ sudo easy_install http://googlecl.googlecode.com/files/googlecl-0.9.11.tar.gz&lt;br /&gt;$ mv -f ~/.googlecl ~/.googlecl.old&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-3011697200870735859?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/3011697200870735859/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=3011697200870735859' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/3011697200870735859'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/3011697200870735859'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/10/how-to-upload-video-to-picasa-from.html' title='How to upload a video to Picasa from Linux, Mac OS X and Windows'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_KsQ12RqjJ4w/TMcub3thc0I/AAAAAAAABTE/J7zPnppIgXI/s72-c/video_pending.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-2657414623601579207</id><published>2010-09-23T14:11:00.001+02:00</published><updated>2010-09-23T14:18:39.154+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='battery pack'/><category scheme='http://www.blogger.com/atom/ns#' term='battery'/><category scheme='http://www.blogger.com/atom/ns#' term='lumix'/><category scheme='http://www.blogger.com/atom/ns#' term='digital camera'/><category scheme='http://www.blogger.com/atom/ns#' term='charger'/><category scheme='http://www.blogger.com/atom/ns#' term='model'/><category scheme='http://www.blogger.com/atom/ns#' term='panasonic'/><category scheme='http://www.blogger.com/atom/ns#' term='li-ion'/><title type='text'>Panasonic Lumix DMC-FS30 battery information</title><content type='html'>&lt;p&gt;This blog post contains information about some digital cameras and their corresponding batteries and battery chargers.&lt;p&gt;The Panasonic Lumix DMC-FS30, FMC-FS11, DMC-FS10 and DMC-FS9 digital camera comes with the battery pack model CGA-S/106C, which is a 3.6V, 740 mAh, 2.7Wh Li-ion battery. The corresponding battery charger is the Panasonic DE-A60 battery charger.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-2657414623601579207?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/2657414623601579207/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=2657414623601579207' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2657414623601579207'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2657414623601579207'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/09/panasonic-lumix-dmc-fs30-battery.html' title='Panasonic Lumix DMC-FS30 battery information'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-9049506252024322419</id><published>2010-08-29T22:30:00.002+02:00</published><updated>2010-08-29T22:35:13.387+02:00</updated><title type='text'>How to emulate a WebSocket client in JavaScript using the Java plugin</title><content type='html'>&lt;p&gt;This blog post shows a proof of concept implementation which can be extended to emulate a &lt;a href="http://en.wikipedia.org/wiki/WebSockets"&gt;WebSocket&lt;/a&gt; client in JavaScript in browsers where WebSocket support is not available, but there is a working Java plugin installed.&lt;p&gt;The motivation behind this blog post is to design drop-in replacements for WebSocket for older browsers (e.g. Internet Explorer 9 and earlier, Opera 9 and earlier, Safari 4 and earlier, Firefox 3.7 and earlier), where WebSocket client support is not available, but some browser plugin (like Java, Flash or Silverlight) could be used to emulate it. This blog post is a proof-of-concept demonstrating how the Java plugin can be used for such an emulation.&lt;p&gt;The trick is to use the &lt;code&gt;java&lt;/code&gt; symbol exported to JavaScript. Here is the relevant HTML page with JavaScript code, which implements a simple, proof-of-concept HTTP client in JavaScript using Java:&lt;pre&gt;&amp;lt;html&gt;&amp;lt;head&gt;&lt;br /&gt;&amp;lt;title&gt;Java WebSocket proof-of-concept test&amp;lt;/title&gt;&lt;br /&gt;&amp;lt;script type="text/javascript"&gt;&lt;br /&gt;function output(str) {&lt;br /&gt;  var output = document.getElementById("output")&lt;br /&gt;  var text = document.createTextNode(str)&lt;br /&gt;  var br = document.createElement('br')&lt;br /&gt;  output.insertBefore(br, null)  &lt;br /&gt;  output.insertBefore(text, null)&lt;br /&gt;}&lt;br /&gt;function init() {&lt;br /&gt;  output("find java")&lt;br /&gt;  java.lang&lt;br /&gt;  var hostItems = window.location.host.split(':')&lt;br /&gt;  var hostName = hostItems[0]&lt;br /&gt;  var port = 80&lt;br /&gt;  if (hostItems.length &gt; 1) {&lt;br /&gt;    port = parseInt(hostItems[1], 10)&lt;br /&gt;    if (port == 443 &amp;&amp; window.location.protocol == 'https:')&lt;br /&gt;      port = 80&lt;br /&gt;  }&lt;br /&gt;  output("connecting to host " + hostName + ", port " + port)&lt;br /&gt;  var socket = new java.net.Socket(hostName, port)&lt;br /&gt;  output("connected")&lt;br /&gt;  var osw = new java.io.OutputStreamWriter(socket.getOutputStream(), "UTF-8")&lt;br /&gt;  var isr = new java.io.InputStreamReader(socket.getInputStream(), "UTF-8")&lt;br /&gt;  var bis = new java.io.BufferedReader(isr)   &lt;br /&gt;  output("sending request (GET /answer.html)")  &lt;br /&gt;  osw.write("GET /answer.html HTTP/1.0\r\n\r\n")&lt;br /&gt;  osw.flush()&lt;br /&gt;  output("reading response")&lt;br /&gt;  // SUXX: This blocks the whole browser (Firefox) until the response is&lt;br /&gt;  // ready.&lt;br /&gt;  var line&lt;br /&gt;  while (true) {&lt;br /&gt;    line = bis.readLine()    &lt;br /&gt;    if (line == null) break&lt;br /&gt;    if (line == '' || line == '\r') break&lt;br /&gt;    output("got header line: " + line)&lt;br /&gt;  }&lt;br /&gt;  output("done with header")&lt;br /&gt;  if (line != null) {&lt;br /&gt;    while (true) {&lt;br /&gt;      line = bis.readLine()  &lt;br /&gt;      if (line == null) break&lt;br /&gt;      output("got body line: " + line)&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  output("done with body")&lt;br /&gt;  output("closing")&lt;br /&gt;  isr.close()&lt;br /&gt;  osw.close()&lt;br /&gt;  socket.close()&lt;br /&gt;  output("done")&lt;br /&gt;}&lt;br /&gt;&amp;lt;/script&gt;&lt;br /&gt;&amp;lt;/head&gt;&amp;lt;body onload="init()"&gt;&lt;br /&gt;&amp;lt;div id="output" style="border:1px solid black;padding: 2px"&gt;Welcome!&amp;lt;/div&gt;&lt;br /&gt;&amp;lt;/body&gt;&amp;lt;/html&gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The code above could be easily upgraded to use the WebSocket protocol.&lt;p&gt;Please note that the implementation above has a show-stopper bug: it locks the whole browser UI (all functionality in all tabs, in Firefox 3.6) until the server returns the HTTP response. It might be possible to solve it by using &lt;code&gt;java.nio.SocketChannel&lt;/code&gt;, but we haven't investigated that yet.&lt;p&gt;Please note that it is possible to do WebSocket emulation with Flash instead of Java, see &lt;a href="http://github.com/gimite/web-socket-js/"&gt;web-socket-js&lt;/a&gt; for the client-side code (JavaScript and Flash) and &lt;a href="http://github.com/gimite/web-socket-ruby/"&gt;web-socket-ruby&lt;/a&gt; for the server-side code.&lt;p&gt;Please note that we haven't investigated if it is possible to do WebSocket emulation with Silverlight instead of Java.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-9049506252024322419?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/9049506252024322419/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=9049506252024322419' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/9049506252024322419'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/9049506252024322419'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/08/how-to-emulate-websocket-client-in.html' title='How to emulate a WebSocket client in JavaScript using the Java plugin'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-3457852885914576427</id><published>2010-08-11T16:18:00.001+02:00</published><updated>2011-01-22T10:12:22.355+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='planet-python'/><title type='text'>How to try Stackless Python on Linux without installing it?</title><content type='html'>&lt;p&gt;This blog post gives instructions on trying Stackless Python without installing it on Linux systems (32-bit and 64-bit).&lt;p&gt;Use the Stackless version of the &lt;a href="http://code.google.com/p/pts-mini-gpl/wiki/StaticPython"&gt;StaticPython&lt;/a&gt; binary, which is a portable version of Stackless Python 2.7 for Linux systems. It is linked statically, with most standard Python modules and C extensions included in the executable binary, so no installation is required. Here is how to try it:&lt;pre&gt;$ wget -O stackless2.7-static \&lt;br /&gt;  http://pts-mini-gpl.googlecode.com/files/stackless2.7-static&lt;br /&gt;$ chmod +x stackless2.7-static&lt;br /&gt;$ ./stackless2.7-static&lt;br /&gt;Python 2.7 Stackless 3.1b3 060516 (release27-maint, Aug 11 2010, 13:55:35) &lt;br /&gt;[GCC 4.1.2] on linux2&lt;br /&gt;Type "help", "copyright", "credits" or "license" for more information.&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; import stackless&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/pre&gt;&lt;p&gt;See more information about features, suggested uses and limitations on the &lt;a href="http://code.google.com/p/pts-mini-gpl/wiki/StaticPython"&gt;StaticPython home page&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-3457852885914576427?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/3457852885914576427/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=3457852885914576427' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/3457852885914576427'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/3457852885914576427'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/08/how-to-try-stackless-python-on-linux.html' title='How to try Stackless Python on Linux without installing it?'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-1759236670336130604</id><published>2010-08-11T15:13:00.001+02:00</published><updated>2011-01-22T10:12:11.950+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='planet-python'/><title type='text'>StaticPython released</title><content type='html'>&lt;p&gt;This blog post is an announcement of the &lt;a href="http://code.google.com/p/pts-mini-gpl/wiki/StaticPython"&gt;StaticPython&lt;/a&gt; software distribution and its first release.&lt;h3&gt;What is StaticPython?&lt;/h3&gt;&lt;p&gt;StaticPython is a statically linked version of the Python 2.x (currently 2.7) interpreter and its standard modules for 32-bit Linux systems (i686, i386). It is distributed as a single, statically linked 32-bit Linux executable binary, which contains the Python scripting engine, the interactive interpreter with command editing (readline), the Python debugger (pdb), most standard Python modules (including pure Python modules and C extensions), coroutine support using greenlet and multithreading support. The binary contains both the pure Python modules and the C extensions, so no additional .py or .so files are needed to run it. It also works in a chroot environment. The binary uses uClibc, so it supports username lookups and DNS lookups as well (without NSS).&lt;h3&gt;Download and run&lt;/h3&gt;&lt;p&gt;Download the &lt;a href="http://pts-mini-gpl.googlecode.com/files/python2.7-static"&gt;StaticPython 2.7 executable binary&lt;/a&gt; for version 0.1.&lt;p&gt;Here is how to use it:&lt;pre&gt;$ wget -O python2.7-static \&lt;br /&gt;  http://pts-mini-gpl.googlecode.com/files/python2.7-static&lt;br /&gt;$ chmod +x python2.7-static&lt;br /&gt;$ ./python2.7-static&lt;br /&gt;Python 2.7 (r27:82500, Aug 11 2010, 10:51:33) &lt;br /&gt;[GCC 4.1.2] on linux2&lt;br /&gt;Type "help", "copyright", "credits" or "license" for more information.&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/pre&gt;&lt;h3&gt;For what purpose is StaticPython useful?&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;for running Python scripts in chroot and other restricted environments (e.g. for running untrusted standard Python code)&lt;li&gt;for running CGI scripts on some web hosting providers where Python is not preinstalled (this is slow)&lt;li&gt;for trying the newest Python and running scripts on a very old Linux system or on a system where package installation is not possible or cumbersome&lt;li&gt;for deploying and running Tornado, Eventlet or Twisted-based networking applications on a machine without a working Python installation (please note that the framework itself has also to be deployed)&lt;/ul&gt;&lt;h3&gt;When isn't StaticPython recommended?&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;if dependencies need Python package installation (e.g. distutils, setuptools, setup.py, Pyrex, Cython) -- distutils is not included, there is no site-packages directory, loading .so files is not supported&lt;li&gt;if dependencies are or need shared libraries (.so files) -- StaticPython doesn't support loading .so files, not even with the dl or ctypes modules&lt;li&gt;if startup and module import has to be fast -- since StaticPython stores .py files (no .pyc) in a ZIP file at the end of the binary&lt;li&gt;for GUI programming -- no GUI or graphics library is included, loading .so files is not supported&lt;/ul&gt;&lt;h3&gt;How to extend, customize or recompile StaticPython?&lt;/h3&gt;Compiling python2.7-static was a one-off manual process. Automating this process has not been implemented yet. Please contact the author if you need this.&lt;h3&gt;Feature details&lt;/h3&gt;&lt;h4&gt;Features provided&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;command-line editing with the built-in readline module&lt;li&gt;almost all standard Python 2.7 modules built-in&lt;li&gt;almost all standard C extensions built-in: _bisect, _codecs, _codecs_cn, _codecs_hk, _codecs_iso2022, _codecs_jp, _codecs_kr, _codecs_tw, _collections, _csv, _curses, _elementtree, _functools, _heapq, _hotshot, _io, _json, _locale, _lsprof, _md5, _multibytecodec, _multiprocessing, _random, _sha, _sha256, _sha512, _socket, _sockobject, _sqlite3 (added 1004307 bytes to the executable binary size), _sre, _struct, _symtable, _weakref, array, audioop, binascii, bz2, cPickle, cStringIO, cmath, crypt, datetime, errno, fcntl, fpectl, future_builtins, gc, grp, imageop, itertools, math, mmap, operator, parser, posix, pwd, pyexpat, readline, resource, select, signal, spwd, strop, syslog, termios, thread, time, timing, zipimport, zlib&lt;li&gt;greenlet integrated for coroutine support&lt;li&gt;multithreading (using thread and threading as usual)&lt;li&gt;line editing even without a terminfo definition or inputrc file(useful in chroot, provided by libreadline/libncurses by default)&lt;li&gt;the usual help, license used in interactive mode&lt;/ul&gt;&lt;h4&gt;Executable binary layout&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Python 2.7 (r27:82500) on Linux i386, statically linkedcompiled and linked with uClibc, so it supports username lookups and DNS lookups as well (without NSS).&lt;li&gt;pure Python and C extensions integrated to a single, statically linked, i386 (i686) Linux executable&lt;li&gt;compiled with uClibc so it can do DNS lookups without /lib/libss_*so*&lt;li&gt;can run from any directory, even in chroot containing only the binary, even in interactive mode, even without /proc mounted&lt;/ul&gt;&lt;h4&gt;Features missing&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;missing: loading .so files (C shared libraries, Python C extensions)&lt;li&gt;missing: the ctypes module and the dl module (since no .so file loading support)&lt;li&gt;missing: the distutils module, custom extension installation&lt;li&gt;missing: !OpenSSL, SSL sockets&lt;li&gt;missing: IPv6 support&lt;li&gt;missing: GUI bindings (tkinter, GTK, Qt etc.)&lt;li&gt;missing: Stackless Python&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-1759236670336130604?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/1759236670336130604/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=1759236670336130604' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1759236670336130604'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1759236670336130604'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/08/staticpython-released.html' title='StaticPython released'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-9133988882863956701</id><published>2010-08-09T22:21:00.008+02:00</published><updated>2011-11-13T18:04:22.077+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='mysqld'/><category scheme='http://www.blogger.com/atom/ns#' term='mariadb'/><title type='text'>How to try the latest MariaDB on Linux</title><content type='html'>&lt;p&gt;This blog post explains how to download and start the bleeding edge MariaDB on a fairly recent 32-bit or 64-bit Linux system, for trial and development, the most straightforward way, without overwriting an existing MySQL installation or its data.&lt;p&gt;MariaDB is an improved, backward compatible, drop-in replacement of the MySQL Database Server, by Michael "Monty" Widenius, the original author of MySQL.&lt;p&gt;Please note that parts of this blog post are obsolete. See also the &lt;a href="http://ptspts.blogspot.com/2011/11/announcing-portable-mariadb-small.html"&gt;new blog post&lt;/a&gt;.&lt;p&gt;The simplest download and startup instructions for MariaDB 5.2.1 for 32-bit (i386, i686) Linux systems is the following:&lt;pre&gt;# Stop any MySQL server currently running.&lt;br /&gt;$ wget -O /tmp/mariadb-compact.tbz2 \&lt;br /&gt;  http://pts-mini-gpl.googlecode.com/files/mariadb-compact-5.2.1-beta-linux-i386.tbz2&lt;br /&gt;$ cd /tmp&lt;br /&gt;$ tar xjvf mariadb-compact.tbz2&lt;br /&gt;$ cd mariadb-compact&lt;br /&gt;$ ./bin/mysqld --datadir=$PWD/data --pid-file=$PWD/mysqld.pid \&lt;br /&gt;  --socket=$PWD/mysqld.sock --language=$PWD/share/mysql/english \&lt;br /&gt;  --log-error=/proc/self/stderr&lt;br /&gt;...&lt;/pre&gt;&lt;p&gt;To stop the server, press Ctrl-&lt;i&gt;Backslash&lt;/i&gt;, &lt;i&gt;Enter&lt;/i&gt; in the window &lt;code&gt;mysqld_safe&lt;/code&gt; is running, and wait 15 seconds for the process to exit.&lt;p&gt;To connect to the server, install the MySQL client. (e.g. with &lt;code&gt;$ sudo apt-get install mysql-client&lt;/code&gt; on an Ubuntu system), and then run&lt;pre&gt;$ mysql --socket=/tmp/mariadb-compact/mysqld.sock --user=root --database=test&lt;/pre&gt;&lt;p&gt;or&lt;/p&gt;&lt;pre&gt;$ mysql --host=127.0.0.1 --user=root --database=test&lt;/pre&gt;&lt;p&gt;to connect. Please note that &lt;i&gt;mariadb-compact&lt;/i&gt; comes with insecure default settings: it lets anyone connect as user &lt;i&gt;root&lt;/i&gt; (on TCP 127.0.0.1:3306 (but not on other IP addresses) and on the Unix socket as well) without a password. Please use the appropriate &lt;i&gt;mysqladmin&lt;/i&gt; commands (or modify the tables &lt;i&gt;mysql.user&lt;/i&gt;, &lt;i&gt;mysql.host&lt;/i&gt; and &lt;i&gt;mysql.db&lt;/i&gt; directly) to set up access restrictions. use the &lt;i&gt;--skip-networking&lt;/i&gt; flag of &lt;i&gt;mysqld&lt;/i&gt; to prevent it from listening on TCP ports (not even 127.0.0.1:3306).&lt;p&gt;FYI Here is how &lt;code&gt;mariadb-compact.tbz2&lt;/code&gt; was created from the official MariaDB Linux binaries. The official download was located on &lt;a href="http://askmonty.org/wiki/MariaDB:Download"&gt;http://askmonty.org/wiki/MariaDB:Download&lt;/a&gt; &lt;a href="http://askmonty.org/wiki/MariaDB:Download:MariaDB_5.2.1-beta"&gt;http://askmonty.org/wiki/MariaDB:Download:MariaDB_5.2.1-beta&lt;/a&gt;, and then the following commands were executed:&lt;pre&gt;$ wget -O /tmp/mariadb-5.2.1-beta-Linux-i686.tar.gz \&lt;br /&gt;  http://ftp.rediris.es/mirror/MariaDB/mariadb-5.2.1-beta/\&lt;br /&gt;  kvm-bintar-hardy-x86/mariadb-5.2.1-beta-Linux-i686.tar.gz&lt;br /&gt;$ mkdir -p /tmp/mariadb-preinst&lt;br /&gt;$ cd /tmp/mariadb-preinst&lt;br /&gt;$ tar xzvf /tmp/mariadb-5.2.1-beta-Linux-i686.tar.gz mariadb-5.2.1-beta-Linux-i686/\&lt;br /&gt;  {bin/mysqld{,_safe},bin/my_print_defaults,scripts/mysql_install_db,\&lt;br /&gt;  share/mysql/english/errmsg.sys,share/fill_help_tables.sql,\&lt;br /&gt;  share/mysql_fix_privilege_tables.sql,share/mysql_system_tables.sql,\&lt;br /&gt;  share/mysql_system_tables_data.sql,share/mysql_test_data_timezone.sql}&lt;br /&gt;$ cd mariadb-5.2.1-beta-Linux-i686&lt;br /&gt;$ strip -s bin/mysqld&lt;br /&gt;$ ./scripts/mysql_install_db --basedir="$PWD" --force --datadir="$PWD"/data&lt;br /&gt;$ rm -rf scripts&lt;br /&gt;$ rm -f share/*.sql&lt;br /&gt;$ cd ..&lt;br /&gt;$ mv mariadb-5.2.1-beta-Linux-i686 mariadb-compact&lt;br /&gt;$ tar cjvf /tmp/mariadb-compact.tbz2 mariadb-compact&lt;br /&gt;$ rm -rf /tmp/mariadb-5.2.1-beta-Linux-i686.tar.gz&lt;br /&gt;$ rm -rf /tmp/mariadb-preinst&lt;br /&gt;$ ls -l /tmp/mariadb-compact.tbz2 &lt;br /&gt;-rw-r--r-- 1 pts pts 4194393 Aug  8 18:10 /tmp/mariadb-compact.tbz2&lt;/pre&gt;&lt;p&gt;The script &lt;i&gt;mysql_install_db&lt;/i&gt; creates the initial databases and tables (e.g. the &lt;i&gt;mysql.user&lt;/i&gt; table used for authentication) in the &lt;code&gt;data&lt;/code&gt; directory.&lt;p&gt;All the other commands above just extract the absolute minimum necessary files from the official binary distribution, strip the binaries, and create a small &lt;code&gt;.tbz2&lt;/code&gt; archive.&lt;p&gt;Please note that the binaries in the official binary distributions are dynamically linked:&lt;pre&gt;$ ldd bin/mysqld&lt;br /&gt;        linux-gate.so.1 =&gt;  (0xb7727000)&lt;br /&gt;        libnsl.so.1 =&gt; /lib/tls/i686/cmov/libnsl.so.1 (0xb76f9000)&lt;br /&gt;        librt.so.1 =&gt; /lib/tls/i686/cmov/librt.so.1 (0xb76f0000)&lt;br /&gt;        libpthread.so.0 =&gt; /lib/tls/i686/cmov/libpthread.so.0 (0xb76d6000)&lt;br /&gt;        libwrap.so.0 =&gt; /lib/libwrap.so.0 (0xb76cd000)&lt;br /&gt;        libdl.so.2 =&gt; /lib/tls/i686/cmov/libdl.so.2 (0xb76c9000)&lt;br /&gt;        libresolv.so.2 =&gt; /lib/tls/i686/cmov/libresolv.so.2 (0xb76b5000)&lt;br /&gt;        libcrypt.so.1 =&gt; /lib/tls/i686/cmov/libcrypt.so.1 (0xb7683000)&lt;br /&gt;        libstdc++.so.6 =&gt; /usr/lib/libstdc++.so.6 (0xb7590000)&lt;br /&gt;        libm.so.6 =&gt; /lib/tls/i686/cmov/libm.so.6 (0xb756a000)&lt;br /&gt;        libc.so.6 =&gt; /lib/tls/i686/cmov/libc.so.6 (0xb7425000)&lt;br /&gt;        /lib/ld-linux.so.2 (0xb7728000)&lt;br /&gt;        libgcc_s.so.1 =&gt; /lib/libgcc_s.so.1 (0xb7407000)&lt;/pre&gt;&lt;p&gt;It would be straightforward to create the 64-bit version of &lt;code&gt;mariadb-compact.tbz2&lt;/code&gt;, by starting from a different official binary distribution (&lt;a href="http://ftp.rediris.es/mirror/MariaDB/mariadb-5.2.1-beta/kvm-bintar-hardy-amd64/mariadb-5.2.1-beta-Linux-x86_64.tar.gz"&gt;http://ftp.rediris.es/mirror/MariaDB/mariadb-5.2.1-beta/kvm-bintar-hardy-amd64/mariadb-5.2.1-beta-Linux-x86_64.tar.gz&lt;/a&gt;), and modifying the the commands above appropriately.&lt;p&gt;A newer version (5.2.9) of this precompiled 32-bit Linux MariaDB is new available: &lt;a href="http://pts-mini-gpl.googlecode.com/svn/trunk/portable-mariadb.release/portable-mariadb.tbz2"&gt;http://pts-mini-gpl.googlecode.com/svn/trunk/portable-mariadb.release/portable-mariadb.tbz2&lt;/a&gt;. Here is the shell script which generated it from the official MariaDB 5.2.9 sources: &lt;a href="http://code.google.com/p/pts-mini-gpl/source/browse/trunk/portable-mariadb/build-mariadb.sh"&gt;http://code.google.com/p/pts-mini-gpl/source/browse/trunk/portable-mariadb/build-mariadb.sh&lt;/a&gt;. Here is the newer blog post: &lt;a href="http://ptspts.blogspot.com/2011/11/announcing-portable-mariadb-small.html"&gt;http://ptspts.blogspot.com/2011/11/announcing-portable-mariadb-small.html&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-9133988882863956701?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/9133988882863956701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=9133988882863956701' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/9133988882863956701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/9133988882863956701'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/08/how-to-try-latest-mariadb-on-linux.html' title='How to try the latest MariaDB on Linux'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-3934980915278815460</id><published>2010-07-29T21:05:00.000+02:00</published><updated>2010-07-29T21:05:14.411+02:00</updated><title type='text'>How to create a bootable Ubuntu Lucid USB pen drive with persistent storage</title><content type='html'>&lt;p&gt;This blog explains how to create a bootable Ubuntu Lucid Lynx (10.04) USB pen drive with persistent storage. Persistent storage means that all changes made to the system settings and all files in the user's home directory are saved to the pen drive and are available after system reboot.&lt;p&gt;Connect your USB pen drive.&lt;p&gt;The Ubuntu Lucid live system supports persistent storage by default. On an existing Ubuntu Lucid system &lt;i&gt;System / Administration / Startup Disk Creator&lt;/i&gt; on an existing Ubuntu Lucid system. If you have an existing Ubuntu Karmic system, run &lt;code&gt;sudo apt-get install usb-creator&lt;/code&gt; to install the &lt;i&gt;Startup Disk Creator&lt;/i&gt; program, and then run &lt;i&gt;System / Administration / USB Startup Disk Creator&lt;/i&gt;.&lt;p&gt;Make sure that the &lt;i&gt;Stored in reserved extra space&lt;/i&gt; is selected (it's selected by default).&lt;p&gt;Download the live CD ISO image to your hard drive from &lt;a href="http://releases.ubuntu.com/lucid/ubuntu-10.04-desktop-i386.iso"&gt;http://releases.ubuntu.com/lucid/ubuntu-10.04-desktop-i386.iso&lt;/a&gt;. If you want to download from a faster mirror, please find the ISO image link on &lt;a href="http://releases.ubuntu.com/lucid/"&gt;http://releases.ubuntu.com/lucid/&lt;/a&gt;. For maximum compatibility, select the &lt;i&gt;Intel x86&lt;/i&gt; (or i386, or 32-bit) version. The download may take 30 minutes or more.&lt;p&gt;In the startup disk creator window, specify the downloaded &lt;code&gt;.iso&lt;/code&gt; file by clicking on the &lt;i&gt;Other...&lt;/i&gt; button.&lt;p&gt;For maximum compatibility, format your pen drive, by clicking on the &lt;i&gt;Format&lt;/i&gt; button in the startup disk creator window.&lt;p&gt;Click on the &lt;i&gt;Make Startup Disk&lt;/i&gt; button.&lt;p&gt;Eject (remove) the USB pen drive in the file manager. Disconnect the pen drive.&lt;p&gt;Boot the computer from your USB stick as usual. There is now configuration necessary. All files you create in the live system in the user's home directory, and all settings you change get retained through reboots.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-3934980915278815460?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/3934980915278815460/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=3934980915278815460' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/3934980915278815460'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/3934980915278815460'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/07/how-to-create-bootable-ubuntu-lucid-usb.html' title='How to create a bootable Ubuntu Lucid USB pen drive with persistent storage'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-2029521564415544606</id><published>2010-07-27T11:28:00.001+02:00</published><updated>2010-07-27T11:28:48.732+02:00</updated><title type='text'>How to add (generate) locales on Debian and Ubuntu</title><content type='html'>&lt;p&gt;This blog post gives instructions to add (and generate) locales on Debian and Ubuntu systems. The instructions given here work on Debian Etch and newer, and Ubuntu Hardy and newer (including Intrepid, Jaunty and Karmic).&lt;p&gt;To add the locales &lt;code&gt;hu_HU.ISO8859-2&lt;/code&gt; and &lt;code&gt;hu_HU.UTF-8&lt;/code&gt;, run&lt;pre&gt;$ echo 'hu_HU.ISO8859-2 ISO-8859-2' | sudo tee -a /var/lib/locales/supported.d/hu&lt;br /&gt;$ echo 'hu_HU.UTF-8 UTF-8' | sudo tee -a /var/lib/locales/supported.d/hu&lt;br /&gt;$ sudo dpkg-reconfigure locales &lt;/pre&gt;&lt;p&gt;To verify that the locales are installed correctly, run the following commands and verify that they don't print anything:&lt;pre&gt;$ LC_ALL=hu_HU.ISO8859-2 perl -e0&lt;br /&gt;$ LC_ALL=hu_HU.UTF-8 perl -e0&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-2029521564415544606?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/2029521564415544606/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=2029521564415544606' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2029521564415544606'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2029521564415544606'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/07/how-to-add-generate-locales-on-debian.html' title='How to add (generate) locales on Debian and Ubuntu'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-5127562476340303774</id><published>2010-07-17T18:17:00.004+02:00</published><updated>2010-07-22T00:06:41.307+02:00</updated><title type='text'>An approximation of pi in bc</title><content type='html'>&lt;p&gt;This blog post shows an approximation of the constant π (3.14...) implemented as a &lt;i&gt;bc&lt;/i&gt; program using Machin's formula.&lt;p&gt;Machin's formula is documented on &lt;a href="http://en.wikipedia.org/wiki/Numerical_approximations_of_%CF%80#Machin-like_formulae"&gt;http://en.wikipedia.org/wiki/Numerical_approximations_of_%CF%80#Machin-like_formulae&lt;/a&gt;. The implementation below computes &lt;i&gt;acot&lt;/i&gt; using its Taylor series expansion, always rounding down for divisions. The implementation knows the number of good digits by computing an upper bound of the total rounding error.&lt;pre&gt;#! /usr/bin/bc -q&lt;br /&gt;# by pts@fazekas.hu at Sat Jul 17 17:38:25 CEST 2010&lt;br /&gt;&lt;br /&gt;/** Return an approximation and lower bound for acot(x) * 10 ^ u. */&lt;br /&gt;define acot(x, u) {&lt;br /&gt;  auto sum, xpower, xx, n, term&lt;br /&gt;  sum = xpower = u / x&lt;br /&gt;  xx = x * x&lt;br /&gt;  n = 3&lt;br /&gt;  for (;;) {&lt;br /&gt;    xpower /= xx&lt;br /&gt;    term = xpower / n&lt;br /&gt;    if (term == 0)&lt;br /&gt;      return sum&lt;br /&gt;    sum -= term&lt;br /&gt;    n += 2&lt;br /&gt;    xpower /= xx&lt;br /&gt;    term = xpower / n&lt;br /&gt;    if (term == 0)&lt;br /&gt;      return sum&lt;br /&gt;    sum += term&lt;br /&gt;    n += 2&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* Return an integer upper bound for the &gt;= 0 error value pi * 10 ^ u - f(u),&lt;br /&gt; * where u is 10 ^ nd, f(u) is the integer 4 * (4 * acot(5, u) - acot(239, u)).&lt;br /&gt; *&lt;br /&gt; * The magic constants in the maxerr implementation were derived from analyzing&lt;br /&gt; * the acot implementation, taking into account the rounding (truncation) done&lt;br /&gt; * in each division.&lt;br /&gt; */&lt;br /&gt;define maxerr(nd) {&lt;br /&gt;  return (286135312 * nd + 41739380) / 10000000&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* Return a string of at most nd characters, prefix of pi,&lt;br /&gt; * assuming nd &gt;= 4.&lt;br /&gt; */&lt;br /&gt;define pi(nd) {&lt;br /&gt;  auto u, y&lt;br /&gt;  u = 10 ^ nd&lt;br /&gt;  y = 4 * (4 * acot(5, u) - acot(239, u))&lt;br /&gt;  y /= 10 ^ (length(maxerr(nd)) - 1)&lt;br /&gt;  while (y % 10 == 0) {&lt;br /&gt;    y /= 10&lt;br /&gt;  }&lt;br /&gt;  return y / 10&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* Print pi with increasing precision infinitely (until aborted). */&lt;br /&gt;define pinfinite() {&lt;br /&gt;  auto b, nb, nd, a, na&lt;br /&gt;  print "3."&lt;br /&gt;  b = 3&lt;br /&gt;  nb = 1&lt;br /&gt;  nd = 8&lt;br /&gt;  for (;;) {&lt;br /&gt;    a = pi(nd)&lt;br /&gt;    na = length(a)&lt;br /&gt;    /* Print digits not printed yet in previous iterations. */&lt;br /&gt;    print a % (10 ^ (na - nb))&lt;br /&gt;    b = a&lt;br /&gt;    nb = na&lt;br /&gt;    nd *= 3&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;pinfinite()  /* Infinite loop. */&lt;/pre&gt;Here is the equivalent program in &lt;i&gt;dc&lt;/i&gt;:&lt;pre&gt;[lulx/dspsslxd*sw3snlDx]sC[ls2Q]sS[lplw/dspln/dst0=Slslt-ssln2+snlplw/dsp&lt;br /&gt;ln/dst0=Slslt+ssln2+snlDx]sD[ly10/dsy10%0=Q]sQ[10ld^sz5sxlzsulCx4*239sxlz&lt;br /&gt;sulCx-4*10ld286135312*41739380+10000000/Z1-^/dsy10%0=Qly10/]sP[10lksdlPxd&lt;br /&gt;sgZdsilj-^lgr%nlgshlisjlk3*sklIx]sI[3.]n3sh1sj8sklIx&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-5127562476340303774?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/5127562476340303774/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=5127562476340303774' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/5127562476340303774'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/5127562476340303774'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/07/approximation-of-pi-in-bc.html' title='An approximation of pi in bc'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-7385454711601486031</id><published>2010-06-27T12:58:00.010+02:00</published><updated>2010-10-20T14:37:26.073+02:00</updated><title type='text'>How to enable bitmap fonts on Ubuntu Karmic and Ubuntu Lucid?</title><content type='html'>&lt;p&gt;This blog post gives instructions to enable bitmap fonts for GNOME and other Xft X11 applications. The instructions given have been tested on Ubuntu Karmic and Ubuntu Lucid, but they might work on other Unix systems as well with minor modifications. The reason for enabling bitmap fonts is to get crisp font rendering in dialog boxes, menus and window titles.&lt;/p&gt;&lt;p&gt;Run these commands to install some bitmap fonts from package:&lt;pre&gt;$ sudo apt-get install xfonts-mplus xfonts-bitmap-mule xfonts-base&lt;br /&gt;$ sudo apt-get install xfonts-75dpi{,-transcoded} xfonts-100dpi{,-transcoded}&lt;/pre&gt;&lt;p&gt;Run the command to install some Microsoft vector fonts (e.g. Times New Roman, Arial, Courier New, Verdana). Installation might take a few minutes, because the font files have to be downloaded form an external site.&lt;pre&gt;$ sudo apt-get install msttcorefonts&lt;/pre&gt;&lt;p&gt;If you are using Ubuntu Karmic or earlier (not Ubuntu Lucid or later), then run these commands to install some QT configuration tools (needed for Skype):&lt;pre&gt;$ sudo apt-get install qt3-qtconfig qt4-qtconfig&lt;/pre&gt;&lt;p&gt;Run these commands to install some useful fonts (fixedsc is the classic 6x13 xterm monospaced bitmap font helpfully renamed to FixedSC, and helxetica is the Helvetica bitmap font helpfully renamed to Helxetica, for QT):&lt;pre&gt;$ wget -q -O - http://pts-mini-gpl.googlecode.com/svn/trunk/fonts/helxetica.tgz |&lt;br /&gt;       (cd / &amp;&amp; sudo tar xzv)&lt;br /&gt;$ wget -q -O - http://pts-mini-gpl.googlecode.com/svn/trunk/fonts/fixedsc.tgz |&lt;br /&gt;       (cd / &amp;&amp; sudo tar xzv)&lt;/pre&gt;&lt;p&gt;Enable bitmap fonts (this works in Ubuntu Hardy, Ubuntu Intrepid, Ubuntu Jaunty as well as in Ubuntu Karmic and Ubuntu Lucid):&lt;pre&gt;$ sudo rm -f /etc/fonts/conf.d/70-{yes,no,force}-bitmaps.conf&lt;br /&gt;$ if test -f /etc/fonts/conf.avail/70-force-bitmaps.conf&lt;br /&gt;  then sudo ln -s {../conf.avail,/etc/fonts/conf.d}/70-force-bitmaps.conf&lt;br /&gt;  else sudo ln -s {../conf.avail,/etc/fonts/conf.d}/70-yes-bitmaps.conf&lt;br /&gt;  fi&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;if&lt;/code&gt; above is needed, because &lt;code&gt;/etc/fonts/conf.avail/70-force-bitmaps.conf&lt;/code&gt; has been introduced and /etc/fonts/conf.avail/70-yes-bitmaps.conf was made almost empty in Ubuntu Lucid. The correct (non-empty) contents are:&lt;pre&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE fontconfig SYSTEM "fonts.dtd"&amp;gt;&lt;br /&gt;&amp;lt;fontconfig&amp;gt;&lt;br /&gt;&amp;lt;!-- Accept bitmap fonts --&amp;gt;&lt;br /&gt; &amp;lt;selectfont&amp;gt;&lt;br /&gt;  &amp;lt;acceptfont&amp;gt;&lt;br /&gt;   &amp;lt;pattern&amp;gt;&lt;br /&gt;     &amp;lt;patelt name="scalable"&amp;gt;&amp;lt;bool&amp;gt;false&amp;lt;/bool&amp;gt;&amp;lt;/patelt&amp;gt;&lt;br /&gt;   &amp;lt;/pattern&amp;gt;&lt;br /&gt;  &amp;lt;/acceptfont&amp;gt;&lt;br /&gt; &amp;lt;/selectfont&amp;gt;&lt;br /&gt;&amp;lt;/fontconfig&amp;gt;&lt;/pre&gt;&lt;p&gt;Run these commands to rebuild the font filename cache (so it will find all bitmap fonts, including the newly installed fonts):&lt;pre&gt;$ sudo rm -f /var/cache/fontconfig/*&lt;br /&gt;$ rm -rf "$HOME/.fontconfig"&lt;br /&gt;$ sudo fc-cache&lt;br /&gt;$ fc-cache&lt;br /&gt;$ fc-list | grep -E 'Helxetica|FixedSC' | sort&lt;br /&gt;FixedSC:style=Bold&lt;br /&gt;FixedSC:style=Regular&lt;br /&gt;Helxetica:style=Bold&lt;br /&gt;Helxetica:style=Bold Oblique&lt;br /&gt;Helxetica:style=Oblique&lt;br /&gt;Helxetica:style=Regular&lt;/pre&gt;&lt;p&gt;To have crisp fonts in dialog boxes, menus an window titles, then in &lt;i&gt;System / Preferences / Appearance / Fonts&lt;/i&gt;, set the following font settings (on Ubuntu Lucid, use &lt;i&gt;Helxetica&lt;/i&gt; instead of &lt;i&gt;Helvetica&lt;/i&gt;):&lt;ul&gt;&lt;li&gt;Application font: &lt;i&gt;Helvetica&lt;/i&gt; | 9&lt;li&gt;Document font: &lt;i&gt;Arial&lt;/i&gt; | 10&lt;li&gt;Desktop font: &lt;i&gt;Helvetica&lt;/i&gt; | 9&lt;li&gt;Window title font: &lt;i&gt;Helvetica Bold&lt;/i&gt; | 9&lt;li&gt;Fixed width font: &lt;i&gt;FixedSC&lt;/i&gt; | 10&lt;/ul&gt;&lt;p&gt;To make the GNOME Panel reload its menu font, you have to restart it. Run&lt;pre&gt;$ killall gnome-panel&lt;/pre&gt;&lt;p&gt;In &lt;i&gt;Applications / Accessories / Terminal / Edit / Profile preferences&lt;/i&gt;, make sure the &lt;i&gt;Use the system fixed width font&lt;/i&gt; is ticked.&lt;p&gt;On Ubuntu Karmic and earlier, press Alt-&lt;i&gt;F2&lt;/i&gt;, type &lt;i&gt;qtconfig-qt3&lt;/i&gt;, press &lt;i&gt;Enter&lt;/i&gt;, then wait for the &lt;i&gt;Qt Configuration&lt;/i&gt; window to appear. In the tab &lt;i&gt;Fonts&lt;/i&gt;, change the &lt;i&gt;Family:&lt;/i&gt; to &lt;i&gt;Helxetica&lt;/i&gt; (sic, it's not &lt;i&gt;Helvetica&lt;/i&gt;), and the &lt;i&gt;Point Size:&lt;/i&gt; to 9. In the menu, choose &lt;i&gt;File / Save&lt;/i&gt;, then &lt;i&gt;File / Exit&lt;/i&gt;.&lt;p&gt;On Ubuntu Karmic and earlier, repeat the previous paragraph with &lt;i&gt;qtconfig-qt4&lt;/i&gt; instead of &lt;i&gt;qtconfig-qt3&lt;/i&gt;.&lt;p&gt;Notes:&lt;ul&gt;&lt;li&gt;There is no need to log out, restart Skype, restart Firefox restart Nautilus, restart the GNOME Terminal or restart the GNOME Panel. All these applications pick up the font changes immediately.&lt;li&gt;The &lt;i&gt;Fixed&lt;/i&gt; (6x13) had to be renamed to &lt;i&gt;FixedSC&lt;/i&gt;, because the original 6x13 font has the tag &lt;i&gt;semicondensed&lt;/i&gt;, which makes it impossible to select in the GNOME font selection dialog (or in any fontconfig-based app).&lt;li&gt;The &lt;i&gt;Helvetica&lt;/i&gt; bitmap font had to be renamed to &lt;i&gt;Helxetica&lt;/i&gt;, because QT4 applications (such as Skype 2.1) cannot render non-latin-1 characters properly (they will find a substitution font for those characters, even though the characters are available in the &lt;i&gt;Helvetica&lt;/i&gt; font).&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-7385454711601486031?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/7385454711601486031/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=7385454711601486031' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7385454711601486031'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7385454711601486031'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/06/how-to-enable-bitmap-fonts-on-ubuntu.html' title='How to enable bitmap fonts on Ubuntu Karmic and Ubuntu Lucid?'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-3614485612660806535</id><published>2010-06-20T14:18:00.000+02:00</published><updated>2010-06-20T14:18:59.808+02:00</updated><title type='text'>Does Btrfs survive silent disk data corruption in RAID1 mode?</title><content type='html'>&lt;p&gt;Some of my experimenting with Btrfs in Linux 2.6.34 yielded the following results:&lt;ul&gt;&lt;li&gt;If only one disk (out of two) contains corrupt data, then Btrfs detects some checksum failures, and then recovers (overwriting the corrupt data with the corresponding good data from the other disk). This works even if the corruption happened while the filesystem was mounted.&lt;li&gt;If both disks contain corrupt data (but not at the same location), then Btrfs detects some checksum failures, then recovers some data, but it won't recover all of it: some files continue to have I/O errors when reading, and the syslog will contain checksum failures again and again. The explanation for this behavior may be that in Btrfs RAID 1 mode the two copies of a block of data might be at a different offset on the two disks.&lt;/ul&gt;&lt;p&gt;Here is how I did the experiment:&lt;ul&gt;&lt;li&gt;I had a Linux 2.6.34 system.&lt;li&gt;I had 2 partitions of size 2000061 KB each. (1 KB == 1 &lt;&lt; 10 bytes.)&lt;li&gt;&lt;code&gt;# mkfs.btrfs -m raid1 -d raid1 /dev/sdc1 /dev/sdb1&lt;/code&gt;&lt;li&gt;&lt;code&gt;# mount /dev/sdb1 /mnt/p&lt;/code&gt;&lt;li&gt;I copied &lt;code&gt;/var/lib/dpkg&lt;/code&gt; (7248 small files of 36.93 MB) recursively to &lt;code&gt;/mnt/p&lt;/code&gt;.&lt;li&gt;I copied 4 large files of 1517.98 MB in total to &lt;code&gt;/mnt/p&lt;/code&gt;. (So the filesystem became &amp;gt;75% full.)&lt;li&gt;I created 10000 empty files.&lt;li&gt;I calculated the checksum of all files in &lt;code&gt;/mnt/p&lt;/code&gt; with a userspace tool.&lt;li&gt;I introduced the single-disk corruption by running &lt;code&gt;dd if=/dev/zero of=/dev/sdb1 bs=1M count=1600 seek=200&lt;/code&gt;&lt;li&gt;I calculated the checksum of all files again. At this point the kernel reported some block checksum mismatches in the syslog, but eventually Btrfs has recovered all the data, and the file checksums matched with the previous run.&lt;li&gt;I introduced the non-ovarlapping multi-disk corruption by running &lt;code&gt;dd if=/dev/zero of=/dev/sdb1 bs=1M count=800 seek=200 &amp;&amp; dd if=/dev/zero of=/dev/sdc1 bs=1M count=800 seek=1000&lt;/code&gt;&lt;li&gt;I calculated the checksum of all files again. At this point the kernel reported some block checksum mismatches in the syslog, and it could reover some blocks, but not all, and some files yielded an I/O error, but the checksum of the non-erroneous files matched with the previous run.&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-3614485612660806535?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/3614485612660806535/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=3614485612660806535' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/3614485612660806535'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/3614485612660806535'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/06/does-btrfs-survive-silent-disk-data.html' title='Does Btrfs survive silent disk data corruption in RAID1 mode?'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-8637093643068602570</id><published>2010-06-18T18:47:00.000+02:00</published><updated>2010-06-18T18:47:59.303+02:00</updated><title type='text'>How to use the ssh-agent programmatically for RSA signing</title><content type='html'>&lt;p&gt;This blog post explains what an SSH agent does, and then gives initial hints and presents some example code using the ssh-agent wire protocol (the SSH2 version of it, as implemented by OpenSSH) for listing the public keys added to the agent, and for signing a message with an RSA key. The motivation for this blog post is to teach the reader how to use ssh-agent to sign a message with RSA. Currently there is no command-line tool for that.&lt;p&gt;The SSH agent (started as the &lt;i&gt;ssh-agent&lt;/i&gt; command in Unix, or usually as Pageant in Windows) is a background application which can store in its process memory some SSH public key pairs in unencrypted form, for the convenience of the user. When logging in, ssh-agent is usually started for the user; the user then calls &lt;i&gt;ssh-add&lt;/i&gt; (or a similar GUI application) to add his key pairs (e.g. &lt;code&gt;$HOME/.ssh/id*&lt;/code&gt;) to the agent, typing the key passphrases if necessary. Afterwards, the user initiates SSH connections, for which the keys used for authentication are taken from the currently running agent. The SSH agent provides the convenience for the user that the user doesn't have to type the key passphrases multiple time, plus that if agent forwarding is enabled (&lt;code&gt;ForwardAgent yes&lt;/code&gt; is present in &lt;code&gt;$HOME/.ssh/config&lt;/code&gt;), then the agent is available in SSH connections initiated from SSH connections (of arbitrary depth). The agent forwarding feature of ssh-agent is unique, because other in-memory key stores such as &lt;i&gt;gpg-agent&lt;/i&gt; don't have that feature, so the keys stored there are available only locally, and not within SSH sessions.&lt;p&gt;The SSH agent stores both the public and the private keys of a key pair (and the comment as well), but it only ever discloses the public keys to applications connecting to it. The public keys can be queried (displayed) with the &lt;code&gt;ssh-add -L&lt;/code&gt; command. But to the ssh-agent can prove to the external world that it knows the private keys (without revealing the keys themselves), because it offers a service to sign the &lt;a href="http://en.wikipedia.org/wiki/SHA-1"&gt;SHA-1&lt;/a&gt; checksum (hash) of any string. SSH uses &lt;a href="http://en.wikipedia.org/wiki/Public-key_cryptography"&gt;public-key cryptography&lt;/a&gt;, which has the basic assumption that a party can sign a message with a key only he knows the private key; but anyone who knows the public key can verify the signature.&lt;p&gt;&lt;i&gt;ssh-add&lt;/i&gt; uses the &lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt; environment variable (containing the pathname of a Unix domain socket) to figure out which ssh-agent to connect to. The permissions for the socket pathname are set up so that only the rightful owner (or root) can connect, other users get a &lt;i&gt;Permission denied&lt;/i&gt;.&lt;p&gt;For more information about how SSH uses public-key cryptography and agents, please read &lt;a href="http://www.unixwiz.net/techtips/ssh-agent-forwarding.html"&gt;this excellent article&lt;/a&gt;.&lt;p&gt;Below there is an example wire dump of an application using the SSH agent protocol to ask the list of public keys added to an ssh-agent (just like &lt;code&gt;ssh-add -L&lt;/code&gt;), and to ask the ssh-agent to sign a message with an RSA key added to it. The sign request is usually sent when an SSH client (ssh(1)) is authenticating itself to an SSH server, when establishing a connection.&lt;p&gt;To understand the wire dump below, one has to know that in the &lt;a href="http://en.wikipedia.org/wiki/RSA"&gt;RSA&lt;/a&gt; public-key cryptography system the public key consists of a modulus and a public exponent, the modulus being a very large integer (2048 bits or longer), the exponent being positive a small or large integer, smaller than the modulus. Verifying a signature consits of interpreting a signature as a large integer, exponentiating it to the public exponent, taking the result modulo the modulus, and comparing that result with the original message (or, in case of SSH, the SHA-1 checksum of the original message). Please read the article linked above for a full definition and the operation of RSA.&lt;pre class="syntax"&gt;&lt;span class="c"&gt;# The client connects to the agent.&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect_to_agent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="c"&gt;# The clients lists the key pairs added to the agent.&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\0\1&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# request_size == 1&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\v&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# 11 == SSH2_AGENTC_REQUEST_IDENTITIES&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\3\5&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# response_size == 773&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\f&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# 12 == SSH2_AGENT_IDENTITIES_ANSWER&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\0\2&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# num_entries == 2&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\1\261&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# entry[0].key_size == 433&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\0\7&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# key_type_size == 7&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ssh-dss&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# 443-4-7 bytes of the DSA key&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\0\25&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# entry[0].comment_size == 21&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/home/foo/.ssh/id_dsa&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\1\25&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# entry[1].key_size == 275&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\0\7&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# key_type_size == 7&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ssh-rsa&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\0\1&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# public_exponent_size == 1&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# public_exponent == 35&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\1\1&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# modulus_size == 257&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0&lt;/span&gt;&lt;span class="s"&gt;...&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# p * q in MSBFirst order&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\0\25&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# entry[1].comment_size == 21&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/home/foo/.ssh/id_rsa&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="c"&gt;# The client gets the agent sign some data.&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;  &lt;span class="c"&gt;# 356 arbitrary bytes to get signed.&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\2\206&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# request_size == 646&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\r&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# 13 == SSH2_AGENTC_SIGN_REQUEST&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\1\25&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# key_size == 277&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\0\7&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# key_type_size == 7&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ssh-rsa&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\0\1&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# public_exponent_size == 1&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# public_exponent == 35&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\1\1&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# modulus_size == 257&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0&lt;/span&gt;&lt;span class="s"&gt;...&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# p * q in MSBFirst order&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\1&lt;/span&gt;&lt;span class="s"&gt;d&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# data_size == 356&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# arbitary bytes to sign&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\0\0&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# flags == 0&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\1\24&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# response_size == 276&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\16&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# 14 == SSH2_AGENT_SIGN_RESPONSE  (could be 5 == SSH_AGENT_FAILURE)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\1\17&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# signature_size == 271&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\0\7&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# key_type_size == 7&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ssh-rsa&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\0\0\1\0&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# signed_value_size == 256&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# MSBFirst order&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="c"&gt;# The client closes the SSH connection.&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# EOF&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;Below there is an example Python script which acts as a client to ssh-agent, listing the keys added (similarly to &lt;code&gt;ssh-add -L&lt;/code&gt;), selecting a key, asking ssh-agent to sign a message with an RSA key, and finally verifying the signature. View and download the latest version of the script &lt;a href="http://code.google.com/p/pts-mini-gpl/source/browse/trunk/rsa/ssh_agent_rsa_sign_example.py"&gt;here&lt;/a&gt;.&lt;pre class="syntax"&gt;&lt;span class="c"&gt;#! /usr/bin/python2.4&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;cStringIO&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;re&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sha&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;socket&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;struct&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;SSH2_AGENTC_REQUEST_IDENTITIES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;SSH2_AGENT_IDENTITIES_ANSWER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;SSH2_AGENTC_SIGN_REQUEST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;SSH2_AGENT_SIGN_RESPONSE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;SSH_AGENT_FAILURE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;RecvAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;recv&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;recv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recv&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;recv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;unexpected EOF&amp;#39;&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;unexpected EOF&amp;#39;&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;RecvU32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unpack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&amp;gt;L&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RecvAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;RecvStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;RecvAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RecvU32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;AppendStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;ary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&amp;gt;L&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;ary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;ssh_key_comment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="c"&gt;# We won&amp;#39;t open this file, but we will use the file name to select the key&lt;/span&gt;&lt;br /&gt;    &lt;span class="c"&gt;# added to the SSH agent.&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;ssh_key_comment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;/.ssh/id_rsa&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;HOME&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="c"&gt;# There is no limitation on the message size (because ssh-agent will&lt;/span&gt;&lt;br /&gt;    &lt;span class="c"&gt;# SHA-1 it before signing anywa).&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;msg_to_sign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;msg_to_sign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;Hello, World! Test message to sign.&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="c"&gt;# Connect to ssh-agent.&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;SSH_AUTH_SOCK&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;br /&gt;      &lt;span class="s"&gt;&amp;#39;ssh-agent not found, set SSH_AUTH_SOCK&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;sock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AF_UNIX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SOCK_STREAM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;SSH_AUTH_SOCK&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="c"&gt;# Get list of public keys, and find our key.&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sendall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\0\0\0\1\v&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;# SSH2_AGENTC_REQUEST_IDENTITIES&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RecvStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;resf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cStringIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StringIO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;RecvAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;chr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SSH2_AGENT_IDENTITIES_ANSWER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;num_keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RecvU32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;num_keys&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;  &lt;span class="c"&gt;# A quick sanity check.&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;num_keys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;no keys have_been added to ssh-agent&amp;#39;&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;matching_keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_keys&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RecvStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;comment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RecvStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;comment&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ssh_key_comment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;matching_keys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;resf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;EOF expected in resf&amp;#39;&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;matching_keys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;no keys in ssh-agent with comment &lt;/span&gt;&lt;span class="si"&gt;%r&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;ssh_key_comment&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;matching_keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;br /&gt;      &lt;span class="s"&gt;&amp;#39;multiple keys in ssh-agent with comment &lt;/span&gt;&lt;span class="si"&gt;%r&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;ssh_key_comment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;matching_keys&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\x00\x00\x00\x07&lt;/span&gt;&lt;span class="s"&gt;ssh-rsa&lt;/span&gt;&lt;span class="se"&gt;\x00\x00&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;br /&gt;      &lt;span class="s"&gt;&amp;#39;non-RSA key in ssh-agent with comment &lt;/span&gt;&lt;span class="si"&gt;%r&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;ssh_key_comment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;keyf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cStringIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StringIO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;matching_keys&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;public_exponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RecvStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;hex&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;modulus_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RecvStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;modulus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modulus_str&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;hex&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;keyf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;EOF expected in keyf&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="c"&gt;# Ask ssh-agent to sign with our key.&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;request_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;chr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SSH2_AGENTC_SIGN_REQUEST&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;AppendStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request_output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;matching_keys&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;AppendStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request_output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_to_sign&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;request_output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&amp;gt;L&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c"&gt;# flags == 0&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;full_request_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;AppendStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;full_request_output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request_output&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;full_request_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;full_request_output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sendall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;full_request_str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RecvStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;resf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cStringIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StringIO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;RecvAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;chr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SSH2_AGENT_SIGN_RESPONSE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RecvStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;resf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;EOF expected in resf&amp;#39;&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;signature&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\0\0\0\7&lt;/span&gt;&lt;span class="s"&gt;ssh-rsa&lt;/span&gt;&lt;span class="se"&gt;\0\0&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;sigf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cStringIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StringIO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;signed_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RecvStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sigf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;hex&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;sigf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;EOF expected in sigf&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="c"&gt;# Verify the signature.&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;decoded_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signed_value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;public_exponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;modulus&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;decoded_hex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%x&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;decoded_value&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decoded_hex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;decoded_hex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;0&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;decoded_hex&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;decoded_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;decoded_hex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;hex&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decoded_str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modulus_str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;  &lt;span class="c"&gt;# e.g. (255, 257)&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;r&amp;#39;\x01\xFF+\Z&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decoded_str&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;bad padding found&amp;#39;&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;expected_sha1_hex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;decoded_hex&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;msg_sha1_hex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sha&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sha&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg_to_sign&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;expected_sha1_hex&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;msg_sha1_hex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;bad signature (SHA1 mismatch)&amp;#39;&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;info: good signature&amp;#39;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;The wire dump above was created by attaching to a running ssh-agent with &lt;i&gt;strace&lt;/i&gt;. The Python example code was written by understanding the &lt;a href="http://www.google.com/codesearch/p?hl=en#l6uhtM9VBFo/pub/OpenBSD/OpenSSH/openssh-4.5.tar.gz|xqe1czY35kc/ssh/ssh-agent.c"&gt;ssh-agent.c&lt;/a&gt; in the OpenSSH codebase.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-8637093643068602570?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/8637093643068602570/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=8637093643068602570' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/8637093643068602570'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/8637093643068602570'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/06/how-to-use-ssh-agent-programmatically.html' title='How to use the ssh-agent programmatically for RSA signing'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-6748642812996755867</id><published>2010-06-14T11:05:00.003+02:00</published><updated>2010-06-21T00:14:52.869+02:00</updated><title type='text'>How to fix printing with HP LaserJet 1018 on Ubuntu Lucid and Karmic</title><content type='html'>&lt;p&gt;This blog post explains how to fix CUPS printing for HP LaserJet 1018. The instructions and the shell script presented have been tested on Ubuntu Lucid and Ubuntu Karmic, but they might work on other Linux systems as well with minor modifications.&lt;p&gt;The first method to make the HP LaserJet 1018 work is running&lt;pre&gt;&lt;br /&gt;$ sudo apt-get install hplip&lt;br /&gt;$ sudo hp-setup&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;, and following the instructions, and running &lt;i&gt;hp-setup&lt;/i&gt; again if necessary. This method seemed to work for me (I could print a test page), but I haven't tested it excessively, and theprinter got the margins wrong, because it assumed that I'm printing to Letter paper, but I was printing to A4.&lt;p&gt;The second method (recommended) is the following. Download and run this script: &lt;a href="http://pts-mini-gpl.googlecode.com/svn/trunk/pts-hplj1018/fix_hplj1018.sh"&gt;http://pts-mini-gpl.googlecode.com/svn/trunk/pts-hplj1018/fix_hplj1018.sh&lt;/a&gt;.&lt;p&gt;The script download and install the printer firmware, it will ask you to install some packages (such as &lt;i&gt;cups&lt;/i&gt; and &lt;i&gt;foo2zjs&lt;/i&gt;), and to connect and disconnect the printer. It will also install the printer, remove (cancel) all pending jobs, and change the CUPS printer state to &lt;i&gt;ready&lt;/i&gt;. Run this script each time you can't print anymore (e.g. because of a system upgrade).&lt;p&gt;The script has the A4 page size (used in Europe) hard-wired. If your printer supports the Letter page size (used in the USA), replace all occurrences of the word &lt;code&gt;A4&lt;/code&gt; in the script by the word &lt;code&gt;Letter&lt;/code&gt;.&lt;p&gt;Setting up the printer is tricky because all settings have to be correct (otherwise the printer will just ignore jobs sent to it), and Ubuntu gets many settings wrong. The script fixes these settings:&lt;ul&gt;&lt;li&gt;The updated firmware (as required by foo2zjs) has to be present in &lt;code&gt;/usr/share/foo2zjs/firmware/sihp1018.dl&lt;/code&gt;. Ubuntu doesn't have a package containing this file. The script downloads, extracts and installs the firmware.&lt;li&gt;The correct udev rules have to be in place so &lt;code&gt;/usr/sbin/hplj1018&lt;/code&gt; is run (and uploads the firmware) when the printer is connected. Ubuntu Lucid has a wrong (non-matching) udev rule in &lt;code&gt;/lib/udev/rules.d/85-hplj10xx.rules&lt;/code&gt;. The script fixes to udev rule.&lt;li&gt;The correct PPD file must be present with the correct page size. The default file &lt;code&gt;/usr/share/ppd/foo2zjs/HP-LaserJet_1018.ppd.gz&lt;/code&gt; in Ubuntu has the Letter size, which the script changes to A4 in the file &lt;code&gt;/etc/cups/ppd/HP_LaserJet_1018_pts.ppd&lt;/code&gt;.&lt;li&gt;No printing jobs must be active or pending when the printer gets connected (so the firmware has a chance to upload). Ubuntu doesn't care about this. The script makes sure that CUPS is not running when the printer gets connected, and it also removes all pending jobs.&lt;li&gt;On Ubuntu Lucid there is a conflict between the &lt;i&gt;usblp&lt;/i&gt; and the &lt;i&gt;usb&lt;/i&gt; drivers: the newest CUPS uses &lt;i&gt;usb&lt;/i&gt; to drive USB printers (while older CUPS versions used &lt;i&gt;usblp&lt;/i&gt;), but &lt;i&gt;usblp&lt;/i&gt; claims the printer first, so CUPS has no chance to actually use it. The solution is to modify the &lt;i&gt;DeviceURI&lt;/i&gt; in &lt;code&gt;/etc/cups/printers.conf&lt;/code&gt; to &lt;code&gt;parallel:///dev/usb/lp0&lt;/code&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-6748642812996755867?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/6748642812996755867/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=6748642812996755867' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/6748642812996755867'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/6748642812996755867'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/06/how-to-fix-hp-laserjet-1018-on-ubuntu.html' title='How to fix printing with HP LaserJet 1018 on Ubuntu Lucid and Karmic'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-1561319321639247973</id><published>2010-06-12T23:36:00.004+02:00</published><updated>2010-10-06T13:45:13.565+02:00</updated><title type='text'>How to create a custom keyboard layout for X.Org on Ubuntu</title><content type='html'>&lt;p&gt;This blog post gives an overview of the steps needed for creating and installing a new custom keyboard layout for X.Org (X11). The steps outlined here have been tested on Ubuntu Karmic and Ubuntu Lucid, but they should work on other Linux systems as well with minor modifications. The designer of a custom keyboard layout can assign (almost) Unicode characters and other keyboard symbols (such as &lt;i&gt;F1&lt;/i&gt; or &lt;i&gt;Insert&lt;/i&gt;) arbitrarily to keys and key combinations (with modifiers like &lt;i&gt;Shift&lt;/i&gt; and &lt;i&gt;Ctrl&lt;/i&gt;). You are encouraged to create a custom keyboard layout for yourself if some useful symbols are missing from your favorite keyboard layout, or you can work with your own custom key mapping much faster with the default layouts, or you need a blend of two layouts with &lt;i&gt;AltGr&lt;/i&gt; (right &lt;i&gt;Alt&lt;/i&gt;) as the modifier key for selecting the alternative layout for 1 keypress.&lt;p&gt;All the keyboard layouts are managed by the XKB subsystem. For simplicity, we assume that you run both your X server and clients (at least GNOME and the &lt;i&gt;setxkbmap&lt;/i&gt; command) on the same machine. The keyboard layouts are defined in the text files &lt;code&gt;/usr/share/X11/xkb/symbols/*&lt;/code&gt;, e.g. the file &lt;code&gt;/usr/share/X11/xkb/symbols/us&lt;/code&gt; contains the definition of the US English keyboard layout (and a few of its the variants). Edit one of these files (&lt;code&gt;us&lt;/code&gt;. in the example) as root, adding your entry, e.g.&lt;pre&gt;partial alphanumeric_keys modifier_keys&lt;br /&gt;xkb_symbols "my_layout" {&lt;br /&gt;    // A comment here.&lt;br /&gt;    name[Group1]= "USA - my layout";&lt;br /&gt;    key &lt;....&gt; { ... };&lt;br /&gt;    ...&lt;br /&gt;};&lt;/pre&gt;&lt;p&gt;As soon as you save your changes, you are able to load the new layout with&lt;pre&gt;$ setxkbmap 'us(my_layout)'&lt;/pre&gt;&lt;p&gt;Please note that the command above is a bit dangerous, because if you load an incomplete or bad layout, you may have to log out (using the mouse) and log in again to make your keyboard useful. Another option is to copy the following command (which restores the US English keyboard layout) with its trailing newline to the clipboard before changing the layout, and then pasting it to a terminal emulator when things go wrong:&lt;pre&gt;$ setxkbmap us&lt;/pre&gt;&lt;p&gt;You can load multiple layouts and then use GNOME's keyboard switching applet to switch between them. For example, the following command loads the French layout by default, with an option to switch to your custom layout, and the default English layout as well:&lt;pre&gt;$ setxkbmap 'fr,us(my_layout),us'&lt;/pre&gt;&lt;p&gt;Once your layout is ready, you may want to make it selectable from the GNOME keyboard preferences dialog box (get it from &lt;i&gt;System / Preferences / Keyboard / Layouts / Add&lt;/i&gt;, or start it with &lt;i&gt;gnome-keyboard-properties&lt;/i&gt;, and then select &lt;i&gt;Layouts / Add&lt;/i&gt;). To do so, you have to add your layout to the files &lt;code&gt;/usr/share/X11/xkb/rules/*.{xml,lst}&lt;/code&gt;, close the GNOME keyboard preferences dialog box, reopen it, and then add a new layout which is yours. There is no need to log out or to restart the system. Ubuntu Karmic and Ubuntu Lucid look at &lt;code&gt;evdev.xml&lt;/code&gt; and &lt;code&gt;evdev.lst&lt;/code&gt; (as reported by running &lt;code&gt;$ strace -e open -o key.log gnome-keyboard-properties&lt;/code&gt;), other systems might look at some other files, especially &lt;code&gt;base.xml&lt;/code&gt; and &lt;code&gt;base.lst&lt;/code&gt;.&lt;p&gt;As an example, see &lt;a href="http://code.google.com/p/pts-mini-gpl/source/browse/trunk/pts-magyar/us.pts_magyar.sh"&gt;http://code.google.com/p/pts-mini-gpl/source/browse/trunk/pts-magyar/us.pts_magyar.sh&lt;/a&gt;, which is an installer shell script, which installs the &lt;code&gt;us(pts_magyar)&lt;/code&gt; keyboard layout, modifying files &lt;code&gt;/usr/share/X11/xkb/symbols/us&lt;/code&gt; and &lt;code&gt;/usr/share/X11/xkb/rules/{evdev,base}.{xml,lst}&lt;/code&gt;. Here is how to install it easily:&lt;pre&gt;$ wget -O- \&lt;br /&gt;  http://pts-mini-gpl.googlecode.com/svn/trunk/pts-magyar/us.pts_magyar.sh | bash&lt;/pre&gt;&lt;p&gt;FYI It is possible to load the config files from &lt;code&gt;/usr/share/X11/xkb/symbols&lt;/code&gt; on one machine, and to apply it on any X server (as identified by the &lt;code&gt;$DISPLAY&lt;/code&gt; variable). To do so, run this on the machine with the config file:&lt;pre&gt;setxkbmap us -print | xkbcomp - "$DISPLAY"&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-1561319321639247973?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/1561319321639247973/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=1561319321639247973' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1561319321639247973'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1561319321639247973'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/06/how-to-create-custom-keyboard-layout.html' title='How to create a custom keyboard layout for X.Org on Ubuntu'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-7434868442112176337</id><published>2010-06-11T08:32:00.001+02:00</published><updated>2010-09-30T12:37:55.495+02:00</updated><title type='text'>How to determine if two line segments intersect (in 2D)?</title><content type='html'>&lt;p&gt;This blog post gives the C++ implementation of the fast schoolbook algorithm for determining if two (finite) line segments on a 2D plane intersect (cross).&lt;pre class=syntax&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;IsOnSegment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;xi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;yi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;xj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;yj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br /&gt;                        &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;xk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;yk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xi&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;xk&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;xj&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;xk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xk&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;xi&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;xk&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;xj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;br /&gt;         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yi&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;yk&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;yj&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;yk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yk&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;yi&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;yk&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;yj&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;ComputeDirection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;xi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;yi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;xj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;yj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br /&gt;                             &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;xk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;yk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xk&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;xi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yj&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;yi&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br /&gt;  &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xj&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;xi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yk&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;yi&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="cm"&gt;/** Do line segments (x1, y1)--(x2, y2) and (x3, y3)--(x4, y4) intersect? */&lt;/span&gt;&lt;br /&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;DoLineSegmentsIntersect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;y1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;x2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;y2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br /&gt;                             &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;x3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;y3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;x4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;y4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;d1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ComputeDirection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br /&gt;  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;d2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ComputeDirection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br /&gt;  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;d3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ComputeDirection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br /&gt;  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;d4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ComputeDirection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(((&lt;/span&gt;&lt;span class="n"&gt;d1&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;d2&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;d2&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;br /&gt;          &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;d3&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;d4&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d3&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;d4&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;&lt;br /&gt;         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;IsOnSegment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;&lt;br /&gt;         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;IsOnSegment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;&lt;br /&gt;         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d3&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;IsOnSegment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;&lt;br /&gt;         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d4&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;IsOnSegment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y4&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;br /&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;The algorithm above does 8 multiplications, 16 subtractions and 52 comparisons in the worst case. But it doesn't do any divisions or square roots. If the input coordinates are integers, and the multiplications and subtractions don't yield an overflow, then the whole algorithm can be performed only with integer arithmetic.&lt;p&gt;The algorithm above doesn't return the coordinates of the intersection point. To find the intersection point of two intersecting line segments, see the formula on &lt;a href="http://en.wikipedia.org/wiki/Line-line_intersection"&gt;http://en.wikipedia.org/wiki/Line-line_intersection&lt;/a&gt;.&lt;p&gt;If there are many line segments and we are interested in all intersections, calling the above algorithm for all pairs is slow (quadratic). See faster algorithms (O(n*log(n))) on &lt;a href="http://en.wikipedia.org/wiki/Line_segment_intersection"&gt;http://en.wikipedia.org/wiki/Line_segment_intersection&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-7434868442112176337?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/7434868442112176337/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=7434868442112176337' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7434868442112176337'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7434868442112176337'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/06/how-to-determine-if-two-line-segments.html' title='How to determine if two line segments intersect (in 2D)?'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-8570688199457866247</id><published>2010-06-07T00:16:00.005+02:00</published><updated>2010-10-13T13:44:25.572+02:00</updated><title type='text'>How to disable the login sound and other sounds in Ubuntu Karmic</title><content type='html'>&lt;p&gt;This blog post explains how to disable the login sounds and other sounds for the default GDM and the GNOME session. The solution presented here was tested on Ubuntu Karmic Koala, but there is a little probability that some parts of it would work in other versions of Ubuntu or other Linux systems.&lt;h3&gt;How to disable the login drum sound and the beep sound before logging in&lt;/h3&gt;&lt;p&gt;Run this command in a terminal window (without the $ signs):&lt;pre&gt;$ sudo -u gdm gconftool-2 --type=bool --set /desktop/gnome/sound/event_sounds false&lt;/pre&gt;Please note that many non-working solution attempts are available on the net, some of them involving the key &lt;code&gt;/apps/gdm/simple-greeter/settings-manager-plugins/sound/active&lt;/code&gt; or &lt;code&gt;/apps/gnome_settings_daemon/plugins/sound/active&lt;/code&gt;, but those don't work in Ubuntu Karmic.&lt;p&gt;The &lt;code&gt;sudo -u gdm&lt;/code&gt; part in this solution is essential, because the sound is played by GDM, which looks at the settings for the user &lt;i&gt;gdm&lt;/i&gt;. Without that part (or with only a simple &lt;code&gt;sudo&lt;/code&gt;) it wouldn't have any effect.&lt;p&gt;The annoying drum sound file is &lt;code&gt;/usr/share/sounds/ubuntu/stereo/system-ready.ogg&lt;/code&gt; . Some solutions on the net suggest removing this file (and also &lt;code&gt;bell.ogg&lt;/code&gt;). There is no need to do so.&lt;h3&gt;How to disable the welcome sound after logging in&lt;/h3&gt;&lt;p&gt;In the menu bar on the top of the screen, select &lt;i&gt;System / Preferences / Startup Applications&lt;/i&gt;. In the appearing dialog box, scroll down to find &lt;i&gt;GNOME Login Sound&lt;/i&gt;. Untick it. Click on the &lt;i&gt;Close&lt;/i&gt; button.&lt;p&gt;As an alternative, it is possible to disable this sound from the command-line as well:&lt;pre&gt;$ perl -pi -0777 -e 's@^X-GNOME-Autostart-enabled=.*\n@@mg;&lt;br /&gt;       s@\n*\Z(?!\n)@\nX-GNOME-Autostart-enabled=false\n@' \&lt;br /&gt;       ~/.config/autostart/libcanberra-login-sound.desktop&lt;/pre&gt;&lt;h3&gt;How to disable the Skype login sound after logging in&lt;/h3&gt;&lt;p&gt;Start Skype, find its &lt;i&gt;Options&lt;/i&gt; dialog box. Select the &lt;i&gt;Notifications&lt;/i&gt; tab. In the tab, select &lt;i&gt;Skype Login&lt;/i&gt;. Untick &lt;i&gt;Enable Event&lt;/i&gt;. Click on the &lt;i&gt;Apply&lt;/i&gt; button.&lt;h3&gt;How to disable system sounds (e.g. on mouse clicks)&lt;/h3&gt;Run this command in a terminal window (without the $ signs):&lt;pre&gt;$ gconftool-2 --type=bool --set /desktop/gnome/sound/event_sounds false&lt;/pre&gt;The following commands don't seem to make any difference, but they wouldn't hurt:&lt;pre&gt;$ gconftool-2 --type=bool --set /apps/gnome_settings_daemon/plugins/sound/active false&lt;br /&gt;$ gconftool-2 --type=bool --set \&lt;br /&gt;  /apps/gdm/simple-greeter/settings-manager-plugins/sound/active false&lt;br /&gt;false&lt;/pre&gt;&lt;h3&gt;How to disable application sounds (e.g. notifications and game sounds)&lt;/h3&gt;Run this command in a terminal window (without the $ signs):&lt;pre&gt;$ gconftool-2 --type=bool --set /apps/empathy/sounds/sounds_enabled false&lt;br /&gt;$ gconftool-2 --type=bool --set /apps/gnobots2/preferences/enable_sound false&lt;br /&gt;$ gconftool-2 --type=bool --set /apps/gnome-power-manager/ui/enable_sound false&lt;br /&gt;$ gconftool-2 --type=bool --set /apps/aisleriot/sound false&lt;br /&gt;$ gconftool-2 --type=string --set /apps/nautilus/preferences/preview_sound never&lt;br /&gt;$ gconftool-2 --type=bool --set /apps/gnibbles/preferences/sound false&lt;br /&gt;$ gconftool-2 --type=bool --set /apps/iagno/sound false&lt;br /&gt;$ gconftool-2 --type=bool --set /apps/gnect/sound false&lt;br /&gt;$ gconftool-2 --type=bool --set /apps/evolution/eplugin/mail-notification/sound-enabled false&lt;br /&gt;$ gconftool-2 --type=bool --set /apps/evolution/eplugin/evolution_indicator/play_sound false&lt;/pre&gt;The following commands don't seem to make any difference, but they wouldn't hurt:&lt;pre&gt;$ gconftool-2 --type=bool --set /apps/gnome_settings_daemon/plugins/sound/active false&lt;br /&gt;$ gconftool-2 --type=bool --set \&lt;br /&gt;  /apps/gdm/simple-greeter/settings-manager-plugins/sound/active false&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Your system might have more sounds settings if you have non-default applications installed. To find these settings, start &lt;i&gt;gconf-editor&lt;/i&gt;, select the &lt;i&gt;Edit / Find&lt;/i&gt; menu item, tick the box to search in keys, type &lt;i&gt;sound&lt;/i&gt;, and click on the &lt;i&gt;Search&lt;/i&gt; button. At the bottom of the main &lt;i&gt;gconf-editor&lt;/i&gt; window, you'll find the matches. Browse them and disable them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-8570688199457866247?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/8570688199457866247/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=8570688199457866247' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/8570688199457866247'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/8570688199457866247'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/06/how-to-disable-login-sound-and-other.html' title='How to disable the login sound and other sounds in Ubuntu Karmic'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-1318877172649694331</id><published>2010-06-06T23:06:00.000+02:00</published><updated>2010-06-06T23:06:23.274+02:00</updated><title type='text'>How to disable the user list at the GDM login screen in Ubuntu Karmic</title><content type='html'>&lt;p&gt;This blog post explains how to disable the user list at the GDM login screen. The solution presented here was tested on Ubuntu Karmic Koala, but it might work on other Ubuntu versions as well (Hardy, Interpid, Jaunty, Karmic and Lucid).&lt;p&gt;To disable the user list, run this command in a terminal window (without the $ signs):&lt;pre&gt;$ sudo -u gdm gconftool-2 --type=bool --set /apps/gdm/simple-greeter/disable_user_list true&lt;/pre&gt;&lt;p&gt;Logout and login again. You have to type your user name from now on.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-1318877172649694331?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/1318877172649694331/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=1318877172649694331' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1318877172649694331'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1318877172649694331'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/06/how-to-disable-user-list-at-gdm-login.html' title='How to disable the user list at the GDM login screen in Ubuntu Karmic'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-1545631803753727346</id><published>2010-06-06T22:33:00.003+02:00</published><updated>2010-06-06T22:38:38.908+02:00</updated><title type='text'>How to disable Compiz Fusion and enable Metacity on Ubuntu Karmic</title><content type='html'>&lt;p&gt;This blog post explains how to disable Compiz Fusion (3D desktop effects), and enable Metacity (2D) as the window manager for a GNOME session, for a single user. The solution presented here was tested on Ubuntu Karmic Koala, but it might work on other Ubuntu versions as well (Hardy, Interpid, Jaunty, Karmic and Lucid).&lt;p&gt;To disable Compiz and enable Metacity, run these commands in a terminal window (without the &lt;code&gt;$&lt;/code&gt; signs):&lt;pre&gt;$ gconftool-2 --type=string --set \&lt;br /&gt;  /desktop/gnome/applications/window_manager/current /usr/bin/metacity&lt;br /&gt;$ gconftool-2 --type=string --set \&lt;br /&gt;  /desktop/gnome/applications/window_manager/default /usr/bin/metacity&lt;/pre&gt;&lt;p&gt;Logout and login again. Metacity should be running.&lt;p&gt;FYI the old setting was &lt;code&gt;/usr/bin/compiz&lt;/code&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-1545631803753727346?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/1545631803753727346/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=1545631803753727346' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1545631803753727346'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1545631803753727346'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/06/how-to-disable-compiz-fusion-and-enable.html' title='How to disable Compiz Fusion and enable Metacity on Ubuntu Karmic'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-4393205634303090601</id><published>2010-06-02T20:48:00.001+02:00</published><updated>2010-06-02T20:48:27.319+02:00</updated><title type='text'>How to add the VirtualBox keyring to Debian and Ubuntu</title><content type='html'>&lt;p&gt;This blog post explains how to add the Sun and Oracle VirtualBox keyring to Debian and Ubuntu, to prevent &lt;i&gt;apt-get update&lt;/i&gt; from complaining.&lt;p&gt;If &lt;i&gt;apt-get update&lt;/i&gt; gives you a warning with &lt;code&gt;NO_PUBKEY 54422A4B98AB5139&lt;/code&gt;, then do this to fix it:&lt;pre&gt;&lt;br /&gt;$ wget -q http://download.virtualbox.org/virtualbox/debian/sun_vbox.asc -O- |&lt;br /&gt;  sudo apt-key add -&lt;br /&gt;$ wget -q http://download.virtualbox.org/virtualbox/debian/oracle_vbox.asc -O- |&lt;br /&gt;  sudo apt-key add -&lt;br /&gt;$ sudo apt-get update&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-4393205634303090601?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/4393205634303090601/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=4393205634303090601' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/4393205634303090601'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/4393205634303090601'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/06/how-to-add-virtualbox-keyring-to-debian.html' title='How to add the VirtualBox keyring to Debian and Ubuntu'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-5832403816444957917</id><published>2010-05-29T20:49:00.005+02:00</published><updated>2011-01-22T10:11:43.748+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='planet-python'/><title type='text'>How to implement a semaphore using mutexes</title><content type='html'>&lt;p&gt;This blog post shows an educational reference implementation of a semaphore using mutexes in Python.&lt;p&gt;Please note that the number of mutexes needed in this implementation is 1 + the number of threads waiting in the &lt;i&gt;acquire&lt;/i&gt; operation while the value is 0. This is too much, 2 or 3 mutexes altogether would be enough, see the various implementations in &lt;a href="http://webhome.csc.uvic.ca/~mcheng/460/notes/gensem.pdf"&gt;Implementation of General Semaphores Using Binary Semaphores&lt;/a&gt;.&lt;p&gt;The implementation is available for download from &lt;a href="http://pts-mini-gpl.googlecode.com/svn/trunk/script/semaphore.py"&gt;http://pts-mini-gpl.googlecode.com/svn/trunk/script/semaphore.py&lt;/a&gt;.&lt;pre class="syntax"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Semaphore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;Semaphore initial value must be &amp;gt;= 0&amp;#39;&lt;/span&gt;&lt;br /&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocate_lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c"&gt;# Create a mutex.&lt;/span&gt;&lt;br /&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_waiters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blocking&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Semaphore P primitive.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;blocking&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class="k"&gt;break&lt;/span&gt;&lt;br /&gt;      &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;locked&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;wait() of un-acquire()d lock&amp;#39;&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;waiter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocate_lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;waiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;      &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_waiters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;waiter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;release&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;      &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c"&gt;# Restore state even if e.g. KeyboardInterrupt is raised.&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;waiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;      &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_value&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;br /&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;release&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Semaphore V primitive.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_value&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;locked&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;notify() of un-acquire()d lock&amp;#39;&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;_waiters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_waiters&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_waiters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;_waiters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;popleft&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;release&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;release&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Semaphore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;      &lt;span class="nb"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;release&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_new_thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;())&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;Press &amp;lt;Enter&amp;gt; twice to continue.&amp;#39;&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_value&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;Done.&amp;#39;&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-5832403816444957917?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/5832403816444957917/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=5832403816444957917' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/5832403816444957917'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/5832403816444957917'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/05/how-to-implement-semaphore-using.html' title='How to implement a semaphore using mutexes'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-2556379839454567181</id><published>2010-05-18T00:10:00.007+02:00</published><updated>2011-01-22T10:11:34.970+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='planet-python'/><title type='text'>Feature comparison of Python non-blocking I/O libraries</title><content type='html'>&lt;p&gt;This blog post is a tabular feature comparison of &lt;a href="http://code.google.com/p/syncless/"&gt;Syncless&lt;/a&gt; and the 6 most popular event-driven and coroutine-based non-blocking (asynchronous) networking I/O libraries for Python. It was inspired by &lt;a href="http://nichol.as/asynchronous-servers-in-python"&gt;http://nichol.as/asynchronous-servers-in-python&lt;/a&gt; (published on 2009-11-22), which compares the features and the performance of 14 Python non-blocking networking I/O libraries. We're not comparing generator-based (&lt;i&gt;yield&lt;/i&gt;) solutions here. We haven't made performance measurements, so speed-related claims in this comparison are beliefs and opinions rather than well-founded facts. Here are the results:&lt;table class=features&gt;&lt;thead&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td class=subject&gt;Concurrence&lt;/td&gt;&lt;td class=subject&gt;Eventlet&lt;/td&gt;&lt;td class=subject&gt;Tornado&lt;/td&gt;&lt;td class=subject&gt;Twisted&lt;/td&gt;&lt;td class=subject&gt;asyncore&lt;/td&gt;&lt;td class=subject&gt;gevent&lt;/td&gt;&lt;td class=subject&gt;circuits&lt;/td&gt;&lt;td class=subject&gt;Syncless&lt;/td&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;pure Python: can work without compiling C code&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;pure Python: runs at full speed without compiling C code&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;standard module in Python 2.6&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;has asynchronous DNS resolver&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment1"&gt;1)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment2"&gt;2)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment3"&gt;3)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment4"&gt;4)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;supports running other tasklets while DNS resolving is in progress&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;has fully asynchronous and scalable DNS resolver&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment5"&gt;5)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;supports timeouts on individual socket send() and recv() operations&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;has WSGI server&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yesmm"&gt;yes--, &lt;a href="#comment6"&gt;6)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;can work with CherryPy's WSGI server&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yesmm"&gt;yes--, &lt;a href="#comment7"&gt;7)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yesmm"&gt;yes--, &lt;a href="#comment7"&gt;7)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;contains a custom, non-WSGI web framework&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject nopp"&gt;no++, &lt;a href="#comment8"&gt;8)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;can run external web frameworks using non-WSGI connectors&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment9"&gt;9)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yespp"&gt;yes++, &lt;a href="#comment10"&gt;10)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;runs with Stackless Python&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yesmm"&gt;yes--, &lt;a href="#comment11"&gt;11)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;runs with greenlet&lt;/td&gt;&lt;td class="subject yesmm"&gt;yes--, &lt;a href="#comment13"&gt;13)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;has fast non-blocking socket class implemented in C or Pyrex&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;has fast read and write buffer code implemented in C or Pyrex&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment14"&gt;14)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;uses fast (C or Pyrex) buffer code for its socket.socket.makefile()&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;uses fast (C or Pyrex) buffer code for its ssl.SSLSocket.makefile()&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment15"&gt;15)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;has SSL support&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment16"&gt;16)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment16"&gt;16)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment16"&gt;16)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment16"&gt;16)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment16"&gt;16)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;has monkey-patchig for socket.socket and other blocking I/O operations&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;prints and recovers from an uncaught exception&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment17"&gt;17)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment18"&gt;18)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment19"&gt;19)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;can use libevent&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;can use the libevent emulation of libev&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment20"&gt;20)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;works without libevent or an emulation installed&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;avoids C stack copying (which is slower than soft switching)&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment21"&gt;21)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment21"&gt;21)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment22"&gt;22)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;can use a high performance event notification primitive (e.g. epoll on Linux)&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment23"&gt;23)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment24"&gt;24)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment23"&gt;23)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment25"&gt;25)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;nichol.as: What license does the framework have?&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment26"&gt;26)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment26"&gt;26)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment27"&gt;27)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment26"&gt;26)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment26"&gt;26)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment26"&gt;26)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment28"&gt;28)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment29"&gt;29)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;nichol.as: Does it provide documentation?&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yespp"&gt;yes++, &lt;a href="#comment30"&gt;30)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yesmm"&gt;yes--, &lt;a href="#comment31"&gt;31)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;nichol.as: Does the documentation contain examples?&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;nichol.as: Is it used in production somewhere?&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment32"&gt;32)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment33"&gt;33)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment34"&gt;34)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment35"&gt;35)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment36"&gt;36)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment37"&gt;37)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;nichol.as: Does it have some sort of community (mailinglist, irc, etc..)?&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yespp"&gt;yes++, &lt;a href="#comment38"&gt;38)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;nichol.as: Is there any recent activity?&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment39"&gt;39)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;nichol.as: Does it have a blog (from the owner)?&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment40"&gt;40)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yespp"&gt;yes++, &lt;a href="#comment41"&gt;41)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yesmm"&gt;yes--, &lt;a href="#comment42"&gt;42)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;nichol.as: Does it have a Twitter account?&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yesmm"&gt;yes--, &lt;a href="#comment42"&gt;42)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;nichol.as: Where can I find the repository? (without links)&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment43"&gt;43)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment44"&gt;44)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment43"&gt;43)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment45"&gt;45)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment46"&gt;46)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment47"&gt;47)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment44"&gt;44)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment48"&gt;48)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;nichol.as: Does it have a thread pool?&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yesmm"&gt;yes--, &lt;a href="#comment49"&gt;49)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;nichol.as: Does it provide a HTTP server for WSGI applications?&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yesmm"&gt;yes--, &lt;a href="#comment50"&gt;50)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yesmm"&gt;yes--, &lt;a href="#comment6"&gt;6)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;nichol.as: Does it provide access to a TCP Socket?&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;nichol.as: Does it have any Comet features?&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;nichol.as: Is it using epoll, if available?&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment23"&gt;23)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment24"&gt;24)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment23"&gt;23)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject nopp"&gt;no++, &lt;a href="#comment51"&gt;51)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment25"&gt;25)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;nichol.as: Does it have unit tests?&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yespp"&gt;yes++, &lt;a href="#comment52"&gt;52)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment53"&gt;53)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;provides generic timeout for any block of code&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;provides synchronization primitives (e.g. semaphore, codition variable)&lt;/td&gt;&lt;td class="subject yesmm"&gt;yes--, &lt;a href="#comment54"&gt;54)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;lets the programmer control event delivery order (e.g. with priorities)&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;provides callbacks (links) when some work is finished&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;has a high-level, comprehensive, consistent network programming framework&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject yesmm"&gt;yes--, &lt;a href="#comment55"&gt;55)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment56"&gt;56)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yesmm"&gt;yes--, &lt;a href="#comment55"&gt;55)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;has non-blocking select.select() implementation&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment12"&gt;12)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;implements some application-level protocols beyond HTTP, WSGI and DNS&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment57"&gt;57)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject nopp"&gt;no++, &lt;a href="#comment58"&gt;58)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment59"&gt;59)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yespp"&gt;yes++, &lt;a href="#comment60"&gt;60)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no&lt;/td&gt;&lt;td class="subject nopp"&gt;no++, &lt;a href="#comment58"&gt;58)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment61"&gt;61)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject nopp"&gt;no++, &lt;a href="#comment62"&gt;62)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;compatible with other non-blocking systems in the same process&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment63"&gt;63)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment64"&gt;64)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment63"&gt;63)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yespp"&gt;yes++, &lt;a href="#comment65"&gt;65)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject no"&gt;no, &lt;a href="#comment63"&gt;63)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject nopp"&gt;no++, &lt;a href="#comment66"&gt;66)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yes"&gt;yes, &lt;a href="#comment67"&gt;67)&lt;/a&gt;&lt;/td&gt;&lt;td class="subject yespp"&gt;yes++, &lt;a href="#comment68"&gt;68)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Comments:&lt;br&gt;&lt;a name="comment1"&gt;&lt;b&gt;1)&lt;/b&gt;&lt;/a&gt; thread pool or Twisted&lt;br&gt;&lt;a name="comment2"&gt;&lt;b&gt;2)&lt;/b&gt;&lt;/a&gt; built-in&lt;br&gt;&lt;a name="comment3"&gt;&lt;b&gt;3)&lt;/b&gt;&lt;/a&gt; evdns&lt;br&gt;&lt;a name="comment4"&gt;&lt;b&gt;4)&lt;/b&gt;&lt;/a&gt; evdns or its equivalents: minihdns or evhdns&lt;br&gt;&lt;a name="comment5"&gt;&lt;b&gt;5)&lt;/b&gt;&lt;/a&gt; if Twisted is available&lt;br&gt;&lt;a name="comment6"&gt;&lt;b&gt;6)&lt;/b&gt;&lt;/a&gt; does not implement the WSGI spec properly (no write or close)&lt;br&gt;&lt;a name="comment7"&gt;&lt;b&gt;7)&lt;/b&gt;&lt;/a&gt; by manually monkey-patching socket and thread&lt;br&gt;&lt;a name="comment8"&gt;&lt;b&gt;8)&lt;/b&gt;&lt;/a&gt; has its own simple HTTPServer class&lt;br&gt;&lt;a name="comment9"&gt;&lt;b&gt;9)&lt;/b&gt;&lt;/a&gt; BaseHTTPServer&lt;br&gt;&lt;a name="comment10"&gt;&lt;b&gt;10)&lt;/b&gt;&lt;/a&gt; BaseHTTPServer, CherryPy, web.py, Google webapp&lt;br&gt;&lt;a name="comment11"&gt;&lt;b&gt;11)&lt;/b&gt;&lt;/a&gt; has partial, incomplete and incomatible greenlet emulation&lt;br&gt;&lt;a name="comment12"&gt;&lt;b&gt;12)&lt;/b&gt;&lt;/a&gt; event-driven&lt;br&gt;&lt;a name="comment13"&gt;&lt;b&gt;13)&lt;/b&gt;&lt;/a&gt; has partial and incompatible Stackless Python emulation&lt;br&gt;&lt;a name="comment14"&gt;&lt;b&gt;14)&lt;/b&gt;&lt;/a&gt; evbuffer&lt;br&gt;&lt;a name="comment15"&gt;&lt;b&gt;15)&lt;/b&gt;&lt;/a&gt; no SSL support&lt;br&gt;&lt;a name="comment16"&gt;&lt;b&gt;16)&lt;/b&gt;&lt;/a&gt; client and server&lt;br&gt;&lt;a name="comment17"&gt;&lt;b&gt;17)&lt;/b&gt;&lt;/a&gt; in the Tasklet class&lt;br&gt;&lt;a name="comment18"&gt;&lt;b&gt;18)&lt;/b&gt;&lt;/a&gt; sliently ignores exceptions and keeps the connection hanging&lt;br&gt;&lt;a name="comment19"&gt;&lt;b&gt;19)&lt;/b&gt;&lt;/a&gt; the process exits&lt;br&gt;&lt;a name="comment20"&gt;&lt;b&gt;20)&lt;/b&gt;&lt;/a&gt; needs evdns&lt;br&gt;&lt;a name="comment21"&gt;&lt;b&gt;21)&lt;/b&gt;&lt;/a&gt; uses greenlet&lt;br&gt;&lt;a name="comment22"&gt;&lt;b&gt;22)&lt;/b&gt;&lt;/a&gt; calls stackless.schedule() from C code&lt;br&gt;&lt;a name="comment23"&gt;&lt;b&gt;23)&lt;/b&gt;&lt;/a&gt; uses libevent&lt;br&gt;&lt;a name="comment24"&gt;&lt;b&gt;24)&lt;/b&gt;&lt;/a&gt; but uses poll and epoll could be added asily&lt;br&gt;&lt;a name="comment25"&gt;&lt;b&gt;25)&lt;/b&gt;&lt;/a&gt; can use libev or libevent&lt;br&gt;&lt;a name="comment26"&gt;&lt;b&gt;26)&lt;/b&gt;&lt;/a&gt; MIT&lt;br&gt;&lt;a name="comment27"&gt;&lt;b&gt;27)&lt;/b&gt;&lt;/a&gt; Apache&lt;br&gt;&lt;a name="comment28"&gt;&lt;b&gt;28)&lt;/b&gt;&lt;/a&gt; GNU GPL v2 or later&lt;br&gt;&lt;a name="comment29"&gt;&lt;b&gt;29)&lt;/b&gt;&lt;/a&gt; Apache License, Version 2.0&lt;br&gt;&lt;a name="comment30"&gt;&lt;b&gt;30)&lt;/b&gt;&lt;/a&gt; exensive&lt;br&gt;&lt;a name="comment31"&gt;&lt;b&gt;31)&lt;/b&gt;&lt;/a&gt; README and docstrings&lt;br&gt;&lt;a name="comment32"&gt;&lt;b&gt;32)&lt;/b&gt;&lt;/a&gt; Hyves.nl (a Dutch social networking site)&lt;br&gt;&lt;a name="comment33"&gt;&lt;b&gt;33)&lt;/b&gt;&lt;/a&gt; Second Life (a virtual reality game)&lt;br&gt;&lt;a name="comment34"&gt;&lt;b&gt;34)&lt;/b&gt;&lt;/a&gt; FriendFeed (a social networking site)&lt;br&gt;&lt;a name="comment35"&gt;&lt;b&gt;35)&lt;/b&gt;&lt;/a&gt; pyftpdlib, supervisor &lt;a href="http://supervisord.org/"&gt;[link]&lt;/a&gt; (via medusa)&lt;br&gt;&lt;a name="comment36"&gt;&lt;b&gt;36)&lt;/b&gt;&lt;/a&gt; many, &lt;a href="http://groups.google.com/group/gevent/browse_thread/thread/4de9703e5dca8271"&gt;[link]&lt;/a&gt; and &lt;a href="http://code.google.com/p/gevent/wiki/ProjectsUsingGevent"&gt;[link]&lt;/a&gt;&lt;br&gt;&lt;a name="comment37"&gt;&lt;b&gt;37)&lt;/b&gt;&lt;/a&gt; Naali, TAMS, website-profiler, kdb IRC bot, python-brisa uPnP&lt;br&gt;&lt;a name="comment38"&gt;&lt;b&gt;38)&lt;/b&gt;&lt;/a&gt; huge&lt;br&gt;&lt;a name="comment39"&gt;&lt;b&gt;39)&lt;/b&gt;&lt;/a&gt; not since 2009-11-19&lt;br&gt;&lt;a name="comment40"&gt;&lt;b&gt;40)&lt;/b&gt;&lt;/a&gt; at facebook&lt;br&gt;&lt;a name="comment41"&gt;&lt;b&gt;41)&lt;/b&gt;&lt;/a&gt; lots&lt;br&gt;&lt;a name="comment42"&gt;&lt;b&gt;42)&lt;/b&gt;&lt;/a&gt; the author writes Syncless-related stuff to his blog&lt;br&gt;&lt;a name="comment43"&gt;&lt;b&gt;43)&lt;/b&gt;&lt;/a&gt; GIT on github&lt;br&gt;&lt;a name="comment44"&gt;&lt;b&gt;44)&lt;/b&gt;&lt;/a&gt; Mercurial on bitbucket&lt;br&gt;&lt;a name="comment45"&gt;&lt;b&gt;45)&lt;/b&gt;&lt;/a&gt; in its own Subversion + Trac repository&lt;br&gt;&lt;a name="comment46"&gt;&lt;b&gt;46)&lt;/b&gt;&lt;/a&gt; in Python's Subversion&lt;br&gt;&lt;a name="comment47"&gt;&lt;b&gt;47)&lt;/b&gt;&lt;/a&gt; Mercurial on bitbuckig&lt;br&gt;&lt;a name="comment48"&gt;&lt;b&gt;48)&lt;/b&gt;&lt;/a&gt; Subversion on Google Code&lt;br&gt;&lt;a name="comment49"&gt;&lt;b&gt;49)&lt;/b&gt;&lt;/a&gt; not tested in production for robustness and speed&lt;br&gt;&lt;a name="comment50"&gt;&lt;b&gt;50)&lt;/b&gt;&lt;/a&gt; limited&lt;br&gt;&lt;a name="comment51"&gt;&lt;b&gt;51)&lt;/b&gt;&lt;/a&gt; it can be enabled manually&lt;br&gt;&lt;a name="comment52"&gt;&lt;b&gt;52)&lt;/b&gt;&lt;/a&gt; extensive&lt;br&gt;&lt;a name="comment53"&gt;&lt;b&gt;53)&lt;/b&gt;&lt;/a&gt; unit tests cover only parts of the functionality&lt;br&gt;&lt;a name="comment54"&gt;&lt;b&gt;54)&lt;/b&gt;&lt;/a&gt; provides queues&lt;br&gt;&lt;a name="comment55"&gt;&lt;b&gt;55)&lt;/b&gt;&lt;/a&gt; not comprehensive&lt;br&gt;&lt;a name="comment56"&gt;&lt;b&gt;56)&lt;/b&gt;&lt;/a&gt; low-level&lt;br&gt;&lt;a name="comment57"&gt;&lt;b&gt;57)&lt;/b&gt;&lt;/a&gt; MySQL client&lt;br&gt;&lt;a name="comment58"&gt;&lt;b&gt;58)&lt;/b&gt;&lt;/a&gt; Python console backdoor, can monkey-patch external modules&lt;br&gt;&lt;a name="comment59"&gt;&lt;b&gt;59)&lt;/b&gt;&lt;/a&gt; storage server compatible with Amazon S3; OpenID&lt;br&gt;&lt;a name="comment60"&gt;&lt;b&gt;60)&lt;/b&gt;&lt;/a&gt; tons of protocols&lt;br&gt;&lt;a name="comment61"&gt;&lt;b&gt;61)&lt;/b&gt;&lt;/a&gt; pygame, GTK+, inotify and pygame&lt;br&gt;&lt;a name="comment62"&gt;&lt;b&gt;62)&lt;/b&gt;&lt;/a&gt; can monkey-patch external modules&lt;br&gt;&lt;a name="comment63"&gt;&lt;b&gt;63)&lt;/b&gt;&lt;/a&gt; not by default&lt;br&gt;&lt;a name="comment64"&gt;&lt;b&gt;64)&lt;/b&gt;&lt;/a&gt; has Twisted reactor&lt;br&gt;&lt;a name="comment65"&gt;&lt;b&gt;65)&lt;/b&gt;&lt;/a&gt; many including GTK+ and Qt&lt;br&gt;&lt;a name="comment66"&gt;&lt;b&gt;66)&lt;/b&gt;&lt;/a&gt; not by default, but there is the project gTornado&lt;br&gt;&lt;a name="comment67"&gt;&lt;b&gt;67)&lt;/b&gt;&lt;/a&gt; pygame and GTK&lt;br&gt;&lt;a name="comment68"&gt;&lt;b&gt;68)&lt;/b&gt;&lt;/a&gt; has monkey-patching for Concurrence, Eventlet, Tornado, Twisted, gevent, circuits and asyncore&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-2556379839454567181?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/2556379839454567181/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=2556379839454567181' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2556379839454567181'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2556379839454567181'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/05/feature-comparison-of-python-non.html' title='Feature comparison of Python non-blocking I/O libraries'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-1078057713974645724</id><published>2010-04-29T17:23:00.001+02:00</published><updated>2011-01-22T10:11:21.791+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='planet-python'/><title type='text'>Google Code Data API</title><content type='html'>&lt;p&gt;This blog post documents the options for programmatic (non-web-browser) access to open source project hosting at Google Code.&lt;p&gt;As of 2010-04-29, there is no full Google Code Data API, but there is an &lt;a href="http://code.google.com/p/support/wiki/ScriptedUploads"&gt;API for uploading files&lt;/a&gt; and an &lt;a href="http://code.google.com/p/support/wiki/IssueTrackerAPI"&gt;API for the issue tracker&lt;/a&gt;.&lt;p&gt;For uploading files, the following scripts can be useful:&lt;ul&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/support/source/browse/trunk/scripts/googlecode_upload.py"&gt;Python command-line script for uploading files&lt;/a&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/support/source/browse/trunk/scripts/googlecode_distutils_upload.py"&gt;Python distutils command for uploading source and binary distributions from setup.py&lt;/a&gt;&lt;li&gt;&lt;a href="http://github.com/fayland/google-code-upload/blob/master/lib/Google/Code/Upload.pm"&gt;Perl module for uploading files&lt;/a&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-1078057713974645724?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/1078057713974645724/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=1078057713974645724' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1078057713974645724'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1078057713974645724'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/04/google-code-data-api.html' title='Google Code Data API'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-7644746823549978564</id><published>2010-04-19T05:21:00.001+02:00</published><updated>2011-01-22T10:11:13.365+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='planet-python'/><title type='text'>Syncless: Non-blocking WSGI server and networking library for Stackless Python</title><content type='html'>&lt;p&gt;This blog post is a release announcement of the software named Syncless I've been developing recently for high-performance, low-memory, single-process, single-threaded, lock-free network communication (TCP/IP client and server) in Python, using coroutines for apperent parallel processing. I needed something which needs less memory than pre-forking worker instances, but doesn't require complicated and error-prone synchronization mechanisms (such as mutexes in a multi-threaded program).&lt;p&gt;&lt;a href="http://code.google.com/p/syncless/"&gt;Syncless&lt;/a&gt; is an experimental, lightweight, non-blocking (asynchronous) client and server socket network communication library for Stackless Python 2.6. For high speed, Syncless uses libevent, and parts of Syncless' code is implemented in C (Pyrex). Thus Syncless can be faster than many other non-blocking Python communication libraries. Syncless contains an asynchronous DNS resolver (using evdns) and a HTTP server capable of serving WSGI applications. Syncless aims to be a coroutine-based alternative of event-driven networking engines (such as Twisted and FriendFeed's Tornado), and it's a competitor of gevent, pyevent, Eventlet and Concurrence. &lt;p&gt;Version 0.03 of Syncless has been released. It is a complete rewrite so it has drop-in replacements for built-in Python socket.socket, socket.gethostbyname (etc.), ssl.SSLSocket, time.sleep and select.select. The replacement implementations... is easily monkey-patchable, so legacy (blocking) pure Python I/O code can be made non-blocking without a code change. Core functionality is now written in Pyrex/Cython for greater speed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-7644746823549978564?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/7644746823549978564/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=7644746823549978564' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7644746823549978564'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/7644746823549978564'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/04/syncless-non-blocking-wsgi-server-and.html' title='Syncless: Non-blocking WSGI server and networking library for Stackless Python'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-2342539658256738655</id><published>2010-03-28T20:58:00.004+02:00</published><updated>2011-01-22T10:11:04.191+01:00</updated><title type='text'>Samsung Story Station Plus external e-SATA hard drive speed test on Linux</title><content type='html'>&lt;p&gt;This blog post shows the results of the speed test I've done with my new Samsung Story Station Plus external e-SATA hard drive on a Linux nettop. Executive summary: the drive is large, fast and quiet; e-SATA with hot-plug works fine and full speed on Ubuntu Hardy and Ubuntu Karmic out-of-the box.&lt;p&gt;Speed results:&lt;ul&gt;&lt;li&gt;sustained local hard drive sequential read: 53 MB/s; dd if=/dev/sda of=/dev/null bs=1M&lt;li&gt;sustained local hard drive sequential write: (not tried to avoid possible damage to the existing system)&lt;li&gt;sustained local hard drive random seek + read 4 KB: 50 seeks/s, 206 kB/s&lt;li&gt;sustained external e-SATA hard drive sequential read: 112 MB/s: dd if=/dev/sdb of=/dev/null bs=1M&lt;li&gt;sustained external e-SATA hard drive sequential write: 108 MB/s: dd if=/dev/zero of=/dev/sdb bs=1M seek=32000&lt;li&gt;sustained external e-SATA hard drive random seek + read 4 KB: 90 seeks/s, 370 kB/s&lt;/ul&gt;&lt;p&gt;System information:&lt;ul&gt;&lt;li&gt;Linux Ubuntu Hardy 64-bit desktop&lt;li&gt;dual Intel Atom 330 @ 1.60GHz&lt;li&gt;Nvidia ION&lt;li&gt;3.3GB RAM&lt;li&gt;internal hard drive: 2.5"; 250 GB; Hitachi HTS54322  FBEO&lt;li&gt;external e-SATA hard drive: Samsung Story Station Plus; 3.5"; 2TB; SAMSUNG HD203WI 1AN1&lt;li&gt;random seek benchmark implemented in Python, using 0.3% CPU&lt;/ul&gt;&lt;p&gt;Other parameters of the external drive:&lt;ul&gt;&lt;li&gt;very quiet, I was not able to tell when it's reading during thesequential read or write benchmarks&lt;li&gt;very quiet, I had to lean with my ear 5 cm from the drive to hear itworking during the random seek test in a work environment. However, at home, when there is no other noise, I can hear the seeks if I concentrate.&lt;li&gt;low-power (0.1 Watt in standby, goes to standby quickly).&lt;/ul&gt;&lt;p&gt;I've repeated the speed test with a Fujitsu Siemens Amilo 3560 notebook running Ubuntu Karmic 32-bit desktop, and the speeds are about the same as with the nettop.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-2342539658256738655?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/2342539658256738655/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=2342539658256738655' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2342539658256738655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2342539658256738655'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/03/samsung-story-station-plus-external-e.html' title='Samsung Story Station Plus external e-SATA hard drive speed test on Linux'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-1440588448890953309</id><published>2010-03-28T20:45:00.001+02:00</published><updated>2010-03-28T21:11:30.538+02:00</updated><title type='text'>How to cope with NIS (YP) server outages on Linux</title><content type='html'>&lt;p&gt;This blog post explains how to cope with &lt;a href="http://en.wikipedia.org/wiki/Network_Information_Service"&gt;NIS (YP)&lt;/a&gt; server outages on Linux (tested on Debian Lenny), i.e. how to give applications instant and valid response even when the NIS server is unreachable. When parts of the user (&lt;i&gt;passwd&lt;/i&gt;) and &lt;i&gt;group&lt;/i&gt; database is not stored locally, but on a NIS (YP) server, then each user and group lookup request (such as &lt;i&gt;getpwnam(3)&lt;/i&gt; and &lt;tt&gt;id USERNAME&lt;/tt&gt;) is sent to the NIS server. Should the NIS server be down or unreachable, each such request is blocked until a very long timeout (sometimes more than a minute). Also sometimes the client (ypbind) doesn't detect properly that the NIS server is back up again, so user lookups tend to fail or time out even when the NIS server has recovered. Another problem with communicating with the NIS server is that it's hard to write a strict firewall rule, because the UDP port number of the NIS service (&lt;i&gt;ypserv&lt;/i&gt;) is not fixed, but dynamically assigned and managed by the RPC &lt;i&gt;portmap&lt;/i&gt; service.&lt;p&gt;The solution presented here involves caching all NIS data locally, updating the cache from a cron job, and directing applications to always read the cache. This design gives instant response to applications, no matter whether the NIS server is reachable, and since cache updates are performed by a dedicated user, more precise firewall packet filters can be written. &lt;p&gt;The instructions below have been verified on Debian Lenny, but they should work similarly on other Linux systems. It is assumed that the NIS domain to connect to is called &lt;i&gt;mydomain&lt;/i&gt; (the real domain name usually available in &lt;tt&gt;/etc/domainname&lt;/tt&gt;), and the IP address of the NIS server is &lt;i&gt;1.2.3.4&lt;/i&gt;.&lt;ol&gt;&lt;li&gt;Make sure root can download the &lt;i&gt;passwd&lt;/i&gt; database from NIS. Try this command: &lt;tt&gt;# ypcat -d mydomain -h 1.2.3.4 passwd&lt;/tt&gt; This should print the the NIS user passwd database, including user names and (encrypted) passwords. If the 2nd field is &lt;code&gt;x&lt;/code&gt; for all users than the passwords may be in the shadow file on the NIS server. Try this: &lt;tt&gt;# ypcat -d mydomain -h 1.2.3.4 shadow&lt;/tt&gt; If this doesn't print any encrypted passwords, and you need password-based login on your machine for NIS users, then it wouldn't work for you (you may try complaining to the admin of the NIS server).&lt;li&gt;Install software (as root) to the client Linux system: &lt;tt&gt;# apt-get install sudo nis python2.4 libnss-extrausers&lt;/tt&gt;&lt;li&gt;Create a user named &lt;i&gt;nis-update&lt;/i&gt;: &lt;tt&gt;$ adduser --system --home=/tmp/blah --group nis-update&lt;/tt&gt;  (This disables login by default, and sets the user's login shell to &lt;tt&gt;/bin/false&lt;/tt&gt;.)&lt;li&gt;Make sure that the line in &lt;tt&gt;/etc/shadow&lt;/tt&gt; starting with &lt;tt&gt;nis-update:&lt;/tt&gt; starts with &lt;tt&gt;nis-update:*:&lt;/tt&gt; instead of &lt;tt&gt;nis-update-!:&lt;/tt&gt;. This disables login for that user.&lt;li&gt;If you have a firewall which restricts outgoing packets on the local machine, you may have to add these rules to allow the &lt;i&gt;nis-update&lt;/i&gt; user can download the NIS data:&lt;pre&gt;# Allow portmap.&lt;br /&gt;iptables -A OUTPUT -m owner --uid-owner nis-update \&lt;br /&gt;    -p tcp --dport 111 -d 1.2.3.4 -j ACCEPT&lt;br /&gt;# Allow all Sun RPC, including NIS (YP).&lt;br /&gt;iptables -A OUTPUT -m owner --uid-owner nis-update \&lt;br /&gt;    -p udp --dport 511:2999  -d 1.2.3.4 -j ACCEPT&lt;/pre&gt;&lt;li&gt;Make sure that the &lt;i&gt;nis-update&lt;/i&gt; user can download the &lt;i&gt;passwd&lt;/i&gt; database from NIS. Try that this command prints all user records: &lt;tt&gt;# sudo -c nis-update ypcat -d mydomain -h 1.2.3.4 passwd&lt;/tt&gt;&lt;li&gt;Add the following script as an executable &lt;tt&gt;/usr/local/sbin/nis-update.py&lt;/tt&gt;:&lt;pre class="syntax"&gt;&lt;span class="c"&gt;#! /usr/bin/python2.4&lt;/span&gt;&lt;br /&gt;&lt;span class="c"&gt;# by pts@fazekas.hu at Sun Mar 28 18:21:20 CEST 2010&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Script to download NIS (YP) users and groups for libnss_extrausers.so* .&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="sd"&gt;This script should be run from a cron job.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="sd"&gt;Please also check /etc/nsswitch.conf for libnss_extrausers.so* . It reads&lt;/span&gt;&lt;br /&gt;&lt;span class="sd"&gt;from /var/lib/extrausers/passwd etc.&lt;/span&gt;&lt;br /&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;__author__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;pts@fazekas.hu (Peter Szabo)&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pwd&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;signal&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;NIS_UPDATE_DOWNLOAD_DIR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;/var/cache/nis-update&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;NIS_UPDATE_COPY_TARGET_DIR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;/var/lib/extrausers&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;NIS_SERVER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;1.2.3.4&amp;#39;&lt;/span&gt;   &lt;span class="c"&gt;#### fix at install time&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;NIS_DOMAIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;mydomain&amp;#39;&lt;/span&gt;  &lt;span class="c"&gt;#### fix at install time&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;NisUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nis_filename&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;nis_filename&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;passwd&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;group&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;shadow&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;download_filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NIS_UPDATE_DOWNLOAD_DIR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nis_filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;target_filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NIS_UPDATE_COPY_TARGET_DIR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nis_filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;download_filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_WRONLY&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_TRUNC&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_CREAT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0644&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;euid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;geteuid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;euid&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;uid&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;euid&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;euid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;fdnull&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/dev/null&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_RDONLY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;fdnull&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dup2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fdnull&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fdnull&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dup2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;euid&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c"&gt;# It&amp;#39;s root&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setgroups&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setregid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setreuid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alarm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class="c"&gt;# This doesn&amp;#39;t need a running ypbind.&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/usr/bin/ypcat&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;ypcat&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;-d&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NIS_DOMAIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;-h&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NIS_SERVER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br /&gt;               &lt;span class="n"&gt;nis_filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;exc_info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exc_info&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;      &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;error in child: &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;br /&gt;         &lt;span class="n"&gt;exc_info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exc_info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;br /&gt;      &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;got_pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;waitpid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;got_pid&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;download_filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;st_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;warning: child &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt; failed with status 0x&lt;/span&gt;&lt;span class="si"&gt;%x&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;nis_filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;download_filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target_filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class="c"&gt;# Don&amp;#39;t print anything, we&amp;#39;re optimized for running as a cron job. &lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pwd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getpwnam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;nis-update&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;NisUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pw_uid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pw_gid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;passwd&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="n"&gt;NisUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pw_uid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pw_gid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;group&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="c"&gt;# TODO: Download and os.chmod the shadow file if necessary.&lt;/span&gt;&lt;/pre&gt;&lt;li&gt;In the script above, search for &lt;tt&gt;####&lt;/tt&gt;, and customize those settings.&lt;li&gt;As root, create the script output directories: &lt;tt&gt;# mkdir -p /var/cache/nis-update /var/lib/extrausers; chown root. /var/cache/nis-update /var/lib/extrausers; chmod 700 /var/cache/nis-update; chmod 755 /var/lib/extrausers&lt;/tt&gt;&lt;li&gt;Run the script as root: &lt;tt&gt;# /usr/local/sbin/nis-update.py&lt;/tt&gt; This should not print any error messages, and it should create the files /var/lib/extrausers/{passwd,group}&lt;/tt&gt;.&lt;li&gt;If you also need the shadow file (because it contains passwords), then modify the script so it creates that file as well.&lt;li&gt;Add the script to your crontab so it runs every 5 minutes: &lt;tt&gt;# echo '0-55/5 * * * * root /usr/local/sbin/nis-update.py' | sudo tee /etc/cron.d/nis-update&lt;/tt&gt;&lt;li&gt;Make sure that the &lt;i&gt;nss-extrausers&lt;/i&gt; pacakge is installed. (There was an instruction above.) &lt;tt&gt;# apt-get install nss-extrausers&lt;/tt&gt;&lt;li&gt;Edit &lt;tt&gt;/etc/nsswitch.conf&lt;/tt&gt;, and set the following values: &lt;pre&gt;passwd: files extrausers&lt;br /&gt;group: files extrausers&lt;br /&gt;shadow: files extrausers&lt;/pre&gt;(The previous values were probably &lt;tt&gt;compat&lt;/tt&gt; or &lt;tt&gt;files nis&lt;/tt&gt;.)&lt;li&gt;At this point, applications would use the cached files &lt;tt&gt;/var/lib/extrausers/{passwd,group}&lt;/tt&gt;. Test this by checking that &lt;tt&gt;$ perl -e 'while(@L=getpwent){print join("+",@L),"\n"}'&lt;/tt&gt; prints all local users followed by all NIS users.&lt;li&gt;Turn off the NIS client: &lt;tt&gt;# /etc/init.d/nis stop&lt;/tt&gt;&lt;li&gt;Run the check above again and make sure that all NIS users are present: &lt;tt&gt;$ perl -e 'while(@L=getpwent){print join("+",@L),"\n"}'&lt;/tt&gt;&lt;li&gt;Disable NIS client startup at boot time: &lt;tt&gt;# mv /etc/domainname{,.not}&lt;/tt&gt;&lt;li&gt;Occasionally check root's e-mail for error messages from the &lt;tt&gt;nis-update.py&lt;/tt&gt; cron job.&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-1440588448890953309?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/1440588448890953309/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=1440588448890953309' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1440588448890953309'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/1440588448890953309'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/03/how-to-cope-with-nis-yp-server-outages.html' title='How to cope with NIS (YP) server outages on Linux'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-8497653068849677337</id><published>2010-03-27T22:06:00.002+01:00</published><updated>2011-01-22T10:10:24.025+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='planet-python'/><title type='text'>Python web framework of the day</title><content type='html'>&lt;p&gt;Since there are quite a lot of &lt;a href="http://wiki.python.org/moin/WebFrameworks"&gt;web application frameworks for Python&lt;/a&gt;, I think one more wouldn't hurt.&lt;p&gt;I was impressed by the compactness of Ruby's &lt;a href="http://www.sinatrarb.com/intro.html"&gt;Sinatra&lt;/a&gt;:&lt;pre&gt;require 'rubygems'&lt;br /&gt;require 'sinatra'&lt;br /&gt;get '/' do&lt;br /&gt;  'Hello world!'&lt;br /&gt;end&lt;/pre&gt;&lt;p&gt;My goal was to create something similar for Python, as a proof-of-concept. Here is the equivalent &lt;i&gt;Hello, world&lt;/i&gt; web application with my Python syntax:&lt;pre&gt;from wfotd import *&lt;br /&gt;@GET&lt;br /&gt;def _():&lt;br /&gt;  return 'Hello world!'&lt;/pre&gt;&lt;p&gt;The Ruby solution looks much more clear and beautiful. Nevertheless, it was a nice Python coding experiment. I named it &lt;i&gt;PYthon Web Framework Of The Day&lt;/i&gt;. The source is available at &lt;a href="http://code.google.com/p/pts-mini-gpl/source/browse/#svn/trunk/pywfotd"&gt;http://code.google.com/p/pts-mini-gpl/source/browse/#svn/trunk/pywfotd&lt;/a&gt;.&lt;p&gt;Here is a larger Python example, demonstrating the scoping and argument passing features of pywfotd:&lt;pre&gt;from wfotd import *&lt;br /&gt;@GET&lt;br /&gt;def _(name=None):&lt;br /&gt;  name = name or 'World'&lt;br /&gt;  return 'Hello, %s!' % name&lt;br /&gt;&lt;br /&gt;@GET&lt;br /&gt;def foo():&lt;br /&gt;  return 'This is /foo'&lt;br /&gt;&lt;br /&gt;class bar:&lt;br /&gt;  class baz:&lt;br /&gt;    @GET&lt;br /&gt;    def _():&lt;br /&gt;      return 'This is /bar/baz'&lt;br /&gt;    @GET&lt;br /&gt;    def quux():&lt;br /&gt;      return 'This is /bar/baz/quux'&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-8497653068849677337?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/8497653068849677337/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=8497653068849677337' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/8497653068849677337'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/8497653068849677337'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/03/python-web-framework-of-day.html' title='Python web framework of the day'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-2627853710956016627</id><published>2010-02-20T11:26:00.001+01:00</published><updated>2010-06-06T14:04:38.344+02:00</updated><title type='text'>How to try the GDM login screen in many resolutions</title><content type='html'>&lt;p&gt;This blog post explains how to try the GDM login screen and make screen shots in any, user-specified screen resolution. This can be useful when designing GDM themes. The instructions were tried on Ubuntu Hardy (8.04), but they should work on Ubuntu Intrepid (8.10) and Ubuntu Jaunty (9.04). They won't work on Ubuntu Karmic or Ubuntu Lucid, because they contain GDM 2, which doesn't have the &lt;code&gt;--xnest&lt;/code&gt; feature implemented (&lt;code&gt;** (gdmflexiserver:18758): WARNING **: Not yet implemented&lt;/code&gt;).Installation instructions:&lt;ol&gt;&lt;li&gt;(When asked to run a command, run it in a terminal window.)&lt;li&gt;Make sure GDM is your display manager. Since GDM is the default, chances are that it is. To make sure, run &lt;tt&gt;sudo dpkg-reconfigure gdm&lt;/tt&gt;, and select GDM if it asks you.&lt;li&gt;Log in using GDM if you haven't already done so. To do that, run &lt;tt&gt;sudo /etc/init.d/gdm restart&lt;/tt&gt; . (You will lose your X11 session doing so.)&lt;li&gt;Install Xephyr, a modern nested (embedded) X server, similar to Xnest: &lt;tt&gt;sudo apt-get install xserver-xephyr&lt;/tt&gt;&lt;li&gt;Install ImageMagick for making screen shots in various image file formats: &lt;tt&gt;sudo apt-get install imagemagick&lt;/tt&gt;&lt;li&gt;Try Xephyr: &lt;tt&gt;Xephyr :9 -screen 800x600 -extension RANDR&lt;/tt&gt; . A new window should appear with the usual a black-and-white diagonal background and a diagonal cross-shaped cursor. Abort Xephyr in the terminal window. Try with different &lt;tt&gt;-screen&lt;/tt&gt; sizes.&lt;li&gt;Find your GDM Xnest command line by running &lt;tt&gt;grep ^Xnest= /etc/gdm/gdm.conf&lt;/tt&gt; . You should see something like &lt;tt&gt;Xnest=/usr/share/gdm/gdmXnestWrapper -br -audit 0&lt;/tt&gt;.&lt;li&gt;Create a new xnest wrapper script:&lt;pre&gt;echo '#!/bin/sh&lt;br /&gt;GEOMETRY="`cat /tmp/new-xnest-geometry`"&lt;br /&gt;GEOMETRY="${GEOMETRY:-800x600}"&lt;br /&gt;exec Xephyr "$@" -screen "$GEOMETRY" -extension RANDR' |&lt;br /&gt;sudo tee  /usr/local/sbin/gdm-xnest &amp;&amp;&lt;br /&gt;chmod 755 /usr/local/sbin/gdm-xnest&lt;/pre&gt;&lt;li&gt;Create the screenshot helper script: &lt;pre&gt;echo '#! /bin/bash --&lt;br /&gt;# by pts@fazekas.hu at Sat Feb 20 11:09:20 CET 2010&lt;br /&gt;GOT=($(ps x | perl -ne '\''if (/[ ]Xephyr :/) {&lt;br /&gt;  $c++;&lt;br /&gt;  print"$1 $2\n" if (/[ ]Xephyr :(\d+)(?= ).* -auth (\S+)/)}&lt;br /&gt;  END{die"Xephyr not found\n"if!$c;die"multiple Xephyrs found\n"if$c&amp;gt;1}'\''))&lt;br /&gt;test "$?" = 0 || exit "$?"&lt;br /&gt;if test ${#GOT} != 2; then&lt;br /&gt;  echo "Xephyr detection failed" &amp;gt;&amp;amp;2&lt;br /&gt;  exit 90&lt;br /&gt;fi&lt;br /&gt;export DISPLAY=":${GOT[0]}" XAUTHORITY="${GOT[1]}"&lt;br /&gt;exec import -window root "$@"' |&lt;br /&gt;sudo tee -a    /usr/local/bin/xephyr-import &amp;&amp;&lt;br /&gt;sudo chmod 755 /usr/local/bin/xephyr-import &lt;/pre&gt;&lt;li&gt;Change the &lt;tt&gt;Xrandr=&lt;/tt&gt; setting in &lt;tt&gt;/etc/gdm/gdm.conf&lt;/tt&gt; to use the new wrapper script: &lt;tt&gt;sudo perl -pi -0777 -e 's@^Xnest=.*@Xnest=/usr/local/sbin/gdm-xnest -br -audit 0@gm' /etc/gdm/gdm.conf&lt;/tt&gt;&lt;li&gt;Make sure the &lt;tt&gt;Xrandr=&lt;/tt&gt; setting is changed: check that running &lt;tt&gt;grep ^Xnest= /etc/gdm/gdm.conf&lt;/tt&gt; displays &lt;tt&gt;Xnest=/usr/local/sbin/gdm-xnest -br -audit 0&lt;/tt&gt;&lt;li&gt;Save your work in your X11 session, and restart GDM: &lt;tt&gt;sudo /etc/init.d/gdm restart&lt;/tt&gt; .  (You will lose your X11 session doing so.)&lt;/ol&gt;Usage instructions (how to show the GDM login dialog inside a window, and how to make a screen shot):&lt;ol&gt;&lt;li&gt;If not already logged in, login in at the GDM login screen.&lt;li&gt;Run &lt;tt&gt;gdmflexiserver --xnest&lt;/tt&gt; to get the GDM login dialog inside a window of your regular session. You can specify the window size using e.g. &lt;tt&gt;echo 1024x768 &gt;/tmp/new-xnest-geometry &amp;&amp; gdmflexiserver --xnest&lt;/tt&gt;&lt;li&gt;To make a JPEG screen shot, run &lt;tt&gt;xephyr-import -quality 75 screenshot.jpg&lt;/tt&gt; while the Xephyr window with the GDM login screen is still open.&lt;li&gt;To make a PNG screen shot, run &lt;tt&gt;xephyr-import screenshot.png&lt;/tt&gt; .&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8821846818714029393-2627853710956016627?l=ptspts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ptspts.blogspot.com/feeds/2627853710956016627/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8821846818714029393&amp;postID=2627853710956016627' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2627853710956016627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8821846818714029393/posts/default/2627853710956016627'/><link rel='alternate' type='text/html' href='http://ptspts.blogspot.com/2010/02/how-to-try-gdm-login-screen-in-many.html' title='How to try the GDM login screen in many resolutions'/><author><name>pts</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8821846818714029393.post-3183726638378708764</id><published>2010-02-19T01:01:00.006+01:00</published><updated>2010-11-16T20:07:32.664+01:00</updated><title type='text'>How to create a Debian/Ubuntu package (.deb) manually</title><content type='html'>&lt;p&gt;This blog post gives some hints how to create a &lt;tt&gt;.deb&lt;/tt&gt; package file (to be used with Debian, Ubuntu and similar Linux distributions). The intended audience is programmers and system administrators, both with a strong Debian or Ubuntu Linux background and strong scripting skills. It is assumed that you know almost everything about your Linux system, you have installed &lt;tt&gt;.deb&lt;/tt&gt; packages by hand (with &lt;i&gt;dpkg&lt;/i&gt;. and &lt;i&gt;apt-get&lt;/i&gt;), you understand the dependencies etc., and the only information you need how to create a &lt;tt&gt;.deb&lt;/tt&gt; package from your software.&lt;p&gt;This blog post describes a low-level, hacky and quick approach with little automatic validation and instrumentation. This approach is useful for packages which don't require compilation or complicated runtime configuration. To start learning the more consistent, heavy-weight, validated approaches, fetch some source packages with &lt;tt&gt;apt-get source&lt;/tt&gt;, and have a look at their &lt;tt&gt;debian&lt;/tt&gt; subdirectories. The merit of our approach is simplicity (you have to understand only a few basic concepts to create your first package) and speed. Disadvantages are that it lets you create suboptimal, nonworking or nonstandard packages since there is only very little automatic validation, so you may sometimes recognize problems with your &lt;tt&gt;.deb&lt;/tt&gt; packages too late, when it's too expensive to fix them; also this approach doesn't force you learn and follow the conventions and best practices of your Linux distribution.&lt;p&gt;First, have a look at the contents of &lt;tt&gt;.deb&lt;/tt&gt; packages similar to your software. To get the &lt;tt&gt;.deb&lt;/tt&gt; file, use &lt;tt&gt;apt-get install --reinstall ${PACKAGENAME}&lt;/tt&gt;, abort the process once all files are downloaded, and fetch the file you are interested in from &lt;tt&gt;/var/cache/apt/sources&lt;/tt&gt;. Once you have the &lt;tt&gt;.deb&lt;/tt&gt; file, extract it with &lt;i&gt;dpkg-deb&lt;/i&gt;:&lt;pre&gt;$ dpkg-deb -x .../${MYFILE}.deb /tmp/${MYFILE}&lt;br /&gt;$ dpkg-deb -e .../${MYFILE}.deb /tmp/${MYFILE}/DEBIAN&lt;/pre&gt;&lt;p&gt;Important text files are:&lt;ul&gt;&lt;li&gt;&lt;tt&gt;/tmp/${MYFILE}/DEBIAN/control&lt;/tt&gt;: all meta-information: package name, size, version number, dependencies, short description, long description&lt;li&gt;&lt;tt&gt;/tmp/${MYFILE}/DEBIAN/md5sums&lt;/tt&gt;: md5sum values for all regular files in the package&lt;li&gt;&lt;tt&gt;/tmp/${MYFILE}/DEBIAN/postinst&lt;/tt&gt;: executable script which will be run by &lt;tt&gt;dpkg -i&lt;/tt&gt; after dependencies are installed, and files of this package are extracted&lt;li&gt;&lt;tt&gt;/tmp/${MYFILE}/DEBIAN/preinst&lt;/tt&gt;: a similar executable script&lt;li&gt;&lt;tt&gt;/tmp/${MYFILE}/DEBIAN/prerm&lt;/tt&gt;: another similar executable script&lt;li&gt;&lt;tt&gt;/tmp/${MYFILE}/DEBIAN/postrm&lt;/tt&gt;: another similar executable script&lt;/ul&gt;&lt;p&gt;Use Google to find out more about these (and possibly other) special files. To get examples, look at the special files of the packages installed to your system; those special files are in  &lt;tt&gt;/var/lib/dpkg/info&lt;/tt&gt;.&lt;p&gt;Google is your friend. Search for &lt;a href="http://www.google.com/search?q=how+to+build+a+debian+package&amp;hl=en"&gt;how to build a debian package&lt;/a&gt;. The first two results I've found seem to be useful, I strongly recommend you read them: &lt;a href="http://tldp.org/HOWTO/html_single/Debian-Binary-Package-Building-HOWTO/"&gt;http://tldp.org/HOWTO/html_single/Debian-Binary-Package-Building-HOWTO/&lt;/a&gt;; &lt;a href="http://www.linuxfordevices.com/c/a/Linux-For-Devices-Articles/How-to-make-deb-packages/"&gt;http://www.linuxfordevices.com/c/a/Linux-For-Devices-Articles/How-to-make-deb-packages/&lt;/a&gt;. However, be prepared that some of the information you find is outdated or obsoleted. Always compare the instructions found on the web to what the packages of your distribution contain. Also be prepared that you don't find any definitive, comprehensive, up-to-date or useful documentation on a particular subtopic: learn from examples then.&lt;p&gt;Follow the these steps to create your &lt;tt&gt;.deb&lt;/tt&gt; package:&lt;ol&gt;&lt;li&gt;Learn everything you possible need to know, as indicated above. Learn primarily from examples (by examining some relevant packages on your Linux distribution).&lt;li&gt;Create a directory named &lt;tt&gt;${PACKAGENAME}_${VERSION}_${ARCHITECTURE}&lt;/tt&gt;. We'll call this the package directory.&lt;li&gt;Create subdirectories and files in the package directory. For example, if you want to have your package contain &lt;tt&gt;/usr/bin/footool&lt;/tt&gt;, then create &lt;tt&gt;usr&lt;/tt&gt;, create &lt;tt&gt;usr/bin&lt;/tt&gt; and copy your prebuilt &lt;tt&gt;footool&lt;/tt&gt; binary to &lt;tt&gt;usr/bin&lt;/tt&gt;.&lt;li&gt;Make sure the owner, group and permission bits are right (as intended on the target system) for all files and directories.&lt;li&gt;Create the &lt;tt&gt;DEBIAN&lt;/tt&gt; subdirectory in the package directory.&lt;li&gt;Create your &lt;tt&gt;DEBIAN/control&lt;/tt&gt; file, possibly copying a similar one, and modifying some fields.&lt;li&gt;If you need to run some code during installation after the package files are extracted to &lt;tt&gt;/&lt;/tt&gt;, then create &lt;tt&gt;DEBIAN/postinst&lt;/tt&gt; as a script (usually starting with &lt;tt&gt;#! /bin/sh&lt;/tt&gt;), and make it executable. To prevent future troubles, make this script robust and idempotent, i.e. it should exit successfully even after a previous half-finished package installation. However, if there is something wrong in the system, the script should exit with a non-zero exit code. &lt;tt&gt;set -e&lt;/tt&gt; can help here: it makes the shell running the script exit at the first nonsuccessful command (outside a subshell).&lt;li&gt;Compute md5sums by running &lt;tt&gt;md5sum `find . -type f | grep -v '^[.]/DEBIAN/'` &amp;gt;DEBIAN/md5sums&lt;/tt&gt; in the package directory.&lt;li&gt;Set the &lt;tt&gt;Installed-Size:&lt;/tt&gt; field of the &lt;tt&gt;DEBIAN/control&lt;/tt&gt; file to last number in the total output of &lt;tt&gt;du&lt;/tt&gt; run in the package directory.&lt;li&gt;Make sure that the package name, version number and architecture in the package directory name are the same is what's indicated in &lt;tt&gt;DEBIAN/control&lt;/tt&gt;.&lt;li&gt;Make sure there are no backup files (&lt;tt&gt;*~&lt;/tt&gt;, especially &lt;tt&gt;DEBIAN/*~&lt;/tt&gt;) or temporary files lying around inside the package directory.&lt;li&gt;Go one level above the package directory, and run &lt;tt&gt;dpkg-deb -b ${PACKAGENAME}_${VERSION}_${ARCHITECTURE}&lt;/tt&gt; . This creates &lt;tt&gt;${PACKAGENAME}_${VERSION}_${ARCHITECTURE}.deb&lt;/tt&gt;.&lt;li&gt;Your &lt;tt&gt;.deb&lt;/tt&gt; package is ready. Try installing it to your system (&lt;tt&gt;sudo dpkg -i ${PA
