<?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</title>
	<atom:link href="http://www.bluetwanger.de/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.bluetwanger.de/blog</link>
	<description>Markus Bertheau, Software developer</description>
	<lastBuildDate>Tue, 05 Mar 2013 09:33:17 +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>Flash Media Server 3.5 on Ubuntu Linux</title>
		<link>http://www.bluetwanger.de/blog/2009/01/19/flash-media-server-35-on-ubuntu-linux/</link>
		<comments>http://www.bluetwanger.de/blog/2009/01/19/flash-media-server-35-on-ubuntu-linux/#comments</comments>
		<pubDate>Sun, 18 Jan 2009 18:11:13 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[computer]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/?p=36</guid>
		<description><![CDATA[Update September 13th 2009: Easier to use install script available.
I have been asked for a patch for installing Adobe Flash Media Server 3.5 on Ubuntu. Here it is, with instructions for Ubuntu 8.04.:
# install dependencies for Ubuntu 8.04
# please let me know what is needed on other versions of Ubuntu
sudo apt-get install libnspr4-0d libstdc++6

Now download [...]]]></description>
			<content:encoded><![CDATA[<p style="font-size: large"><strong>Update September 13th 2009:</strong> <a href="http://www.markusbe.com/2009/09/installing-flash-media-server-on-ubuntu-linux/">Easier to use install script available.</a></p>
<div style="text-decoration: line-through">I have been asked for a patch for installing Adobe Flash Media Server 3.5 on Ubuntu. Here it is, with instructions for Ubuntu 8.04.:</p>
<pre># install dependencies for Ubuntu 8.04
# please let me know what is needed on other versions of Ubuntu
sudo apt-get install libnspr4-0d libstdc++6
</pre>
<p>Now download <a href="http://download.macromedia.com/pub/flashmediaserver/fms_development/3_5/linux/FlashMediaServer3.5.tar.gz">Flash Media Server 3.5</a> and copy FlashMediaServer3.5.tar.gz over to your Ubuntu box. Don’t untar the .tar.gz file on windows and copy the files over to linux &#8211; this way file permissions will be wrong and the patch won’t work. Then</p>
<pre>tar xfz FlashMediaServer3.5.tar.gz
cd FMS_3_5_0_r405
wget http://www.bluetwanger.de/~mbertheau/<a href="http://www.bluetwanger.de/~mbertheau/flash-media-server-3.5-ubuntu.patch">flash-media-server-3.5-ubuntu.patch</a>
patch -p1 < flash-media-server-3.5-ubuntu.patch
sudo ./installFMS
</pre>
<p>If you get</p>
<pre>./installFMS: line 172: ./fmsini: No such file or directory

ERROR: You are running the Adobe Flash Media Server installer on the wrong platform.
</pre>
<p>then execute the following:</p>
<pre>sudo apt-get install ia32-libs
</pre>
<p>That will install 32bit support on your 64bit Ubuntu.</p>
<p>If you opted to install Apache and it doesn't work, execute the following if you are on 32 bit:</p>
<pre>sudo ln -s libexpat.so.1 /usr/lib/libexpat.so.0
</pre>
<p>If you are on 64 bit, execute this instead:</p>
<pre>sudo ln -s libexpat.so.1 /usr/lib32/libexpat.so.0
</pre>
<p>You can later uninstall the server:</p>
<pre>cd /opt/adobe/fms
sudo ./uninstallFMS
</pre>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2009/01/19/flash-media-server-35-on-ubuntu-linux/feed/</wfw:commentRss>
		<slash:comments>24</slash:comments>
		</item>
		<item>
		<title>Flash Media Server 3 on Ubuntu 7.10 Gutsy</title>
		<link>http://www.bluetwanger.de/blog/2008/02/11/flash-media-server-3-on-ubuntu-710-gutsy/</link>
		<comments>http://www.bluetwanger.de/blog/2008/02/11/flash-media-server-3-on-ubuntu-710-gutsy/#comments</comments>
		<pubDate>Sun, 10 Feb 2008 17:52:18 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[computer]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/2008/02/11/flash-media-server-3-on-ubuntu-710-gutsy/</guid>
		<description><![CDATA[Update September 13th 2009: Easier to use install script available.

Update January 31st 2009: Patch for Adobe Flash Media Server 3.5 on ubuntu available.
I have been asked for a patch for installing Adobe Flash Media Server 3 on Ubuntu. Here it is:

# install dependencies
sudo apt-get install libnspr4-dev

Now download Flash Media Server 3, unzip the file and [...]]]></description>
			<content:encoded><![CDATA[<p style="font-size: large"><strong>Update September 13th 2009:</strong> <a href="http://www.markusbe.com/2009/09/installing-flash-media-server-on-ubuntu-linux/">Easier to use install script available.</a></p>
<div style="text-decoration: line-through">
<p><strong>Update January 31st 2009:</strong> <a href="http://www.bluetwanger.de/blog/2009/01/19/flash-media-server-35-on-ubuntu-linux/">Patch for Adobe Flash Media Server 3.5 on ubuntu</a> available.</p>
<p>I have been <a href="http://www.bluetwanger.de/blog/2006/12/25/installing-flash-media-server-2-on-ubuntu-610-edgy/#comment-27811">asked</a> <a href="http://www.bluetwanger.de/blog/2006/12/25/installing-flash-media-server-2-on-ubuntu-610-edgy/#comment-28421">for</a> a patch for installing Adobe Flash Media Server 3 on Ubuntu. Here it is:
<pre>
# install dependencies
sudo apt-get install libnspr4-dev
</pre>
<p>Now <a href="http://www.adobe.com/go/tryflashmediaserver">download Flash Media Server 3</a>, unzip the file and copy <tt>FlashMediaServer3.tar.gz</tt> over to your Ubuntu box. Don&#8217;t untar the <tt>.tar.gz</tt> file on windows and copy the files over to linux &#8211; this way file permissions will be wrong and the patch won&#8217;t work. Then</p>
<pre>
tar xfz FlashMediaServer3.tar.gz
cd FMS_3_0_0_r1157
wget http://www.bluetwanger.de/~mbertheau/<a href="http://www.bluetwanger.de/~mbertheau/flash-media-server-3-ubuntu.patch">flash-media-server-3-ubuntu.patch</a>
patch -p1 &lt; flash-media-server-3-ubuntu.patch
sudo ./installFMS
</pre>
<p>You can later uninstall the server:</p>
<pre>
cd /opt/adobe/fms
sudo ./uninstallFMS
</pre>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2008/02/11/flash-media-server-3-on-ubuntu-710-gutsy/feed/</wfw:commentRss>
		<slash:comments>46</slash:comments>
		</item>
		<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>4</slash:comments>
		</item>
		<item>
		<title>Firefox custom search engine rant</title>
		<link>http://www.bluetwanger.de/blog/2007/05/11/firefox-custom-search-engine-rant/</link>
		<comments>http://www.bluetwanger.de/blog/2007/05/11/firefox-custom-search-engine-rant/#comments</comments>
		<pubDate>Thu, 10 May 2007 18:48:34 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[computer]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/2007/05/11/firefox-custom-search-engine-rant/</guid>
		<description><![CDATA[If it wasn&#8217;t for Vimperator, I would still be using Epiphany instead of Firefox. Compare how you create a custom search engine in both:
Epiphany

Create a bookmark of a result page of the search engine (Ctrl-D)
Replace the search term with %s in the URL

Firefox

Write up an XML file according to the OpenSearch spec
Figure out how to [...]]]></description>
			<content:encoded><![CDATA[<p>If it wasn&#8217;t for <a href="http://vimperator.mozdev.org">Vimperator</a>, I would still be using <a href="http://www.gnome.org/projects/epiphany/">Epiphany</a> instead of Firefox. Compare how you create a custom search engine in both:</p>
<h3>Epiphany</h3>
<ol>
<li>Create a bookmark of a result page of the search engine (Ctrl-D)</li>
<li>Replace the search term with <tt>%s</tt> in the URL</li>
</ol>
<h3>Firefox</h3>
<ol>
<li>Write up an XML file according to the <a href="http://developer.mozilla.org/en/docs/Creating_OpenSearch_plugins_for_Firefox">OpenSearch spec</a></li>
<li>Figure out how to load that file into Firefox</li>
<li>Figure out how to get that XML file right &#8211; Firefox just says that it doesn&#8217;t support this search engine</li>
<li>&#8230;</li>
</ol>
<p>End of rant.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2007/05/11/firefox-custom-search-engine-rant/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Host Networking with VirtualBox on Ubuntu 7.04 Feisty</title>
		<link>http://www.bluetwanger.de/blog/2007/04/30/host-networking-with-virtualbox-on-ubuntu-704-feisty/</link>
		<comments>http://www.bluetwanger.de/blog/2007/04/30/host-networking-with-virtualbox-on-ubuntu-704-feisty/#comments</comments>
		<pubDate>Mon, 30 Apr 2007 12:38:10 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[computer]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/2007/04/30/host-networking-with-virtualbox-on-ubuntu-704-feisty/</guid>
		<description><![CDATA[This post describes how to set up host networking for VirtualBox on Ubuntu 7.04 Feisty. The procedure probably works for older versions of Ubuntu.
The outcome of the procedure is that you&#8217;ll have a second network card for your virtual machine, which you can configure from inside the virtual machine as if it was a real [...]]]></description>
			<content:encoded><![CDATA[<p>This post describes how to set up host networking for <a href="http://virtualbox.org">VirtualBox</a> on Ubuntu 7.04 Feisty. The procedure probably works for older versions of Ubuntu.</p>
<p>The outcome of the procedure is that you&#8217;ll have a second network card for your virtual machine, which you can configure from inside the virtual machine as if it was a real network card connected to the same ethernet as your real network card.</p>
<p>I assume that you either</p>
<ul>
<li>get your IP address with <a href="http://en.wikipedia.org/wiki/DHCP">DHCP</a></li>
<li>or have a static IP address</li>
</ul>
<p>If you&#8217;re on DSL or cable modem with PPPoE you probably don&#8217;t want host networking, but NAT, which works out of the box.</p>
<p>We&#8217;re going to</p>
<ol>
<li>create a virtual network interface</li>
<li>set up an ethernet bridge</li>
<li>add your physical network interface and the virtual interfaces to the bridge</li>
</ol>
<h2>Preparations</h2>
<p>At first let&#8217;s install the needed software:</p>
<pre>$ sudo apt-get install bridge-utils uml-utilities</pre>
<p>The virtual network interface is configured with the package <tt>uml-utilities</tt>. uml stands for <a href="http://user-mode-linux.sourceforge.net/">User Mode Linux</a>, so understandably the package is preconfigured for use with User Mode Linux. In order to work correctly with VirtualBox, in <tt>/etc/network/if-pre-up.d/uml-utilities</tt> replace</p>
<pre>
chown root:uml-net /dev/net/tun
</pre>
<p>with</p>
<pre>
chown root:vboxusers /dev/net/tun
</pre>
<p>As we&#8217;re going to change the network configuration, we&#8217;re going to shut down the network. So don&#8217;t close this browser window :)</p>
<pre>
$ sudo /etc/init.d/networking stop
</pre>
<h2>Creating a Virtual Network Interface</h2>
<p>Now on to configuring the virtual network interface. Ubuntu and Debian store network configuration in the file <tt>/etc/network/interfaces</tt>. Assuming your network card is <tt>eth0</tt>, you&#8217;ll find a stanza beginning with the following in the file:</p>
<pre>
auto eth0
iface eth0 inet .....
</pre>
<p>Actually at install Ubuntu writes several such stanzas into the file so that they automatically work. Create a backup copy of <tt>/etc/network/interfaces</tt> (Now.) Then comment out all interfaces you don&#8217;t use so that NetworkManager doesn&#8217;t change the network configuration when we don&#8217;t want to. Leave in the <tt>lo</tt> interface, it&#8217;s required for local IP communication.</p>
<pre>
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet .....

#auto eth1
#iface eth1 inet dhcp

#auto ath0
#iface ath0 inet dhcp

#auto wlan0
#iface wlan0 inet dhcp
</pre>
<p>The next step is to create a virtual network interface. This is the network interface that will be used by the virtual machine. We don&#8217;t configure it &#8211; the virtual machine will do it. Add the following stanza under the <tt>lo</tt> interface:</p>
<pre>
auto tap0
iface tap0 inet manual
tunctl_user markus
uml_proxy_arp markus.mynetwork.loc
uml_proxy_ether eth0
</pre>
<p>Replace <tt>markus.mynetwork.loc</tt> with the host name or IP address you get from DHCP for your host machine (not the virtual machine). Also replace <tt>eth0</tt> with your real network interface, if that is not <tt>eth0</tt>, and <tt>markus</tt> with your user name on the system. The user name set here will be the only user with permission to work with the virtual network interface.</p>
<h4>Static IP address</h4>
<p>If you have a static IP address, replace <tt>markus.mynetwork.loc</tt> instead with your static IP address.</p>
<h2>Creating the bridge</h2>
<p>Now we&#8217;ll set up the bridge. Add the following stanza after the <tt>tap0</tt> stanza:</p>
<pre>
auto br0
iface br0 inet dhcp
bridge_ports eth0 tap0
bridge_maxwait 0
</pre>
<h4>Static IP address</h4>
<p>If you have a static IP address, you have to carry over the network settings from <tt>eth0</tt> to <tt>br0</tt>. Assuming your <tt>eth0</tt> stanza looks something like this:</p>
<pre>
auto eth0
iface eth0 inet static
address 192.168.1.2
netmask 255.255.255.0
gateway 192.168.1.254
</pre>
<p>change the <tt>br0</tt> stanza to look like this:</p>
<pre>
auto br0
iface br0 inet static
address 192.168.1.2
netmask 255.255.255.0
gateway 192.168.1.254
bridge_ports eth0 tap0
bridge_maxwait 0
</pre>
<p>In any case, change the stanza for <tt>eth0</tt> to the following:</p>
<pre>
auto eth0
iface eth0 inet manual
</pre>
<p>That&#8217;s it. Enable networking again:</p>
<pre>
$ sudo /etc/init.d/networking start
</pre>
<p>You can use <tt>ifconfig -a</tt> to see if all devices were correctly configured. You can now use host networking in VirtualBox. Enter <tt>tap0</tt> in the interface name field. The fields setup application and terminate application can be left empty.</p>
<h2>More than one virtual network interface</h2>
<p>You can run more than one OS at the same time and have all them use host networking. Add a <tt>tap</tt> interface for all of them. Here&#8217;s an example for three virtual network interfaces:</p>
<pre>
auto tap0
iface tap0 inet manual
tunctl_user markus
uml_proxy_arp markus.mynetwork.loc
uml_proxy_ether eth0

auto tap1
iface tap1 inet manual
tunctl_user markus
uml_proxy_arp markus.mynetwork.loc
uml_proxy_ether eth0

auto tap2
iface tap2 inet manual
tunctl_user markus
uml_proxy_arp markus.mynetwork.loc
uml_proxy_ether eth0

auto br0
iface br0 inet dhcp
bridge_ports eth0 tap0 tap1 tap2
bridge_maxwait 0
</pre>
<p>Have fun, and let me know if that post was helpful to you :)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2007/04/30/host-networking-with-virtualbox-on-ubuntu-704-feisty/feed/</wfw:commentRss>
		<slash:comments>46</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>Word boundaries for Ctrl-{Left,Right} in Firefox and other Gecko browsers</title>
		<link>http://www.bluetwanger.de/blog/2007/04/12/word-boundaries-for-ctrl-leftright-in-firefox-and-other-gecko-browsers/</link>
		<comments>http://www.bluetwanger.de/blog/2007/04/12/word-boundaries-for-ctrl-leftright-in-firefox-and-other-gecko-browsers/#comments</comments>
		<pubDate>Thu, 12 Apr 2007 08:27:01 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[computer]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/2007/04/12/word-boundaries-for-ctrl-leftright-in-firefox-and-other-gecko-browsers/</guid>
		<description><![CDATA[By default Gecko based browsers (Firefox, Epiphany) don&#8217;t take punctuation symbols for a word boundary. This means that when you navigate by-word in the URL bar, text inputs or text areas using Ctrl-Left, Ctrl-Right or Ctrl-Backspace, it moves right to the next resp. previous white space. I have found this to be inconvenient when editing [...]]]></description>
			<content:encoded><![CDATA[<p>By default <a href="http://wiki.mozilla.org/Gecko:Home_Page">Gecko</a> based browsers (Firefox, Epiphany) don&#8217;t take punctuation symbols for a word boundary. This means that when you navigate by-word in the URL bar, text inputs or text areas using Ctrl-Left, Ctrl-Right or Ctrl-Backspace, it moves right to the next resp. previous white space. I have found this to be inconvenient when editing URLs, or source code snippets in bug reports and in other places. Thanks to an entry <a href="http://mg.pov.lt/blog/unbreak-firefox-address-bar.html">Unbreaking Firefox&#8217;s address bar</a> from <a href="http://mg.pov.lt/">Marius Gedminas</a> I came to learn how to unbreak this behaviour: Search for <tt>punctuation</tt> in <a href="about:config">about:config</a>; Gecko finds <tt>layout.word_select.stop_at_punctuation</tt> which you need to set to true. More information in the blog post I linked to.</p>
<p>I can generally recommend <a href="http://mg.pov.lt/blog">Marius Gdeminas&#8217; blog</a>, I found quite a lot of interesting things in there, including a link to his <a href="http://mg.pov.lt/gtimelog/">GTimeLog</a>, <a href="http://mg.pov.lt/blog/bash-prompt.html">Bash prompts: showing the command in the window title</a>, <a href="http://mg.pov.lt/blog/xsel.html">xsel: the power of Unix</a>, &#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2007/04/12/word-boundaries-for-ctrl-leftright-in-firefox-and-other-gecko-browsers/feed/</wfw:commentRss>
		<slash:comments>0</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>Installing Flash Media Server 2 on Ubuntu 7.10 Gutsy, 7.04 Feisty and 6.10 Edgy</title>
		<link>http://www.bluetwanger.de/blog/2006/12/25/installing-flash-media-server-2-on-ubuntu-610-edgy/</link>
		<comments>http://www.bluetwanger.de/blog/2006/12/25/installing-flash-media-server-2-on-ubuntu-610-edgy/#comments</comments>
		<pubDate>Mon, 25 Dec 2006 14:02:18 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[computer]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/2006/12/25/installing-flash-media-server-2-on-ubuntu-610-edgy/</guid>
		<description><![CDATA[Update September 13th 2009: Easier to use install script available.

Update January 31st 2009: Patch for Adobe Flash Media Server 3.5 on ubuntu available.
Update February 11th 2008: Patch for Adobe Flash Media Server 3 on Ubuntu available.
The installation script for Flash Media Server 2 works only on RedHat Enterprise by default. With some modifications it works [...]]]></description>
			<content:encoded><![CDATA[<p style="font-size: large"><strong>Update September 13th 2009:</strong> <a href="http://www.markusbe.com/2009/09/installing-flash-media-server-on-ubuntu-linux/">Easier to use install script available.</a></p>
<div style="text-decoration: line-through">
<p><strong>Update January 31st 2009:</strong> <a href="http://www.bluetwanger.de/blog/2009/01/19/flash-media-server-35-on-ubuntu-linux/">Patch for Adobe Flash Media Server 3.5 on ubuntu</a> available.</p>
<p><strong>Update February 11th 2008:</strong> <a href="http://www.bluetwanger.de/blog/2008/02/11/flash-media-server-3-on-ubuntu-710-gutsy/">Patch for Adobe Flash Media Server 3 on Ubuntu</a> available.</p>
<p>The installation script for Flash Media Server 2 works only on RedHat Enterprise by default. With some <a href="http://www.bluetwanger.de/~mbertheau/fms.patch">modifications</a> it works fine on Ubuntu Gutsy, Feisty and Edgy. At first we need to install the dependencies:</p>
<pre>
# install dependencies
apt-get install libnspr4-dev libstdc++5 libstdc++5-3.3-dev
</pre>
<p>For older versions of Ubuntu (7.04 and 6.10) use:</p>
<pre>
# install dependencies
apt-get install libnspr4 libstdc++5 libstdc++5-3.3-dev
</pre>
<p>Then <a href="http://www.adobe.com/cfusion/tdrc/index.cfm?product=flashmediaserver">download FlashMediaServer2.tar.gz</a> and use the patch:</p>
<pre>
tar xfz FlashMediaServer2.tar.gz
cd FMS*
wget http://www.bluetwanger.de/~mbertheau/fms.patch
patch -p1 < fms.patch
sudo ./installFMS
</pre>
<p>You can later uninstall the server:</p>
<pre>
cd /opt/macromedia/fms
sudo ./uninstallFMS
</pre>
<p><strong>Update January 3rd 2007:</strong> Added installation of dependencies. Thanks to <a href="http://www.markontech.com">Mark Sullivan</a>.</p>
<p><strong>Update May 23rd 2007:</strong> Checked on feisty. Removed dead FMS download link.</p>
<p><strong>Update November 29th 2007:</strong> Adapted instructions for gutsy. Thanks to <a href="http://www.dwalbert.com/">Donavan</a>.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2006/12/25/installing-flash-media-server-2-on-ubuntu-610-edgy/feed/</wfw:commentRss>
		<slash:comments>44</slash:comments>
		</item>
		<item>
		<title>Polish</title>
		<link>http://www.bluetwanger.de/blog/2006/12/04/polish/</link>
		<comments>http://www.bluetwanger.de/blog/2006/12/04/polish/#comments</comments>
		<pubDate>Sun, 03 Dec 2006 17:05:35 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[life]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/2006/12/04/polish/</guid>
		<description><![CDATA[I started to learn Polish. Very interesting. As a start I did an &#8220;About me&#8221; page in Polish.
]]></description>
			<content:encoded><![CDATA[<p>I started to learn Polish. Very interesting. As a start I did an <a href="http://www.bluetwanger.de/blog/o-mnie/">&#8220;About me&#8221; page in Polish</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2006/12/04/polish/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>33</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>Learn a song text by heart in 15 minutes</title>
		<link>http://www.bluetwanger.de/blog/2006/10/10/learn-a-song-text-by-heart-in-15-minutes/</link>
		<comments>http://www.bluetwanger.de/blog/2006/10/10/learn-a-song-text-by-heart-in-15-minutes/#comments</comments>
		<pubDate>Mon, 09 Oct 2006 18:09:54 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[life]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/2006/10/10/learn-a-song-text-by-heart-in-15-minutes/</guid>
		<description><![CDATA[I have started to learn to play the guitar recently, and in order to play freely it&#8217;s beneficial to know song texts by heart. Having read about how people on various TV shows manage to remember a huge amount of information in a short time, I decided to try their methods to learn &#8220;Hotel California&#8221; [...]]]></description>
			<content:encoded><![CDATA[<p>I have started to learn to play the guitar recently, and in order to play freely it&#8217;s beneficial to know song texts by heart. Having read about how people on various TV shows manage to remember a huge amount of information in a short time, I decided to try their methods to learn &#8220;Hotel California&#8221; by the Eagles by heart.</p>
<p>The idea is to remember the text not word by word, but to remember just the key words in each line and build a mental story with these words. The story doesn&#8217;t have to be convincing or anything; it&#8217;s just a tool to help you remember. Do try this at home! I&#8217;ll offer my key words and my mental story for part of this song. I only had time for two stanzas:</p>
<p>(I won&#8217;t reproduce the whole text here as it&#8217;s probably copyrighted.)</p>
<p>highway<br/>hair<br/><a href="http://www.straightdope.com/classics/a5_001">colitas</a><br/>rising up<br/>distance<br/>shimmering light<br/>head heavy<br/>night<br/><br/>doorway<br/>mission bell<br/>thinking<br/>heaven hell<br/>candle<br/>show way<br/>voices<br/>heard<br/><br/>(refrain)<br/><br/>tiffany<br/>mercedes<br/>pretty<br/>friends<br/>dance<br/>sweet<br/>remember<br/>forget<br/><br/>captain<br/>wine<br/>spirits<br/>1969<br/>voices<br/>night<br/>say<br/></p>
<p>I wrote these words down from memory, about 14 hours after coming up with them in the <a href="http://en.wikipedia.org/wiki/Marshrutka">marshrutka</a> on my way to work. That took me about 15 minutes. Do repeat the text without looking at it after coming up with your words / story. After work I could recall everything. I now have more trouble remembering the 8 accords that you have to play in a stanza than the text :)</p>
<p>The scene (mental story) I imagine for second stanza goes like this: It&#8217;s a warm sunny day, some rich women went by car to a street cafe where she sits now. Because she&#8217;s rich, pretty guys desire her. She calls them friends, although these guys are only after her money. They dance for her in the courtyard, she finds that sweet and they sweat. It&#8217;s summer. Some of the guys dance well (to remember), some not so well (to forget). Then the first-person narrator calls the waiter (the captain is the waiter in my story) to ask him to bring him his wine. Wine contains alcohol &#8212; spirits. The waiter tells his story.</p>
<p>I don&#8217;t have a story for the last four lines, as they are pretty easy to remember by itself. The words were enough.</p>
<p>I encourage you to try this at home :)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2006/10/10/learn-a-song-text-by-heart-in-15-minutes/feed/</wfw:commentRss>
		<slash:comments>1</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>Jabber transports, or a tutorial on how to use ICQ with Gossip</title>
		<link>http://www.bluetwanger.de/blog/2006/09/24/jabber-transports-or-a-tutorial-on-how-to-use-icq-with-gossip/</link>
		<comments>http://www.bluetwanger.de/blog/2006/09/24/jabber-transports-or-a-tutorial-on-how-to-use-icq-with-gossip/#comments</comments>
		<pubDate>Sun, 24 Sep 2006 06:28:00 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[computer]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/?p=8</guid>
		<description><![CDATA[Update: It seems that this will soon be obsoleted &#8211; AOL, mother of ICQ, is adopting Jabber.
Gossip has been my favourite Jabber client for a long time. I like the simplicity and non-intrusiveness of its interface. But at work the standard IM network is ICQ. I&#8217;ve been using Gaim to connect to ICQ, but its [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Update:</strong> It seems that this will soon be obsoleted &#8211; <a href="http://florianjensen.com/2008/01/17/aol-adopting-xmpp-aka-jabber/">AOL, mother of ICQ, is adopting Jabber</a>.</p>
<p><a href="http://developer.imendio.com/projects/gossip">Gossip</a> has been my favourite Jabber client for a long time. I like the simplicity and non-intrusiveness of its interface. But at work the standard IM network is ICQ. I&#8217;ve been using <a href="http://gaim.sf.net">Gaim</a> to connect to ICQ, but its interface has always bugged me.</p>
<p>The Jabber protocol provides for so-called transports, which enable you to talk to other IM networks while using Jabber on the client side. Gossip doesn&#8217;t support transports. But although that sounds like a deal-breaker, it isn&#8217;t. Transports work like this: you register on a jabber server and then sign up for a transport, providing your ICQ credentials. Then your ICQ contacts are available through UIN@transport.jabber.example.com, for example. After signing up for the transport using a transport-supporting client, you can use any Jabber client you like, and that includes Gossip. All your ICQ contacts will appear on the new account, and you can add other ICQ accounts using UIN@transport.jabber.example.com.</p>
<p>Now step-by-step for Ubuntu Dapper users:</p>
<ol>
<li>Shut down Gossip.</li>
<li>Install gajim:
<ol>
<li>Applications -&gt; Add/Remove Software</li>
<li>check &#8220;show applications without tech support&#8221;</li>
<li>in the search field enter &#8220;gajim&#8221;</li>
<li>check gajim and click OK</li>
</ol>
</li>
<li>Start gajim through the Applications menu. It&#8217;s in &#8220;Internet&#8221;.</li>
<li>Add your existing jabber account to gajim.</li>
<li>Add a new account on a server that has a transport for ICQ (or whatever you need). I used jabber.freenet.de. This server has transports for AIM/ICQ, MSN, Yahoo, ICQv2 and IRC. You can see a list of accounts in Edit -&gt; Accounts -&gt; New -&gt; Forward.<img src="http://www.bluetwanger.de/gajim-servers.png" />
<p>Use the &#8220;Discover services&#8221; window to find out which transports are offered by a specific server.</p>
<p><img src="http://www.bluetwanger.de/gajim-transports.png" /></p>
<p>You can have both windows open at the same time.</li>
<li>Close the &#8220;Discover services&#8221; window and open it with your new jabber account.</li>
<li>Select the transport you want and click &#8220;Edit&#8221; or &#8220;Register&#8221;. You&#8217;ll be asked to provide the credentials for your ICQ/AIM/whatever account.<img src="http://www.bluetwanger.de/gajim-register-transport.png" /></li>
<li>Close gajim.</li>
<li>Start gossip and add your account on the new server.</li>
</ol>
<p>That&#8217;s it! All your ICQ contacts appear in Gossip. Add new ICQ contacts using UIN@icq.jabber.freenet.de (replace icq.jabber.freenet.de with the transport server you selected).</p>
<p><a href="http://digg.com/linux_unix/How_to_use_ICQ_with_Jabber_clients">Digg this</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2006/09/24/jabber-transports-or-a-tutorial-on-how-to-use-icq-with-gossip/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Epiphany: Automatic bookmark updating</title>
		<link>http://www.bluetwanger.de/blog/2006/09/23/epiphany-automatic-bookmark-updating/</link>
		<comments>http://www.bluetwanger.de/blog/2006/09/23/epiphany-automatic-bookmark-updating/#comments</comments>
		<pubDate>Sat, 23 Sep 2006 09:08:00 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[computer]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/?p=7</guid>
		<description><![CDATA[
The text says &#8220;Update bookmark &#8220;IEs 4 Linux &#8211; Internet Explorers for Linux &#8211; English Page&#8221;? The page has moved to the location http://www.tatanka.com.br/ies4linux/index-en.html. [Don't update] [Update].
When a web site is moved to a new address, it can use several ways to redirect visitors to the new address. If it&#8217;s a permanent move, the correct [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.bluetwanger.de/epiphany-respect.png"><img src="http://www.bluetwanger.de/epiphany-respect.png" alt="" border="0" /></a><br />
The text says &#8220;Update bookmark &#8220;IEs 4 Linux &#8211; Internet Explorers for Linux &#8211; English Page&#8221;? The page has moved to the location http://www.tatanka.com.br/ies4linux/index-en.html. [Don't update] [Update].<br />
When a web site is moved to a new address, it can use several ways to redirect visitors to the new address. If it&#8217;s a permanent move, the correct way is to send a <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.2">HTTP 301 Moved Permanently</a>. As it turns out, <a href="http://www.gnome.org/projects/epiphany/">Epiphany</a> notices such redirects and offers to update your bookmark, if you have bookmarked the site&#8217;s old location.<br />
I&#8217;m impressed. The developers of <a href="http://www.gnome.org/projects/epiphany/">Epiphany</a> really did their homework here.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2006/09/23/epiphany-automatic-bookmark-updating/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Challenge your mind in lucid dreams</title>
		<link>http://www.bluetwanger.de/blog/2006/09/17/challenge-your-mind-in-lucid-dreams/</link>
		<comments>http://www.bluetwanger.de/blog/2006/09/17/challenge-your-mind-in-lucid-dreams/#comments</comments>
		<pubDate>Sun, 17 Sep 2006 11:52:00 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[life]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/?p=6</guid>
		<description><![CDATA[Lucid dreams are dreams in which you are aware that you&#8217;re dreaming. Being able to control your actions allows for some interesting challenges. I specificially thought of two such challenges:

Find a computer, sit down in front of it and play Minesweeper.
Teleport yourself to a foreign country the language of which you don&#8217;t know and try [...]]]></description>
			<content:encoded><![CDATA[<p>Lucid dreams are dreams in which you are aware that you&#8217;re dreaming. Being able to control your actions allows for some interesting challenges. I specificially thought of two such challenges:</p>
<ul>
<li>Find a computer, sit down in front of it and play Minesweeper.</li>
<li>Teleport yourself to a foreign country the language of which you don&#8217;t know and try to understand the people, talk to them and write in their language.</li>
</ul>
<p>Playing Minesweeper is especially interesting: You play against yourself. Or rather your awareness observes how your ego in a dream plays against a computer that exists only in your ego&#8217;s dream. Try to catch your brain on making a logical mistake while you open more and more fields on the mine field.</p>
<p>I&#8217;ll add to this list as I think of more challenges. Leave your ideas for challenges in lucid dreams in the comments.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2006/09/17/challenge-your-mind-in-lucid-dreams/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Lucid dreaming: Recognizing something you&#8217;ve never seen before</title>
		<link>http://www.bluetwanger.de/blog/2006/09/17/lucid-dreaming-recognizing-something-youve-never-seen-before/</link>
		<comments>http://www.bluetwanger.de/blog/2006/09/17/lucid-dreaming-recognizing-something-youve-never-seen-before/#comments</comments>
		<pubDate>Sun, 17 Sep 2006 10:43:00 +0000</pubDate>
		<dc:creator>Markus Bertheau</dc:creator>
				<category><![CDATA[life]]></category>

		<guid isPermaLink="false">http://www.bluetwanger.de/blog/?p=5</guid>
		<description><![CDATA[I had a lucid dream today. I don&#8217;t remember everything, but I was walking through a German town (I&#8217;m from Berlin, Germany). When I realized that I was dreaming, I started to look around, fascinated by the degree of detail that the human brain is able to create in imagination. Being more interested in what [...]]]></description>
			<content:encoded><![CDATA[<p>I had a <a href="http://www.stevepavlina.com/blog/2005/04/learning-to-fly/">lucid dream</a> today. I don&#8217;t remember everything, but I was walking through a German town (I&#8217;m from Berlin, Germany). When I realized that I was dreaming, I started to look around, fascinated by the degree of detail that the human brain is able to create in imagination. Being more interested in what was happening, I started to lose the dream a few times, feeling my real body lying on the bed, sleeping, or rather dozing. But somehow I stayed in the dream for long enough for the following experiment:</p>
<p>I was walking by a bus or tram stop and saw a transport network plan. I decided to read it. As it turns out, I was in <a href="http://en.wikipedia.org/wiki/Cottbus">Cottbus</a>, a middle-sized town in East Germany. I have never been to Cottbus in real life. The network plan contained all the stations the buses, or trams, in Cottbus stop at. Suddenly I had an idea: I wanted to challenge my brain, challenge the completeness and correctness of its imagination. I tried to read the station names, with the intent to later, when I was awake, find them on the <a href="http://217.160.141.52/frontstage/DC-Stadtwerke/data/multimedia/ABtag.pdf">real transport network plan of Cottbus</a>.</p>
<p>As it stands, my mind couldn&#8217;t lie to my awareness: I plainly wasn&#8217;t able to read the text. I saw lines that resembled something that could be text in some other language, but it weren&#8217;t latin letters. (The text &#8220;Cottbus&#8221; was written readably with latin letters.) Everytime I looked at one specific bus stop label, it seemed to hav changed from the last time. For this reason I had problems remembering a specific label. I do remember though how the script generally looked like: It contained strokes, mainly from top to bottom and diagonal ones, and arcs like in C or ). These elements were less connected that latin letters; in a word of the length of 10 latin letters there were maybe 20 such strokes and arcs.</p>
<p>Why did my mind allow me to read the plan in the first place? As I&#8217;ve never been to Cottbus and have never seen the plan of public transport, it couldn&#8217;t possibly show me the real plan. I knew that, as well as my mind. (That sentence sounds a little insane, so let&#8217;s rephrase it: My awareness  knew that as well as the mind of my physical ego, which was dreaming at the time. Read more about you, awareness and ego on <a href="http://www.stevepavlina.com/blog/category/consciousness-awareness/">Steve Pavlinas web log</a>.)</p>
<p>On the time line in the dream, I first saw the plan and only then decided to take a detailed look at it, so it was too late for my mind to not let me see it. And I hadn&#8217;t thought of the challenge yet. So I didn&#8217;t expect to see something that I will later compare with reality. Before looking at the station labels though, I already thought of the challenge. And my mind knew that I was specifically after tricking it. So it decided to do something about it. After all this is a dream, and in a dream it&#8217;s possible for text to be just not readable. In the end my mind tricked my awareness.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluetwanger.de/blog/2006/09/17/lucid-dreaming-recognizing-something-youve-never-seen-before/feed/</wfw:commentRss>
		<slash:comments>1</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>3</slash:comments>
		</item>
	</channel>
</rss>
