<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Live aus der Marschrutka &#187; programming</title>
	<atom:link href="http://www.bluetwanger.de/blog/categories/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.bluetwanger.de/blog</link>
	<description>Markus Bertheau, Software developer</description>
	<lastBuildDate>Tue, 22 Sep 2009 05:27:24 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Mapping CapsLock to Escape in Xorg</title>
		<link>http://www.bluetwanger.de/blog/2007/05/12/mapping-capslock-to-escape-in-xorg/</link>
		<comments>http://www.bluetwanger.de/blog/2007/05/12/mapping-capslock-to-escape-in-xorg/#comments</comments>
		<pubDate>Fri, 11 May 2007 21:14:06 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[computer]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/2007/05/12/mapping-capslock-to-escape-in-xorg/</guid>
		<description><![CDATA[Ok, as I promised, here is how to map CapsLock to Escape in Xorg. This is especially useful for folks who use vim, as CapsLock in on the home row, and Escape is not. Actually escape is that far away that you have to have really long fingers in order to hit escape without moving [...]]]></description>
			<content:encoded><![CDATA[<p>Ok, as I <a href="http://blog.ryanak.ca/archives/14#comment-29">promised</a>, here is how to map CapsLock to Escape in Xorg. This is especially useful for folks who use vim, as CapsLock in on the home row, and Escape is not. Actually escape is that far away that you have to have really long fingers in order to hit escape without moving your hand from its usual position.</p>
<p style="font-size: 85%; margin-left: 20px">Paths and line numbers are given for Ubuntu 7.04 Feisty Fawn, so if you&#8217;re on another distribution or another version of Ubuntu, your mileage may vary.</p>
<p>What we&#8217;ll do is add an XkbOption to the keyboard configuration files. At first, add the following at the end of <tt>/usr/share/X11/xkb/symbols/capslock</tt>:</p>
<pre>
partial hidden modifier_keys
xkb_symbols "escape" {
    key &lt;CAPS&gt; {        [       Escape  ]       };
    key &lt;ESC&gt;  {        [       None    ]       };
};
</pre>
<p>This defines an option that maps the CAPS and ESC key codes to the Escape and None symbols respectively. If you don&#8217;t want to disable the original Escape key, leave the corresponding line out. Now let&#8217;s give it an option name: insert the following line to <tt>/usr/share/X11/xkb/rules/base</tt>, somewhere around line 810, where the other capslock lines are:</p>
<pre>
caps:escape          =       +capslock(escape)
</pre>
<p>Now let&#8217;s add that option to the keyboard configuration in <tt>/etc/X11/xorg.conf</tt>: Find the InputDevice section for the keyboard and add the following line to the section:</p>
<pre>
        Option          "XkbOptions"    "caps:escape"
</pre>
<p>Now restart X by logging out and typing Ctrl-Alt-Backspace at the login prompt. That&#8217;s it. CapsLock is gone and on its place Escape stood in.</p>
<p>I wasn&#8217;t successful in convincing <a href="http://www.advogato.org/person/svu/">the XKeyboardConfig maintainer Sergej Udaltsov</a> to accept a patch for this, but I attempted only once yet :)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2007/05/12/mapping-capslock-to-escape-in-xorg/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Correctly displaying russian MP3 ID3 tags in Muine</title>
		<link>http://www.bluetwanger.de/blog/2007/04/15/correctly-displaying-russian-mp3-id3-tags-in-muine/</link>
		<comments>http://www.bluetwanger.de/blog/2007/04/15/correctly-displaying-russian-mp3-id3-tags-in-muine/#comments</comments>
		<pubDate>Sat, 14 Apr 2007 19:26:01 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[computer]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/2007/04/15/correctly-displaying-russian-mp3-id3-tags-in-muine/</guid>
		<description><![CDATA[Although I&#8217;m from Germany, I live in Novosibirsk at the moment. Novosibirsk is in Russia, so I listen to russian music. The player I use is muine. Unfortunately the artist and title information looks like this: 
The reason is that windows software that adds meta tags to music files uses the default russian 8-bit encoding [...]]]></description>
			<content:encoded><![CDATA[<p>Although I&#8217;m from Germany, I live in Novosibirsk at the moment. Novosibirsk is in Russia, so I listen to russian music. The player I use is <a href="http://muine-project.org">muine</a>. Unfortunately the artist and title information looks like this: <img src="http://www.bluetwanger.de/blog/wp-content/uploads/2007/04/muine-before.png"/></p>
<p>The reason is that windows software that adds meta tags to music files uses the default russian 8-bit encoding CP1251. All ID3 versions except for the newest ones only allow ISO-8859-1 as the tag encoding. So muine, according to the standard, interprets the tags in ISO-8859-1. Let&#8217;s change that.</p>
<p>I&#8217;m using Ubuntu 6.10. Let&#8217;s have a look at the muine sources:</p>
<pre>~/src/deb$ apt-get install build-essential
~/src/deb$ apt-get source muine
...
dpkg-source: extracting muine in muine-0.8.5
dpkg-source: unpacking muine_0.8.5.orig.tar.gz
dpkg-source: applying ./muine_0.8.5-1ubuntu4.diff.gz
~/src/deb$ cd muine-0.8.5/
~/src/deb/muine-0.8.5$ ls src/
...
AddWindowEntry.cs             DndUtils.cs      Metadata.cs          SkipToWindow.cs
...
</pre>
<p>The file Metadata.cs looks like it&#8217;s responsible for the ID3 tags. Searching it for title shows the following lines:</p>
<pre>
                // Properties :: Title (get;)
                [DllImport ("libmuine")]
                private static extern IntPtr metadata_get_title (IntPtr metadata);
</pre>
<p><tt>DllImport</tt> imports a binary library file. The next line declares a function <tt>metadata_get_title</tt> which is implemented in libmuine. Let&#8217;s look at that.</p>
<pre>
~/src/deb/muine-0.8.5$ ls libmuine/
...
gsequence.c  metadata.c   player-gst-0.8.c  rb-cell-renderer-pixbuf.c
...
</pre>
<p>Searching for <tt>title</tt> in <tt>metadata.c</tt> gives us the following line:</p>
<pre>
        metadata->title = get_mp3_comment_value (tag, ID3_FRAME_TITLE, 0);
</pre>
<p>Which leads us to <tt>get_mp3_comment_value</tt>. Let&#8217;s look at its definition:</p>
<pre>
get_mp3_comment_value (struct id3_tag *tag,
                       const char *field_name,
                       int index)
{
...
        frame = id3_tag_findframe (tag, field_name, 0);
...
        field = id3_frame_field (frame, 1);
...
        ucs4 = id3_field_getstrings (field, index);
...
        utf8 = id3_ucs4_utf8duplicate (ucs4);
...
}
</pre>
<p><tt>get_mp3_comment_value</tt> calls a lot of functions the name of which starts with id3. The functions are not defined in <tt>metadata.c</tt>. They aren&#8217;t defined anywhere in the muine source code:</p>
<pre>
~/src/deb/muine-0.8.5$ grep -r id3_field_getstrings .
./libmuine/metadata.c:  latin1 = id3_ucs4_latin1duplicate (id3_field_getstrings (field, 0));
./libmuine/metadata.c:  ucs4 = id3_field_getstrings (field, index);
</pre>
<p>Only calls to that function. In <tt>metadata.c</tt> there&#8217;s an include statement that includes <tt>id3tag.h</tt>. Looks like what we need. Let&#8217;s download the source for the corresponding library:</p>
<pre>
~/src/deb/muine-0.8.5$ apt-cache search id3tag
libid3tag0 - ID3 tag reading library from the MAD project
libid3tag0-dev - ID3 tag reading library from the MAD project
mp3rename - Rename mp3 files based on id3tags
somaplayer - player audio for the soma suite
~/src/deb/muine-0.8.5$ cd ..
~/src/deb$ apt-get source libid3tag0
...
dpkg-source: extracting libid3tag in libid3tag-0.15.1b
dpkg-source: unpacking libid3tag_0.15.1b.orig.tar.gz
dpkg-source: applying ./libid3tag_0.15.1b-8.diff.gz
~/src/deb$ cd libid3tag-0.15.1b/
~/src/deb/libid3tag-0.15.1b$ grep -r id3_field_getstrings .
...
./field.c:id3_ucs4_t const *id3_field_getstrings(union id3_field const *field,
...
</pre>
<p>The function is defined in <tt>field.c</tt>. It accesses an array <tt>stringlist</tt>. That array is filled in the function <tt>id3_field_parse</tt>. This function calls another function, <tt>id3_parse_string</tt> that extracts the string values of a field.</p>
<pre>
~/src/deb/libid3tag-0.15.1b$ grep -r id3_parse_string *
parse.c:id3_ucs4_t *id3_parse_string(id3_byte_t const **ptr, id3_length_t length,
parse.h:id3_ucs4_t *id3_parse_string(id3_byte_t const **, id3_length_t,
</pre>
<p>This function is defined in <tt>parse.c</tt>. For ISO-8859-1 fields it calls <tt>id3_latin1_deserialize</tt>.</p>
<pre>
~/src/deb/libid3tag-0.15.1b$ grep -r id3_latin1_deserialize *
latin1.c:id3_ucs4_t *id3_latin1_deserialize(id3_byte_t const **ptr, id3_length_t length)
...
</pre>
<p><tt>id3_latin1_deserialize</tt> is defined in <tt>latin1.c</tt>. It calls <tt>id3_latin1_decode</tt> to convert the latin1 string to UCS-4, which in turn calls <tt>id3_latin1_decodechar</tt> to convert a single character. We&#8217;re there: we have found the place we have to change:</p>
<pre>
/*
 * NAME:        latin1->decodechar()
 * DESCRIPTION: decode a (single) latin1 char into a single ucs4 char
 */
id3_length_t id3_latin1_decodechar(id3_latin1_t const *latin1,
                                   id3_ucs4_t *ucs4)
{
  *ucs4 = *latin1;

  return 1;
}
</pre>
<p>The function is very simple: ISO-8859-1 is a subset of unicode, so only a direct assignment is needed. For CP1251 things are different. Looking at the <a href="http://en.wikipedia.org/wiki/CP1251">wikipedia page for CP1251</a>, we see that the letters of the russian alphabet start at 0xC0 with the upper case letters, followed by the lower case letters to 0xFF. Using gnome-character-map, we find that the corresponding unicode code points are U+0410 through U+044F and that the letters are in the same order. Very convenient. Let&#8217;s change the function to return the correct unicode values for the CP1251 letters 0xC0 through 0xFF:</p>
<pre>
id3_length_t id3_latin1_decodechar(id3_latin1_t const *latin1,
				   id3_ucs4_t *ucs4)
{
  if (*latin1 >= 0xc0)
    *ucs4 = 0x410 + (*latin1 - 0xc0);
  else
    *ucs4 = *latin1;

  return 1;
}
</pre>
<p>The unicode encoding used here, UCS-4, just packs the unicode code point in a 32 bit integer, so we can just directly assign the unicode value. Now on to compiling the changed libid3tag.</p>
<pre>
~/src/deb/libid3tag-0.15.1b$ sudo apt-get build-dep libid3tag0
...
~/src/deb/libid3tag-0.15.1b$ sudo apt-get install fakeroot
...
~/src/deb/libid3tag-0.15.1b$ fakeroot dpkg-buildpackage -uc -us
...
~/src/deb/libid3tag-0.15.1b$ sudo dpkg -i ../libid3tag0_0.15.1b-8_i386.deb
...
</pre>
<p>Now let&#8217;s delete the muine song database so that it re-reads the metadata.</p>
<pre>
~/src/deb/libid3tag-0.15.1b$ rm ~/.gnome2/muine/*
</pre>
<p>Start muine and import the music file:</p>
<p><img src="http://www.bluetwanger.de/blog/wp-content/uploads/2007/04/muine-after.png"/></p>
<p>Победа! :)</p>
<p><strong>Update:</strong> Added install of <tt>build-essential</tt> at the beginning.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2007/04/15/correctly-displaying-russian-mp3-id3-tags-in-muine/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>About subversion, ignored files, branches and switching between them</title>
		<link>http://www.bluetwanger.de/blog/2007/04/05/about-subversion-ignored-files-branches-and-switching-between-them/</link>
		<comments>http://www.bluetwanger.de/blog/2007/04/05/about-subversion-ignored-files-branches-and-switching-between-them/#comments</comments>
		<pubDate>Thu, 05 Apr 2007 04:33:29 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/2007/04/05/about-subversion-ignored-files-branches-and-switching-between-them/</guid>
		<description><![CDATA[In short: Before you switch between branches, delete all files that are ignored by subversion. If you don&#8217;t, you will receive errors like these:

svn: Won't delete locally modified directory '.'
svn: Left locally modified or unversioned files
svn status looks weird after such a failed switch:
markus@markus:/var/www/community$ svn status
!      .
    [...]]]></description>
			<content:encoded><![CDATA[<p>In short: Before you switch between branches, delete all files that are ignored by subversion. If you don&#8217;t, you will receive errors like these:</p>
<pre>
svn: Won't delete locally modified directory '.'
svn: Left locally modified or unversioned files</pre>
<p><tt>svn status</tt> looks weird after such a failed switch:</p>
<pre>markus@markus:/var/www/community$ svn status
!      .
    S  app
!   S  admin
!      admin/tmp
?      admin/tmp/cache/models
!      admin/tmp/cache
    S  sql
...
</pre>
<p>What&#8217;s going on? Let&#8217;s assume that I checked out a branch and want to switch to the trunk. In the branch a directory <tt>admin/tmp/cache/models</tt> was added and its svn:ignore was set to <tt>*</tt>, that is, all files inside that directory are ignored. Now there appeared files inside this directory. I issue the switch to branch command and got the above error message. That means, that there were some files inside models that are ignored by subversion. The switch operation deleted the <tt>.svn</tt> directory in <tt>admin/tmp/cache/models</tt> but didn&#8217;t remove the directory itself because it won&#8217;t delete files that it doesn&#8217;t control &#8211; specificially the ignored files in <tt>admin/tmp/cache/models</tt>. How to get out of that situation?</p>
<p>At first, switch back to where you were, i.e. to the branch. This will give you the following error:</p>
<pre>...
svn: Failed to add directory 'admin/tmp/cache/models': object of the same name already exists
</pre>
<p><tt>svn status</tt> looks much better now:</p>
<pre>markus@markus:/var/www/community$ svn status
!      .
!      admin
!      admin/tmp
?      admin/tmp/cache/models
!      admin/tmp/cache
</pre>
<p>Now delete the unversioned <tt>models</tt> directory and switch again to the branch:</p>
<pre>...
A    admin/tmp/cache/models
...
</pre>
<p>Now delete all ignored files by hand. To find out which files exist that are ignored, use <tt>svn status --no-ignore</tt>. Note that ignored files interfere with the switch <em>only if they are in a directory that exists only in the branch</em>. Now the switch to the trunk should work without a glitch.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2007/04/05/about-subversion-ignored-files-branches-and-switching-between-them/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL and UTF-8 &#8212; no more question marks!</title>
		<link>http://www.bluetwanger.de/blog/2006/11/20/mysql-and-utf-8-no-more-question-marks/</link>
		<comments>http://www.bluetwanger.de/blog/2006/11/20/mysql-and-utf-8-no-more-question-marks/#comments</comments>
		<pubDate>Mon, 20 Nov 2006 06:18:15 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/2006/11/20/mysql-and-utf-8-no-more-question-marks/</guid>
		<description><![CDATA[UTF-8, a Unicode encoding, is probably already the most used character encoding for new web applications, except maybe for Asia. The most popular open source database is MySQL. (But don&#8217;t miss the most advanced open source database, which I prefer.)
What do you need to do to have your database and web application be all UTF-8? [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://en.wikipedia.org/wiki/UTF-8">UTF-8</a>, a <a href="http://en.wikipedia.org/wiki/Unicode">Unicode</a> encoding, is probably already the most used character encoding for new web applications, except maybe for Asia. The most popular open source database is <a href="http://mysql.org/">MySQL</a>. (But don&#8217;t miss <a href="http://www.postgresql.org/">the most <em>advanced</em> open source database</a>, which I prefer.)</p>
<p>What do you need to do to have your <b>database and web application be all UTF-8</b>? MySQL offers a lot of places to configure character set (character encoding) and character collation (used for sorting and comparing text).</p>
<p>The most important rule is: <b>Don&#8217;t rely on server configuration</b> &#8211; you may not control it on the server you application will be running. When you write a web application that needs to run on a variety of operating systems and Linux distributions, all with their own default database configuration, you must make as little assumptions as possible about the system it will run on and its configuration. You may have configured <em>your</em> MySQL server to run your application correctly, but you may not have permission or the opportunity to reconfigure the MySQL server your application will run on. Fortunately you can specify all character set configuration in MySQL in places that you control: in the SQL scripts and the source code of your web application.</p>
<h2>Stored data</h2>
<p>One side of the problem is the data in the tables. If you control the CREATE DATABASE statement, you should specify the character set there:</p>
<pre>
CREATE DATABASE webapp
        DEFAULT CHARACTER SET utf8;
</pre>
<p>On some web hosts, web applications have to use the one database that came with the hosting. The database has already been created for you. In that case you have to specify the character set in the individual CREATE TABLE statements:</p>
<pre>
CREATE TABLE gadgets (
    name VARCHAR(255) PRIMARY KEY,
    rating INT
) DEFAULT CHARACTER SET utf8;
</pre>
<p>It doesn&#8217;t hurt to specify the character set in both locations. (Except you&#8217;re violating the <a href="http://www.artima.com/intv/dry.html"><abbr title="Don't repeat yourself">DRY</abbr> Principle</a>.) Now MySQL knows that the data in your tables is in UTF-8.</p>
<h2>Communication with the database</h2>
<p>The other side of the problem is the data that comes from and gets sent to the client. MySQL offers a lot of features here; you can have different character sets at almost every stage of data processing. To be all UTF-8, issue the following statement just after you&#8217;ve made the connection to the database server:</p>
<pre>
SET NAMES utf8;
</pre>
<p>This sets the <tt>character_set_client</tt>, <tt>character_set_connection</tt> and <tt>character_set_results</tt> variables to <tt>utf8</tt>. See below for the meaning of each of these variables.</p>
<p>Communication with the database also concerns SQL files you read with the MySQL command line client, or upload with phpMyAdmin. Put the statement at the top of every SQL file, like this:</p>
<pre>
SET NAMES utf8;
INSERT INTO TABLE gadgets (name, rating) VALUES ('iPod', 45);
</pre>
<p>If you&#8217;re talking to mysql from a command line that doesn&#8217;t understand UTF-8 (likely in Windows and older Linuxes), use the following statement to tell MySQL which character set you&#8217;re using on the client side:</p>
<pre>
SET CHARACTER SET cp1250;
</pre>
<p>This sets the <tt>character_set_client</tt> and <tt>character_set_results</tt> variables to <tt>cp1250</tt>. Upon arriving on the server, your data will be converted from CP1250 to UTF-8. Results returned to you will be converted from UTF-8 to CP1250.</p>
<h3>Which character set do you need for the command line?</h3>
<dl>
<dt><tt>utf8</tt></dt>
<dd>Modern Linux (Fedora, Ubuntu since 5.04, recent SuSE, recent Mandriva) for all languages. No need to issue a <tt>SET CHARACTER SET</tt> command here.</dd>
<dt><tt>latin1</tt></dt>
<dd>Western European Windows and Linux. English, Spanish, German, French, &#8230;</dd>
<dt><tt>cp1250</tt></dt>
<dd>Central European Windows. Polish, Czech, Slovak, Hungarian, Slovene, Croatian, Romanian, Albanian.</dd>
<dt><tt>latin2</tt></dt>
<dd>Central European Linux. Polish, Czech, Slovak, Hungarian, Slovene, Croatian, Romanian, Albanian.</dd>
<dt><tt>cp1251</tt></dt>
<dd>Cyrillic Windows. Russian, Ukrainian, Bulgarian, Belorussian, &#8230;</dd>
<dt><tt>koi8r</tt></dt>
<dd>Russian Linux.</dd>
<dt><tt>koi8u</tt></dt>
<dd>Ukrainian Linux.</dd>
<dt><tt>cp1256</tt></dt>
<dd>Arabic Windows.</dd>
<dt><tt>cp1257</tt></dt>
<dd>Baltic Windows. Estonian, Latvian, Lithuanian.</dd>
<dt><tt>latin7</tt></dt>
<dd>Baltic Linux. Estonian, Latvian, Lithuanian.</dd>
<dt><tt>latin5</tt></dt>
<dd>Turkish Linux.</dd>
</dl>
<h2>Character set and collation variables</h2>
<p>What do these <tt>character_set_*</tt> variables mean?</p>
<h3>Variables concerning communication</h3>
<dl>
<dt><tt>character_set_client</tt></dt>
<dd>This informs MySQL about the character set data from the client is encoded in.</dd>
<dt><tt>character_set_connection</tt></dt>
<dd>This is the character set MySQL converts incoming data to. It converts from <tt>character_set_client</tt>.</dd>
<dt><tt>character_set_result</tt></dt>
<dd>This is the character set MySQL converts outgoing data to. It converts from the character set specified for the data in the database / tables / columns.</dd>
</dl>
<h3>Variables concerning data storage</h3>
<dl>
<dt><tt>character_set_server</tt></dt>
<dd>The character set used for new databases if none is specified in the <tt>CREATE DATABASE</tt> statement. It can be set from the server configuration file, on the command line for <tt>mysqld</tt> and interactively in a database session.</dd>
<dt><tt>character_set_database</tt></dt>
<dd>The character set used for new tables if none is specified in the <tt>CREATE TABLE</tt> statement. It is set to <tt>character_set_server</tt> by default.</dd>
<dt><tt>character_set_system</tt></dt>
<dd>The character set for meta-data: database, table and column names. Its value is always <tt>utf8</tt>.</dd>
</dl>
<h2>Feedback</h2>
<p>Please leave a comment if this information was helpful to you. Also don&#8217;t hesitate to ask questions concerning the above. I&#8217;m not the best writer and some things are probably phrased incomprehensibly.</p>
<p>Last but not least I&#8217;m always interested in other topics concerning web programming that I could write about. What are you most interested in? What information do you need most?</p>
<h2>Links</h2>
<ul>
<li><a href="http://www.cl.cam.ac.uk/~mgk25/unicode.html">Unicode and UTF-8 FAQ for Unix/Linux by Markus Kuhn</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2006/11/20/mysql-and-utf-8-no-more-question-marks/feed/</wfw:commentRss>
		<slash:comments>31</slash:comments>
		</item>
		<item>
		<title>Productivity tip: use full screen mode instead of maximized mode</title>
		<link>http://www.bluetwanger.de/blog/2006/11/02/productivity-tip-use-full-screen-mode-instead-of-maximized-mode/</link>
		<comments>http://www.bluetwanger.de/blog/2006/11/02/productivity-tip-use-full-screen-mode-instead-of-maximized-mode/#comments</comments>
		<pubDate>Wed, 01 Nov 2006 18:49:03 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/2006/11/02/productivity-tip-use-full-screen-mode-instead-of-maximized-mode/</guid>
		<description><![CDATA[Since a few days I&#8217;ve been using vim in full screen mode, that is, the only thing on my screen is my editor. No panel, no task bar, no systray. It may be subjective, but I have the impression that without all the distractions, bells and whistles on my desktop, it is easier for me [...]]]></description>
			<content:encoded><![CDATA[<p>Since a few days I&#8217;ve been using vim in full screen mode, that is, the <emph>only</emph> thing on my screen is my editor. No panel, no task bar, no systray. It may be subjective, but I have the impression that without all the distractions, bells and whistles on my desktop, it is easier for me to concentrate on the task at hand. Compare</p>
<p class="image"><a href="http://www.bluetwanger.de/blog/wp-content/uploads/2006/11/fullscreen.png"><img src="http://www.bluetwanger.de/blog/wp-content/uploads/2006/11/fullscreen-small.png"/></a></p>
<p>to</p>
<p class="image"><a href="http://www.bluetwanger.de/blog/wp-content/uploads/2006/11/fullfullscreen.png"><img src="http://www.bluetwanger.de/blog/wp-content/uploads/2006/11/fullfullscreen-small.png"/></a></p>
<p>With metacity and GNOME, you can set for example Shift-Alt-Enter to toggle full screen mode. This is similar to Alt-Enter for toggling maximized mode, so it&#8217;s easy to remember:</p>
<p class="image"><img src="http://www.bluetwanger.de/blog/wp-content/uploads/2006/11/keyboard-shortcuts.png"/></p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2006/11/02/productivity-tip-use-full-screen-mode-instead-of-maximized-mode/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>This should never happen</title>
		<link>http://www.bluetwanger.de/blog/2006/10/05/this-should-never-happen/</link>
		<comments>http://www.bluetwanger.de/blog/2006/10/05/this-should-never-happen/#comments</comments>
		<pubDate>Thu, 05 Oct 2006 15:37:11 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/2006/10/05/this-should-never-happen/</guid>
		<description><![CDATA[Google Code Search was launched. Let&#8217;s listen to a soliloquy:
This is buggy, but I&#8217;ll fix it later. It&#8217;s also racy, but who cares, I don&#8217;t understand why, anyway. Let&#8217;s just hope that this will never happen. Or ?!?!
You can also search for buffer overflows.
]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.google.com/codesearch">Google Code Search</a> was launched. Let&#8217;s listen to a soliloquy:</p>
<p><a href="http://www.google.com/codesearch?hl=en&#038;lr=&#038;q=%22this+is+buggy%22&#038;btnG=Search">This is buggy</a>, but <a href="http://www.google.com/codesearch?hl=en&#038;lr=&#038;q=%22fix+this+later%22&#038;btnG=Search">I&#8217;ll fix it later</a>. <a href="http://www.google.com/codesearch?hl=en&#038;lr=&#038;q=%22this+is+racy%22&#038;btnG=Search">It&#8217;s also racy</a>, <a href="http://www.google.com/codesearch?hl=en&#038;lr=&#038;q=%22but+who+cares%22&#038;btnG=Search">but who cares</a>, <a href="http://www.google.com/codesearch?hl=en&#038;lr=&#038;q=%22I+don%27t+understand%22&#038;btnG=Search">I don&#8217;t understand</a> why, anyway. Let&#8217;s just <a href="http://www.google.com/codesearch?hl=en&#038;lr=&#038;q=%22never+happen%22+hope&#038;btnG=Search">hope that this will never happen</a>. Or <a href="http://www.google.com/codesearch?hl=en&#038;lr=&#038;q=%5C%3F%21%5C%3F%21&#038;btnG=Search">?!?!</a></p>
<p>You can also search for <a href="http://www.google.com/codesearch?hl=en&#038;lr=&#038;q=buffer+%22should+be+big+enough%22&#038;btnG=Search">buffer overflows</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2006/10/05/this-should-never-happen/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>No core dumps in Haskell?</title>
		<link>http://www.bluetwanger.de/blog/2006/10/04/no-core-dumps-in-haskell/</link>
		<comments>http://www.bluetwanger.de/blog/2006/10/04/no-core-dumps-in-haskell/#comments</comments>
		<pubDate>Tue, 03 Oct 2006 18:41:24 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/2006/10/04/no-core-dumps-in-haskell/</guid>
		<description><![CDATA[I read an interesting article about Haskell today, so I tried to learn a little Haskell. It&#8217;s a very interesting language. I installed hugs and started. On haskell.org you can read that Haskell means no core dumps. I got a core dump relatively fast. Here&#8217;s how:

Install hugs
Create an empty file foo.hs
start hugs


markus@katerina2:~/src/haskell$ touch foo.hs
markus@katerina2:~/src/haskell$ hugs
__ [...]]]></description>
			<content:encoded><![CDATA[<p>I read an interesting article about Haskell today, so I tried to learn a little Haskell. It&#8217;s a very interesting language. I installed <a href="http://www.haskell.org/hugs/">hugs</a> and started. On haskell.org you can read that <a href="http://www.haskell.org/haskellwiki/Introduction#3._No_core_dumps">Haskell means no core dumps</a>. I got a core dump relatively fast. Here&#8217;s how:</p>
<ul>
<li>Install hugs</li>
<li>Create an empty file foo.hs</li>
<li>start hugs</li>
</ul>
<pre>
markus@katerina2:~/src/haskell$ touch foo.hs
markus@katerina2:~/src/haskell$ hugs
__   __ __  __  ____   ___      _________________________________________
||   || ||  || ||  || ||__      Hugs 98: Based on the Haskell 98 standard
||___|| ||__|| ||__||  __||     Copyright (c) 1994-2005
||---||         ___||           World Wide Web: http://haskell.org/hugs
||   ||                         Report bugs to: hugs-bugs@haskell.org
||   || Version: 20050308       _________________________________________

Haskell 98 mode: Restart with command line option -98 to enable extensions

Type :? for help
Hugs.Base> :load foo.hs
Main> :edit
</pre>
<p><tt>:edit</tt> calls the editor with the last loaded file &#8211; here <tt>foo.hs</tt>. Put the following in the file:</p>
<pre>
times 1 x = x
times n x = times (n-1) x ++ x
</pre>
<p>This defines a function <tt>times</tt> which takes two arguments: one from which 1 can be subtracted and another one that can be concatenated with itself. Haskell infers this from how you use the parameters in the function. <tt>times</tt> concatenates its second argument n times with itself.</p>
<pre>
Main> times 2 [3]
[3,3]
Main> times 2 [42]
[42,42]
</pre>
<p>Now in order to produce the seg fault (or core dump) in hugs, you have to call <tt>times</tt> with a nonpositive number of times:</p>
<pre>
Main> times 0 [42]
Segmentation fault
</pre>
<p>Nothing earth-shattering, but I find it interesting to have found a possibility to crash Haskell in half an hour after reading about its core dump immunity.</p>
<p>This is meant humoristically, not as a rant. Take it with a grain of salt :)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2006/10/04/no-core-dumps-in-haskell/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Functional unit testing for web applications: Selenium Remote Control</title>
		<link>http://www.bluetwanger.de/blog/2006/09/14/functional-unit-testing-for-web-applications-selenium-remote-control/</link>
		<comments>http://www.bluetwanger.de/blog/2006/09/14/functional-unit-testing-for-web-applications-selenium-remote-control/#comments</comments>
		<pubDate>Thu, 14 Sep 2006 14:32:00 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/?p=4</guid>
		<description><![CDATA[Unit testing web applications is relatively hard, because you usually have quite a lot of layers: starting from the database, over PHP/Python/Ruby, the web server, the browser and HTML up to Javascript. Traditional unit testing hooks into the code at the PHP/Python/Ruby level. It does quite a good job at testing this layer of web [...]]]></description>
			<content:encoded><![CDATA[<p>Unit testing web applications is relatively hard, because you usually have quite a lot of layers: starting from the database, over PHP/Python/Ruby, the web server, the browser and HTML up to Javascript. Traditional unit testing hooks into the code at the PHP/Python/Ruby level. It does quite a good job at testing this layer of web applications. There also exist testing frameworks that allow you to <a href="http://jsunit.net/">unit test Javascript</a>. Alas, none of these solutions test the whole experience that the end user has. This is where functional unit testing comes into play.</p>
<p><a href="http://openqa.org">Selenium</a>, a framework that supports functional unit testing of web applications, simulates a user clicking links, filling out forms and submitting them. It can determine whether a blog post appeared in a list, after you used a form to submit it. It can test whether your AJAX screenname availability check works. It supports cookies. And all that because it runs directly in your browser. The Javascript that runs in your browser receives commands like &#8220;click the submit button&#8221; or &#8220;wait for the spinner to appear&#8221; or &#8220;make sure this error message didn&#8217;t appear on the page&#8221;.</p>
<p>Selenium comes in several flavours: one is Selenium Core, which runs directly and only in the browser. As a language for writing tests it supports only selenese, which can express only a simple sequence of actions and tests. This is of course too little for most web applications. But there&#8217;s a flavour of Selenium that can be integrated with traditional unit testing frameworks like <a href="http://www.lastcraft.com/simple_test.php">SimpleTest</a> (for PHP) and <a href="http://pyunit.sourceforge.net/">PyUnit</a>: Selenium Remote Control.</p>
<p>Selenium Remote Control is essentially a server written in Java with two functions: it acts as a proxy server for the browser and takes commands via HTTP that will be executed in the browser. The proxy server is needed because browsers rightfully don&#8217;t allow Javascript from one site to run on another site. Read <a href="http://openqa.org/selenium-rc/tutorial.html#sameorigin">Selenium Remote Control: The Same Origin Policy</a> if you&#8217;d like to know more.</p>
<p>Selenium Remote Control comes with client drivers for Python, Ruby, Perl and Java &#8211; a PHP client driver has not made it in the official release yet.</p>
<p>To start using Selenium Remote Control for doing functional tests of your web application, download the current release (<a href="http://openqa.org/selenium-rc/download.action">http://openqa.org/selenium-rc/download.action</a>), unpack it and start the server:</p>
<pre>wget <a href="http://release.openqa.org/selenium-remote-control/0.8.1/selenium-remote-control-0.8.1.zip">selenium-remote-control-0.8.1.zip</a>
unzip selenium-remote-control-0.8.1.zip
cd selenium-remote-control-0.8.1/server
java -jar selenium-server.jar</pre>
<p>This starts the two servers: the proxy server for the browser and the server that takes the commands. Then write a unit test case, using one of the client drivers provided in the archive. I&#8217;ll use Python here:</p>
<pre>mkdir functional-tests
cd functional-tests
cp path/to/selenium-remote-control-0.8.1/python/selenium.py .</pre>
<p>and put this in a file test-login.py</p>
<pre>import unittest

class LoginTest(unittest.TestCase):
seleniumHost = 'localhost'
seleniumPort = '4444'
browserStartCommand = '*firefox /usr/lib/firefox/firefox-bin'
browserURL = 'http://community'

def setUp(self):
self.selenium = selenium('localhost', '4444', '*firefox /usr/lib/firefox/firefox-bin', 'http://www.example.com')
self.selenium.start()

def tearDown(self):
self.selenium.stop()

def testLogin(self):
self.selenium.open("/login")
self.selenium.type("name=username", "john")
self.selenium.type("name=password", "johnspassword")
self.selenium.click("id=Submit")
self.selenium.wait_for_page_to_load(15000)
self.failUnless(self.selenium.is_text_present("Login successful"))

if __name__ == '__main__':
unittest.main()</pre>
<p>Then run</p>
<pre>python ./test-login.py</pre>
<p>and watch selenium opening a Firefox instance for you, loading the login page, typing username and password, submitting the form and finally checking for the message about successful login. After that Firefox is closed and PyUnit reports that the test ran successfully.</p>
<h3>Links</h3>
<ul>
<li><a href="http://blog.thinkphp.de/archives/133-Practical-Testing-PHP-Applications-with-Selenium.html">Practical Testing PHP Applications with Selenium</a></li>
<li><a href="http://www-128.ibm.com/developerworks/library/wa-selenium-ajax/">Automate acceptance tests with Selenium</a>: A detailed tutorial with real life examples</li>
<li><a href="http://phpblog.php-for-beginners.co.uk/2006/07/28/web-testing-your-apps-with-selenium-core/">Web Testing Your Apps with Selenium-Core</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2006/09/14/functional-unit-testing-for-web-applications-selenium-remote-control/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
