<?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>Martin Ankerl &#187; tricks</title>
	<atom:link href="http://martin.ankerl.com/category/tricks/feed/" rel="self" type="application/rss+xml" />
	<link>http://martin.ankerl.com</link>
	<description>No movement is faster than no movement</description>
	<lastBuildDate>Tue, 13 Jul 2010 05:31:29 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=abc</generator>
		<item>
		<title>How To: Download Any Flash Video with flashrip in Ubuntu</title>
		<link>http://martin.ankerl.com/2009/11/15/how-to-download-any-flash-video-with-flashrip-in-ubuntu/</link>
		<comments>http://martin.ankerl.com/2009/11/15/how-to-download-any-flash-video-with-flashrip-in-ubuntu/#comments</comments>
		<pubDate>Sun, 15 Nov 2009 11:57:37 +0000</pubDate>
		<dc:creator>Martin Ankerl</dc:creator>
				<category><![CDATA[downloads]]></category>
		<category><![CDATA[freeware]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[tricks]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[videos]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/?p=218</guid>
		<description><![CDATA[Downloading flash videos in Linux was already not too difficult, but thanks to flashrip, it has gotten very easy. Here is a little demo how it works: Once installed, you basically use one click to get a video preview and then a prompt with the filename to save the file. The script works by looking [...]]]></description>
			<content:encoded><![CDATA[<p>Downloading flash videos in Linux was already <a href="http://www.youtube.com/watch?v=vxBGr2T1Ueo">not too difficult</a>, but thanks to <tt>flashrip</tt>, it has gotten very easy. Here is a little demo how it works:<br />
<center><br />
<object width="560" height="370"><param name="movie" value="http://www.youtube.com/v/qvxHQKGci9o&#038;hl=en_US&#038;fs=1&#038;"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/qvxHQKGci9o&#038;hl=en_US&#038;fs=1&#038;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="560" height="370"></embed></object><br />
</center></p>
<p>
Once installed, you basically use one click to get a video preview and then a prompt with the filename to save the file. The script works by looking into the newest flash files in your <tt>/tmp</tt> folder, and creates a hardlink to the save destination. When the video has fully loaded, you can close the browser window. The temp file will get deleted, and the linked copy will remain.</p>
<h2>Installing flashrip</h2>
<p>Open a terminal like gnome-terminal or konsole, and run these commands:</p>
<pre>wget http://martin.ankerl.com/wp-content/uploads/2009/11/flashrip.sh
chmod 755 flashrip.sh
sudo mv flashrip.sh /usr/local/bin</pre>
<p>Now all thats left to do is to create a link in your gnome panel for ease of use: Right click the gnome panel, &#8220;Add to panel&#8230;&#8221;, choose &#8220;Custom Application Launcher&#8230;&#8221;. Choose a proper name, and a command like this:
<pre>/usr/local/bin/flashrip.sh /home/manker/Videos</pre>
<p>For the command, replace the second parameter with the default location where you want to save the ripped videos (you have to use the full path here!)</p>
<p>I have tested this in Ubuntu, but it should work on any linux where gnome is installed. </p>
<p>Have fun!</p>
<div style='clear:both'></div><img src="http://martin.ankerl.com/?ak_action=api_record_view&id=218&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2009/11/15/how-to-download-any-flash-video-with-flashrip-in-ubuntu/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Online Password Encrypter for Apache</title>
		<link>http://martin.ankerl.com/2009/05/22/online-password-encrypter-for-apache/</link>
		<comments>http://martin.ankerl.com/2009/05/22/online-password-encrypter-for-apache/#comments</comments>
		<pubDate>Fri, 22 May 2009 21:33:35 +0000</pubDate>
		<dc:creator>Martin Ankerl</dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[news]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[tricks]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/?p=213</guid>
		<description><![CDATA[Apache uses (among other hashes) SHA-1 keys for encryption in the .htpasswd. I administer a subversion server, and from time to time I have to add new external users to the system. This is usually rather cumbersome because there is no easy way to get to their encrypted password. Thats why I have created The [...]]]></description>
			<content:encoded><![CDATA[<p>Apache uses (among other hashes) SHA-1 keys for encryption in the .htpasswd. I administer a subversion server, and from time to time I have to add new external users to the system. This is usually rather cumbersome because there is no easy way to get to their encrypted password.</p>
<p>Thats why I have created <a href="http://martin.ankerl.com/files/pwd-encrypter.html">The Online Password Encrypter</a>. Here users can enter their desired username and password, and the encrypted key is automatically generated online, without transmitting anything to any server.</p>
<p>Here is an iframe of the file. <a href="http://martin.ankerl.com/files/pwd-encrypter.html">Click here for full screen</a>.</p>
<p><iframe src ="http://martin.ankerl.com/files/pwd-encrypter.html" width="95%" height="650">
<p>Your browser does not support iframes.</p>
<p></iframe></p>
<p>The <a href="http://martin.ankerl.com/files/pwd-encrypter.html">Online Password Encrypter</a> is just one single HTML page, it does not depend on any other files. So it is easy to download it, modify and send it around. Feel free do whatever you want with it.</p>
<p>Have fun,<br />
Martin</p>
<div style='clear:both'></div><img src="http://martin.ankerl.com/?ak_action=api_record_view&id=213&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2009/05/22/online-password-encrypter-for-apache/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Beautiful Font Hinting in Ubuntu 8.10 and 9.04</title>
		<link>http://martin.ankerl.com/2009/01/22/beautiful-font-hinting-in-ubuntu-810/</link>
		<comments>http://martin.ankerl.com/2009/01/22/beautiful-font-hinting-in-ubuntu-810/#comments</comments>
		<pubDate>Thu, 22 Jan 2009 20:59:03 +0000</pubDate>
		<dc:creator>Martin Ankerl</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[news]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[tricks]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/?p=197</guid>
		<description><![CDATA[Even though I have an LCD monitor, I always have the subpixel hinting switched off because it is just painfully ugly to my eyes. Even when hinting is switched to maximum, the fonts are quite blurry (if you don&#8217;t believe me, type xmag and take a screenshot of your font. You can see red and [...]]]></description>
			<content:encoded><![CDATA[<p>Even though I have an LCD monitor, I always have the subpixel hinting switched off because it is just painfully ugly to my eyes. Even when hinting is switched to maximum, the fonts are quite blurry (if you don&#8217;t believe me, type <tt>xmag</tt> and take a screenshot of your font. You can see red and blue linese everywhere). My eyes hurt when I see this. </p>
<p>Thanks to <a href="http://johan.kiviniemi.name/blag/ubuntu-fonts/">Johan Kivinemi</a> I have just found out how to bring back the excellent legacy subpixel hinting engine. This has a much more crisp hinting, and uses subpixels only where it really is an improvement:</p>
<p>Just open these files in your home directory, and copy the content into them:</p>
<h2>~/.fonts.conf</h2>
<pre class="brush: xml;">
&lt;?xml version='1.0'?&gt;
&lt;!DOCTYPE fontconfig SYSTEM 'fonts.dtd'&gt;
&lt;fontconfig&gt;
  &lt;match target=&quot;font&quot;&gt;
    &lt;edit name=&quot;antialias&quot; mode=&quot;assign&quot;&gt;
      &lt;bool&gt;true&lt;/bool&gt;
    &lt;/edit&gt;
    &lt;edit name=&quot;hinting&quot; mode=&quot;assign&quot;&gt;
      &lt;bool&gt;true&lt;/bool&gt;
    &lt;/edit&gt;
    &lt;edit name=&quot;hintstyle&quot; mode=&quot;assign&quot;&gt;
      &lt;const&gt;hintfull&lt;/const&gt;
    &lt;/edit&gt;
    &lt;edit name=&quot;lcdfilter&quot; mode=&quot;assign&quot;&gt;
      &lt;const&gt;lcdlegacy&lt;/const&gt;
    &lt;/edit&gt;
    &lt;edit name=&quot;rgba&quot; mode=&quot;assign&quot;&gt;
      &lt;const&gt;rgb&lt;/const&gt;
    &lt;/edit&gt;
  &lt;/match&gt;
&lt;/fontconfig&gt;
</pre>
<h2>~/.Xresources</h2>
<pre class="brush: xml;">
Xft.antialias:  true
Xft.hinting:    true
Xft.hintstyle:  hintfull
Xft.lcdfilter:  lcdlegacy
Xft.rgba:       rgb
</pre>
<p>This should work in Ubuntu 8.04, 8.10, and 9.04 too, and makes all fonts much more crisp. Of course, your mileage may vary.</p>
<h1>UPDATE: Comparison Screenshots</h1>
<p>As promised on <a href="http://www.reddit.com/r/linux/comments/7ru91/beautiful_font_hinting_in_ubuntu_810/">reddit</a>, I got back from an awesome snowboard trip so I am able to put up extensive comparison screenshots of the two subpixel hinting engines. Move your mouse over the following images to see the differences. Watch especially out for letters like &#8220;m&#8221; where the spacing between the lines is very small. You might have to wait a bit for the image to load.</p>
<p>I have used all of the most important fonts that I usually use, and just for fun I have added &#8220;Dijkstra&#8221;, which just looks cool.</p>
<h2>Sans Fonts</h2>
<p>Mouse to see the same fonts with the legacy hinter.</p>
<style type="text/css"><!-- #sans a { text-decoration:none; display:block; background-image:url(http://martin.ankerl.com/wp-content/uploads/2009/01/sans-normal.png); width:395px; height:850px; } #sans a:hover {background-image:url(http://martin.ankerl.com/wp-content/uploads/2009/01/sans-legacy.png); } --> </style>
<div id="sans">
<a href="#">&nbsp;</a>
</div>
<h2>Mono Fonts</h2>
<p>Mouse to see the same fonts with the legacy hinter.</p>
<style type="text/css"><!-- #mono a { text-decoration:none; display:block; background-image:url(http://martin.ankerl.com/wp-content/uploads/2009/01/mono-normal.png); width:430px; height:940px; } #mono a:hover {background-image:url(http://martin.ankerl.com/wp-content/uploads/2009/01/mono-legacy.png); } --> </style>
<div id="mono">
<a href="#">&nbsp;</a>
</div>
<h2>Zoomed Comparison Screenhots</h2>
<p>Here is an excerpt with 400% magnifications. Mouse over the pictures to see the legacy hinter.</p>
<h3>Zoomed Sans</h3>
<style type="text/css"><!-- #sanszoom a { text-decoration:none; display:block; background-image:url(http://martin.ankerl.com/wp-content/uploads/2009/01/sans-normal-zoomed.png); width:400px; height:200px; } #sanszoom a:hover {background-image:url(http://martin.ankerl.com/wp-content/uploads/2009/01/sans-legacy-zoomed.png); } --> </style>
<div id="sanszoom">
<a href="#">&nbsp;</a>
</div>
<h3>Zoomed Mono</h3>
<style type="text/css"><!-- #monozoom a { text-decoration:none; display:block; background-image:url(http://martin.ankerl.com/wp-content/uploads/2009/01/mono-normal-zoomed.png); width:400px; height:200px; } #monozoom a:hover {background-image:url(http://martin.ankerl.com/wp-content/uploads/2009/01/mono-legacy-zoomed.png); } --> </style>
<div id="monozoom">
<a href="#">&nbsp;</a>
</div>
<div style='clear:both'></div><img src="http://martin.ankerl.com/?ak_action=api_record_view&id=197&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2009/01/22/beautiful-font-hinting-in-ubuntu-810/feed/</wfw:commentRss>
		<slash:comments>27</slash:comments>
		</item>
		<item>
		<title>Approximation of sqrt(x) in Java</title>
		<link>http://martin.ankerl.com/2009/01/05/approximation-of-sqrtx-in-java/</link>
		<comments>http://martin.ankerl.com/2009/01/05/approximation-of-sqrtx-in-java/#comments</comments>
		<pubDate>Mon, 05 Jan 2009 11:51:50 +0000</pubDate>
		<dc:creator>Martin Ankerl</dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[tricks]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/?p=195</guid>
		<description><![CDATA[Yesterday I have played a bit with reinventing a fast approximation for sqrt() in Java. This might be handy with J2ME. Wikipedia has a nice article about Approximations that depend on IEEE representation. My version works, and on my Intel Dual Core with an average error of 1.57%, maximum error 4.02% it is 3.5 times [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday I have played a bit with reinventing a fast approximation for <tt>sqrt()</tt> in Java. This might be handy with J2ME. Wikipedia has a nice article about <a href="http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Approximations_that_depend_on_IEEE_representation">Approximations that depend on IEEE representation</a>.  My version works, and on my Intel Dual Core with an average error of 1.57%, maximum error 4.02% it is 3.5 times faster than the original sqrt. In addition, it is very simple to improve the precision to 0.000161% average error and 0.000775% maximum error which is then 1.56 times faster than <tt>Math.sqrt()</tt>.</p>
<h2>Sourcecode</h2>
<p>I use floating point tricks based on my <a href="http://martin.ankerl.com/2007/10/04/optimized-pow-approximation-for-java-and-c-c/">pow() approximation</a>. Basically I just took the pow() formula and for a^b I substitued <tt>b</tt> with <tt>0.5</tt>, then simplified this as much as possible. As it turns out the result is very simple and short. This initial approximation can be easily made more precise with <a href="http://en.wikipedia.org/wiki/Newton%27s_method">Newton&#8217;s method</a>:</p>
<pre class="brush: java;">
    public static double sqrt(final double a) {
        final long x = Double.doubleToLongBits(a) &gt;&gt; 32;
        double y = Double.longBitsToDouble((x + 1072632448) &lt;&lt; 31);

        // repeat the following line for more precision
        //y = (y + a / y) * 0.5;
        return y;
    }
</pre>
<p>Here is a comparison of the performance and accurancy versus the number of repetitions:</p>
<table width="100%">
<tr>
<th>Repetitions</th>
<th>Average<br/>error</th>
<th>Maximum<br/>error</th>
<th>Speedup</th>
</tr>
<tr>
<td>0</td>
<td>1.57%</td>
<td>4.02%</td>
<td>3.53</td>
</tr>
<tr>
<td>1</td>
<td>0.000161%</td>
<td>0.000775%</td>
<td>1.56</td>
</tr>
<tr>
<td>2</td>
<td>2.51e-8%</td>
<td>3.00e-7</td>
<td>0.838</td>
</tr>
</table>
<p>With 2 repetitions, the trouble is not worth the effort, as the approximation is already slower than the original Math.sqrt() which is more precise.</p>
<div style='clear:both'></div><img src="http://martin.ankerl.com/?ak_action=api_record_view&id=195&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2009/01/05/approximation-of-sqrtx-in-java/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ripping Multilanguage DVDs with Subtitles using Mencoder</title>
		<link>http://martin.ankerl.com/2008/12/25/ripping-multilanguage-dvds-with-subtitles-using-only-mencoder/</link>
		<comments>http://martin.ankerl.com/2008/12/25/ripping-multilanguage-dvds-with-subtitles-using-only-mencoder/#comments</comments>
		<pubDate>Thu, 25 Dec 2008 22:06:11 +0000</pubDate>
		<dc:creator>Martin Ankerl</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[tricks]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[videos]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/?p=185</guid>
		<description><![CDATA[Yesterday at Christmas I got the Akira Kurosawa Samurai Edition, which is a 7 disc DVD set of his awesome movies. I am converting it into the best quality files currently possible: MKV as the container, x264 codec for the video, dual audio, and with subtitles. This is short Howto so that I won&#8217;t forget [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday at Christmas I got the <a href="http://en.wikipedia.org/wiki/Akira_Kurosawa">Akira Kurosawa</a> Samurai Edition, which is a 7 disc DVD set of his awesome movies. I am converting it into the best quality files currently possible: MKV as the container, x264 codec for the video, dual audio, and with subtitles. This is short Howto so that I won&#8217;t forget how <img src='http://martin.ankerl.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /><br />
<span id="more-185"></span></p>
<ol>
<li>Create a file <tt>~/.mplayer/mencoder.conf</tt> with default compression settings. I use this, with encoding quality settings I have from <a href="http://www.mplayerhq.hu/DOCS/HTML/en/menc-feat-x264.html#menc-feat-x264-example-settings">mplayer&#8217;s x264 examples</a>:
<pre class="brush: ruby;">
o=out.avi
ovc=x264=yes
oac=mp3lame=yes

#lameopts=preset=medium
lameopts=aq=2:vbr=4
#lameopts=preset=voice

# the lower crf, the better
# 20: very good
# 22: Medium Quality DVD rips
# 23: quite ok
# 25: so-so
# 30: acceptable
# 40: my eyes hurt
# 50: my eyes bleed
x264encopts=threads=auto:crf=20:subq=7:partitions=all:8x8dct:me=umh:frameref=5:bframes=3:b_pyramid:weight_b

# deinterlace
# vf=yadif

# slight denoise
# vf=hqdn3d=3:2:3:3

# turbo encoding (low quality!)
#x264encopts=threads=auto:crf=23:turbo=2:subq=1:frameref=1
</pre>
<li>I use constant quality setting. The advantage is that it requires only one pass, and you get, well, constant quality <img src='http://martin.ankerl.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  In the config file find the <tt>crf=20</tt> section and change it to your desire.
<li>Find out which DVD chapter you want to rip, starting with 1 up (e.g. <tt>mplayer dvd://1</tt>).
<li>If the DVD has black borders, find out their sizes with
<pre>mplayer dvd://2 -vf cropdetect</pre>
<p>Fast forward a bit into the movie so that the ratio can be trusted.<br />
<strong>WARNING</strong> Some DVDs like Natural Born Killers are shot with multiple different films, so the border changes! Take care not to crop anything important away. Copy the -crop printouts into the clipboard.</p>
<li>Open another console window, run <tt>mplayer dvd://2 -identify</tt>, and quit. Now scroll up, there is some important information about the tracks which you need in the next step. I have extraced the important information here:
<pre class="brush: ruby;">
ID_AUDIO_ID=128
ID_AID_128_LANG=de
...
ID_AUDIO_ID=129
ID_AID_129_LANG=ja
...
subtitle ( sid ): 0 language: de
...
subtitle ( sid ): 1 language: de
</pre>
<p>So there is audio language <tt>de</tt> and <tt>ja</tt>, and 2 subtitles for de. Mplayer the DVD and press <tt>J</tt> to find out which subtitles you want to have. (mplayer shows the ID, like <tt>(0) de</tt>).</p>
<li>I have chosen AID 129 and sid 1. In the other window, start ripping the movie:
<pre class="brush: ruby;">
mencoder dvd://2 -vf crop=704:432:0:72 -aid 129 -o Yojimbo.avi -vobsubout subs -vobsuboutindex 0 -sid 1</pre>
<p>This will get you 3 files: <tt>Yojimbo.avi</tt> with Japanese audio and x264 encoded movie video, and <tt>subs.idx</tt> and <tt>subs.sub</tt> with the subtitles. Play the movie to check everything works as it should.</p>
<li>Rip additional sound tracks now, if you want them. You can rip one additional subtitle at the same time. To do this, increase the vobsuboutindex by one, or choose another filename. I choose to rip the german audio and another subtitle track:
<pre class="brush: ruby;">
mencoder dvd://2 -aid 128 -ovc frameno -o de.avi -vobsubout out -vobsuboutindex 0 -sid 1
</pre>
<p>The <tt>-ovc frameno</tt> part is important, because this skips video encoding. Encoding is much faster this way because we already have the video anyways.</p>
<li>Merge everything together with <tt>mmg</tt>, this is a GUI interface for <tt>mkvmerge</tt> which you get via <tt>sudo apt-get install mkvtoolnix</tt>. Select the correct languages for the audio and subtitle tracks.
</ol>
<p>I think that&#8217;s about it. This way you will get very high quality, multi language rips with subtitles. Oh, some other interesting points to note:</p>
<ul>
<li>I <em>always</em> encode with the same resolution as the source, no rescaling. Rescaling is very bad, I much prefer that quality is reduced by the codec and not preemptively through scaling down. Even a HDTV ripped to 700MB gets you a much better quality when not rescaled than a DVD ripped to 700MB. The x264 does an awesome job at preserving quality where it is important.
<li>I only rip with variable bitrate VBR. It has very good quality, but it is not surround sound.
</ul>
<div style='clear:both'></div><img src="http://martin.ankerl.com/?ak_action=api_record_view&id=185&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2008/12/25/ripping-multilanguage-dvds-with-subtitles-using-only-mencoder/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Amazing Caching Proxy in Java</title>
		<link>http://martin.ankerl.com/2008/12/22/amazing-caching-proxy-in-java/</link>
		<comments>http://martin.ankerl.com/2008/12/22/amazing-caching-proxy-in-java/#comments</comments>
		<pubDate>Mon, 22 Dec 2008 21:53:59 +0000</pubDate>
		<dc:creator>Martin Ankerl</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[tricks]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/?p=184</guid>
		<description><![CDATA[Use Case Imagine you have some Java code that does lots and lots of computation. All the time intensive calculations is performed by the class SlowCalculator which implements the interface Calculator: public static interface Calculator { public String calculate(int a, String b); } public static void main(String[] args) { Calculator c = new SlowCalculator(); // [...]]]></description>
			<content:encoded><![CDATA[<h2>Use Case</h2>
<p>Imagine you have some Java code that does lots and lots of computation. All the time intensive calculations is performed by the class <tt>SlowCalculator</tt> which implements the interface <tt>Calculator</tt>:</p>
<pre class="brush: java;">
public static interface Calculator {
    public String calculate(int a, String b);
}

public static void main(String[] args) {
    Calculator c = new SlowCalculator();
    // call c.calculate() a lot of times here...
}
</pre>
<p>You notice that <tt>calculate()</tt> is often called with the same parameters which lead to the exact same result (<tt>SlowCalculator</tt> is stateless). This means it is possible to cache values so there&#8217;s no need to recompute. Using the generic CachingProxy&trade; described below, you can create a cached proxy for any class with just one single line of code:</p>
<pre class="brush: java;">
// ...

public static void main(String[] args) {
    Calculator c = new SlowCalculator();
    c = CachedProxy.create(Calculator.class, c);
    // call c.calculate() a lot of times here...
}
</pre>
<p>That&#8217;s it, and the application is blazingly fast again.</p>
<p><strong>UPDATE</strong>: Support for <tt>null</tt> values, transparently handles exceptions, better hash, nullpointer-bugfix.</p>
<p><strong>UPDATE</strong>: Here is an article &#8220;<a href="http://www.onjava.com/pub/a/onjava/2003/08/20/memoization.html">Memoization in Java Using Dynamic Proxy Classes</a>&#8221; that does (almost) exactly the same as this code.</p>
<p><span id="more-184"></span></p>
<h2>How To Do This</h2>
<p>All this sounds nice, but can you do this in java? Turns out you can and it is not that difficult either. The feature that makes it all possible is <a href="http://java.sun.com/j2se/1.4.2/docs/guide/reflection/proxy.html">Dynamic Proxy</a>. With it you can implement interfaces <em>at runtime</em>. You take an interface, create a proxy for it with <tt><a href="http://java.sun.com/javase/6/docs/api/java/lang/reflect/Proxy.html">Proxy</a>.newProxyInstance(...)</tt>, supply an <a href="http://java.sun.com/javase/6/docs/api/java/lang/reflect/InvocationHandler.html">InvocationHandler</a> that implements the <tt><a href="http://java.sun.com/javase/6/docs/api/java/lang/reflect/InvocationHandler.html#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])">invoke()</a></tt> method, and you are done.</p>
<p>The code for the <tt>CachedProxy.create()</tt> method is this:</p>
<pre class="brush: java;">
    /**
     * Creates an intermediate proxy object that uses cached results if
     * available, otherwise calls the given code.
     *
     * @param &lt;T&gt;
     *            Type of the class.
     * @param cl
     *            The interface for which the proxy should be created.
     * @param code
     *            The actual calculation code that should be cached.
     * @return The proxy.
     */
    @SuppressWarnings(&quot;unchecked&quot;)
    public static &lt;T&gt; T create(final Class&lt;T&gt; cl, final T code) {
        // create the cache
        final Map&lt;Args, Object&gt; argsToOutput = new HashMap&lt;Args, Object&gt;();

        // proxy for the interface T
        return (T) Proxy.newProxyInstance(cl.getClassLoader(), new Class&lt;?&gt;[] { cl }, new InvocationHandler() {

            @Override
            public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
                final Args input = new Args(method, args);
                Object result = argsToOutput.get(input);
                // check containsKey to support null values
                if (result == null &amp;&amp; !argsToOutput.containsKey(input)) {
                    // make sure exceptions are handled transparently
                    try {
                        result = method.invoke(code, args);
                        argsToOutput.put(input, result);
                    } catch (InvocationTargetException e) {
                        throw e.getTargetException();
                    }
                }
                return result;
            }
        });
    }
</pre>
<ol>
<li>First I create a <tt>HashMap</tt> that is the cache for the return values. I have written a class <tt>Args</tt> (omitted here) that is as the key to map from the method and the parameters to the cached output.
<li>A Proxy is created for the interface <tt>cl</tt>, with an InvocationHandler that does all the magic.
<li>The magic is actually very simple: If there is no cached result already available (line 25), perform the computation (line 26) and store the result in the map, then return the result.
</ol>
<h2>Download</h2>
<p>You can get the full code at my github repository:</p>
<ul>
<li>
<a href="http://github.com/martinus/java-playground/tree/master/src/java/com/ankerl/proxy/CachedProxy.java">CachedProxy</a>
</li>
</ul>
<h2>Benchmarks</h2>
<p>In my benchmark I can run about 8 million calls per secons via the cached proxy. That&#8217;s not too bad, given all the additional overhead with reflection and the HashMap.</p>
<p>Do you know of any way to improve this? Any ideas or suggestions are welcome!</p>
<div style='clear:both'></div><img src="http://martin.ankerl.com/?ak_action=api_record_view&id=184&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2008/12/22/amazing-caching-proxy-in-java/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Two Word Anagram Finder Algorithm (in Ruby)</title>
		<link>http://martin.ankerl.com/2008/08/09/two-word-anagram-finder-algorithm/</link>
		<comments>http://martin.ankerl.com/2008/08/09/two-word-anagram-finder-algorithm/#comments</comments>
		<pubDate>Sat, 09 Aug 2008 19:32:30 +0000</pubDate>
		<dc:creator>Martin Ankerl</dc:creator>
				<category><![CDATA[benchmark]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[tricks]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/?p=156</guid>
		<description><![CDATA[Today I have got some sourcecode for you. There is a little programming challenge named The Self-Documenting Code Contest that is quite fun, they try to find the cleanest and easiest to read code for this task: Write a program that generates all two-word anagrams of the string &#8220;documenting&#8221;. Here&#8217;s a word list you might [...]]]></description>
			<content:encoded><![CDATA[<p>Today I have got some sourcecode for you. There is a little programming challenge named <a href="http://selfexplanatorycode.blogspot.com/">The Self-Documenting Code Contest</a> that is quite fun, they try to find the cleanest and easiest to read code for this task:</p>
<blockquote><p>
Write a program that generates all two-word anagrams of the string &#8220;documenting&#8221;. Here&#8217;s a word list you might want to use: <a href='http://martin.ankerl.com/wp-content/uploads/2008/08/wordlist.zip'>wordlist.zip</a>.</p>
<p>When you&#8217;re done, send the results to <a href="mailto:selfdocumenting@hotmail.com">selfdocumenting@hotmail.com</a>.</p>
<p>Good luck!
</p></blockquote>
<p>So this caught my interest and i wrote a little entry in Ruby that is 23 lines long with whitespace and very nice to read. But I won&#8217;t show you this code until the contest is over, and this is not the reason for this post. The reason is, that the nice version takes about 2 seconds, and somebody else has coded a Python solution that takes only 1 second (I have no idea what his code looks like). This post is about a fast anagram finding algorithm, and how I developed this algorithm. The final result takes about 0.11 seconds.</p>
<h1>Algorithm</h1>
<p>The most basic algorithm has two phases:</p>
<ol>
<li>Read in the file
<li>Build all combinations of two words and compare the letter count with the query.
</ol>
<p>Building the combinations is usually done with two nested loops and takes O(n^2) runtime. This is slow, so I have added another step in between:</p>
<h2>Idea #1: Filter out Candidate Words</h2>
<p>The second step is really slow, but it would be a lot faster if it has to handle less words. So I wrote a little filtering step that lets only words through which are made out of the same letters as the query word.</p>
<p>For example when the query is <tt>documenting</tt>, the word <tt>men</tt> or <tt>go</tt> and even <tt>too</tt> are extracted, even if the number of letters might not match. But that&#8217;s not important, what is important is that the number of possible words are reduced a lot, and so the next phase is faster.</p>
<h2>Idea #2: Use a Commutative Hashing Function</h2>
<p>String comparisons are slow. To common way to find out if the strings <tt>coming</tt> with <tt>tuned</tt> is an anagram of the word <tt>documenting</tt> is to sort the letters and make a comparison, like this:</p>
<pre class="brush: ruby;">
irb(main):003:0&gt; &quot;documenting&quot;.unpack(&quot;c*&quot;).sort.pack(&quot;c*&quot;)
=&gt; &quot;cdegimnnotu&quot;
irb(main):004:0&gt; (&quot;coming&quot; + &quot;tuned&quot;).unpack(&quot;c*&quot;).sort.pack(&quot;c*&quot;)
=&gt; &quot;cdegimnnotu&quot;
</pre>
<p>The strings are equal, so we have a match. But this comparison is terribly slow! What&#8217;s worse, the computations have to be redone for each match. It would be much better to just compare hash values, and find a hash function to quickly check if we might have a match, and only do the string comparison when the hash check matches. The hash has to be good enough that we don&#8217;t have too much false positives (hashes are equal but the real comparisons not) to get a speed advantage. So why not just sum up all the letters bytes? </p>
<pre class="brush: ruby;">
irb(main):005:0&gt; &quot;documenting&quot;.sum
=&gt; 1181
irb(main):006:0&gt; &quot;coming&quot;.sum + &quot;tuned&quot;.sum
=&gt; 1181
</pre>
<p>Ruby&#8217;s <a href="http://www.ruby-doc.org/core/classes/String.html#M000857">String#sum</a> does exactly this. we can now precalculate the sum for each word, and to find a match we just add the two hashes and compare the result to the query&#8217;s hash:</p>
<pre class="brush: ruby;">
irb(main):007:0&gt; query=&quot;documenting&quot;; first=&quot;coming&quot;; second=&quot;tuned&quot;
=&gt; &quot;tuned&quot;
irb(main):008:0&gt; first.sum + second.sum == query.sum
=&gt; true
</pre>
<p>When this very quick check returns true, we have to do the string comparison to be absolutely sure it is a match. This considerably speeds up the whole program, but it is still O(n^2).</p>
<h2>Idea #3: Reformulate Problem</h2>
<p>Now here comes the trickiest and coolest part. Since Idea #2 the slowest part is matching the numbers, with still quadratic complexity. But the hard task is not anagram finding any more, we have reduced it to finding two hashes that combined have the same hash as the query. We can reformulate this problem into something completely detached from the anagram problem:</p>
<blockquote><p>
Given a list of numbers, find all combination of two numbers that add up to a given number
</p></blockquote>
<p>When we concentrate on just this problem and ignore the rest, we might come up with a better way of doing things.</p>
<p>I came up with a fast solution, described below. Somebody posted a better solution that is both faster and simpler, if you want just this final solution <a href="#idea4">skip ahead to Idea #4</a> as the following description is outdated.</p>
<p>It clearly looks stupid to just try all combinations to add the numbers.<br />
So lets sort them first. Quicksort is fast, especially with numbers, so no worries here. Now consider a list of numbers like this example:</p>
<pre>1   3   7   10   10   12   17   20   22   23   24   24   25   26   30</pre>
<p>Find all the combinations of two number that add up to 27. They are</p>
<ul>
<li>1 + 26 = 27
<li>3 + 24 = 27
<li>7 + 20 = 27
<li>10 + 17 = 27
<li>10 + 17 = 27 (a second time)
</ul>
<p>You can detect a pattern here: the first number always increases, the second number always decreases! We can now formulate an algorithm for this:</p>
<p>We can have two pointers to the array, one starting from the left side, the other starting from the right side. When the numbers behind the pointers add up to a bigger result than the query (e.g. 1 + 30 = 31), we decrease the right pointer to find a smaller combination (1 + 26 = 27). When the sums are too small (1 + 25 = 26), we move the left pointer to the right (3 + 25 = 28).</p>
<p>This way we walk through the whole array in O(n) time and the sum of the pointers is always kept as close the the desired result as possible. When the pointers meet each other, we can stop the whole process or otherwise we would just reverse the words. </p>
<p>This algorithm gets a bit more complicated when you consider that we might have lots of numbers in it that are equal, whenever this happens you have to fall back into an O(n^2) matching algorithm for just this section.</p>
<h2><a name="idea4"></a>Idea #4: Use Hash directly</h2>
<p><b>UPDATE</b> Scrap the implementation in idea #3. A blog post here from a reader of this article posted a way to do this really in O(n), without any sorting which is O(n*log(n)). The idea is to use a hashmap that maps from the hash key of the word to its matches:</p>
<pre class="brush: ruby;">
M = {}
S = the target sum
for each element e in the list
      if M[S-e] exists? (e,S-e) is a pair
      add e to the M
</pre>
<p>Just use a Hashmap that maps from the cummulative hash of a word to a list of words that have the same hash. Whenever a new word is added, get the list of words that is stored under <tt>query.sum - current_word.sum</tt>. When the hashes are the same we just have to create a list of all the matches under this key, and check each of the matches sequentially for equality. This is just normal hash collision handling through a linked list. That&#8217;s very simple and works like a charm.</p>
<p>I have revised the code, it got both simpler and faster. That&#8217;s a win-win situation, wohoo! </p>
<h1>The Sourcecode</h1>
<p>I hope the code is understandable now with the above explanation. If you have any questions or ideas, please share them here!</p>
<pre class="brush: ruby;">
#!/usr/bin/ruby

# created by Martin Ankerl http://martin.ankerl.com/

class String
	# creates an array of characters
	def letters
		unpack(&quot;c*&quot;)
	end
end

class Array
	# converts an array of letters back into a String
	def word
		pack(&quot;c*&quot;)
	end
end

query = &quot;documenting&quot;
query_letters_sorted = query.letters.sort
txt = File.read('wordlist.txt').downcase

# to quickly check if a letter is part of the query word
used_letters = Array.new(256, nil)
query_letters_sorted.each do |letter|
	used_letters[letter] = true
end

# Maps from cummulative hash of a word to a list of words that have this hash code.
hashToWords = Hash.new do |hash, key|
	hash[key] = Array.new
end

query_hash = query.sum

prev = 0
txt_size = txt.size
separator = 10
idx = txt.index(separator, prev)
while prev &lt; txt_size

	letter_idx = prev

	# no need to check end of word because it is \n
	# which is not part of the word anyways
	while used_letters[txt[letter_idx]]
		letter_idx += 1
	end

	# ignore word if the above quick check fails
	if letter_idx == idx
		word = txt[prev, idx-prev]

		# check all key matches
		key = word.sum
		hashToWords[query_hash - key].each do |other_word|
			if (word.letters + other_word.letters).sort == query_letters_sorted
				puts &quot;#{word} #{other_word}&quot;
				puts &quot;#{other_word} #{word}&quot;
			end
		end

		# insert word
		hashToWords[key] &lt;&lt; word
	end

	prev = idx + 1

	# no need to check end of file because we have to end with new line
	idx = txt.index(separator, prev)
end
</pre>
<p>When you rewrite the algorithm in C++ or Java or Python I am sure it will be faster than this one. But this is not the point of this post. The point is, &#8220;The Best Optimizer is between Your Ears&#8221; (Michael Abrash, <a href="http://www.byte.com/abrash/">Graphics Programming Black Book</a>).</p>
<p>Have fun!</p>
<div style='clear:both'></div><img src="http://martin.ankerl.com/?ak_action=api_record_view&id=156&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2008/08/09/two-word-anagram-finder-algorithm/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Howto Get Enough Sleep Despite StumbleUpon with Ubuntu</title>
		<link>http://martin.ankerl.com/2008/01/24/howto-get-enough-sleep-despite-stumbleupon-with-ubuntu/</link>
		<comments>http://martin.ankerl.com/2008/01/24/howto-get-enough-sleep-despite-stumbleupon-with-ubuntu/#comments</comments>
		<pubDate>Thu, 24 Jan 2008 22:06:44 +0000</pubDate>
		<dc:creator>Martin Ankerl</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[tricks]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[cron]]></category>
		<category><![CDATA[getsomesleep]]></category>
		<category><![CDATA[lifehack]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/2008/01/24/howto-get-enough-sleep-despite-stumbleupon-with-ubuntu/</guid>
		<description><![CDATA[What? I am a long-term StumbleUpon user, which means that I don&#8217;t get much sleep. Now, after almost 4 years of stumbling, I have decided to get my life back. Well, at least some sleep! What does this do? Every night when I have to work on the next day (Sunday night to Thursday night [...]]]></description>
			<content:encoded><![CDATA[<h2>What?</h2>
<p><a href='http://martin.ankerl.com/wp-content/uploads/2008/01/stumbling-insomnia.jpg'><img src="http://martin.ankerl.com/wp-content/uploads/2008/01/stumbling-insomnia.jpg" alt="" title="stumbleupon insomnia" width="150" height="104" style="float:right;" /></a>I am a long-term <a href="http://www.stumbleupon.com/">StumbleUpon</a> user, which means that I don&#8217;t get much sleep. Now, after <a href="http://martinus.stumbleupon.com/public/">almost 4 years of stumbling</a>, I have decided to get my life back. Well, at least some sleep! </p>
<h2>What does this do?</h2>
<p>Every night when I have to work on the next day (Sunday night to Thursday night ), at 23:25 my computer shows me this little warning message:<br />
<center><img src='http://martin.ankerl.com/wp-content/uploads/2008/01/screenshot-warning.png' alt='go to bed warning' /></center><br />
After the 5 minutes have passed, the computer shuts itself automatically down.</p>
<p>I use this little trick with <a href="http://www.ubuntu.com/">Ubuntu,</a> but it should work anywhere where <a href="http://www.gnome.org/">Gnome</a> is installed.</p>
<h2>How?</h2>
<p>Thanks to the power of Linux, this is not difficult to do for yourself, and configure it however you want it to behave:</p>
<ol>
<li>Open <tt>/etc/crontab</tt> with your favourite text editor (no need for <tt>crontab -e</tt> since this is the system wide crontab), e.g.
<pre>sudo gedit /etc/crontab</pre>
</li>
<li>Add the following lines (replace <tt>manker</tt> with your username!)
<pre>25 23 * * 0-4   manker  /usr/bin/zenity --display :0 --warning --text="Shutdown in 5 minutes. Go to bed."
25 23 * * 0-4   root    shutdown -h +5</pre>
<li>The first part of both lines <tt>25 23 * * 0-4</tt> means that the commands are executed at 23:25, but only Sunday (day 0) to Thursday (day 4). Read <tt>man 5 crontab</tt> for a detailed description of that format.</li>
<li>The first command uses <tt>zenity</tt> to show a warning message. You have to execute this as the same user that you use for working, or you will not see the message, so change <tt>manker</tt> to your username (root does not work either).
<li>The second command <tt>shutdown -h +5</tt> means that the computer will halt in 5 minutes.  This has to be run as root, and it also shows nice warning messages in all your open terminals so you can&#8217;t really miss it.</li>
<li>Save the file, and stumble until it is 23:25.</ul>
</ol>
<p>Sweet dreams!</p>
<div style='clear:both'></div><img src="http://martin.ankerl.com/?ak_action=api_record_view&id=106&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2008/01/24/howto-get-enough-sleep-despite-stumbleupon-with-ubuntu/feed/</wfw:commentRss>
		<slash:comments>72</slash:comments>
		</item>
		<item>
		<title>Get More Space Out of Your ext3 Partition</title>
		<link>http://martin.ankerl.com/2008/01/12/get-more-space-out-of-your-ext3-partition/</link>
		<comments>http://martin.ankerl.com/2008/01/12/get-more-space-out-of-your-ext3-partition/#comments</comments>
		<pubDate>Sat, 12 Jan 2008 11:56:24 +0000</pubDate>
		<dc:creator>Martin Ankerl</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[tricks]]></category>
		<category><![CDATA[ext3]]></category>
		<category><![CDATA[harddisk]]></category>
		<category><![CDATA[trick]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[wastedspace]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/?p=104</guid>
		<description><![CDATA[I have just discovered that ext3 defaults to reserving 5% of its partition exclusively for root, as a precaution measure that your system does not get FUBAR when you use it for your root partition. I have a 230GB external USB disk that I use for all my big storage requirements, downloaded stuff, backups etc. [...]]]></description>
			<content:encoded><![CDATA[<p>I have just discovered that ext3 defaults to reserving 5% of its partition exclusively for root, as a precaution measure that your system does not get FUBAR when you use it for your root partition. I have a 230GB external USB disk that I use for all my big storage requirements, downloaded stuff, backups etc. Due to this reservation I had 11.5GB of unusable disk space, thankfully this is easy to fix:</p>
<pre>tune2fs -m 0 /dev/sdf1</pre>
<p>Replace <tt>sdf1</tt> with your partition name. You don&#8217;t even have to unmount your disk. Voilá, 11.5 GB more space for free <img src='http://martin.ankerl.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  Here is the output of <tt>df -h</tt> as proof:</p>
<h3>Before:</h3>
<pre>Filesystem            Size  Used Avail Use% Mounted on
/dev/sdf1             230G  193G   26G  89% /media/disk</pre>
<h3>After:</h3>
<pre>Filesystem            Size  Used Avail Use% Mounted on
/dev/sdf1             230G  193G   38G  84% /media/disk</pre>
<p>If you like this, you might also be interested in <a href="/2007/11/03/howto-change-ubuntu-forced-fsck/">How to change Ubuntu forced fsck</a>.</p>
<p><strong>Update:</strong> The free space limitation is also used to prevent fragmentation. So if you set the limit to zero and operate on a very full harddisk for a while, your filesystem might slow down.</p>
<div style='clear:both'></div><img src="http://martin.ankerl.com/?ak_action=api_record_view&id=104&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2008/01/12/get-more-space-out-of-your-ext3-partition/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Clearlooks Compact Gnome Theme</title>
		<link>http://martin.ankerl.com/2007/11/04/clearlooks-compact-gnome-theme/</link>
		<comments>http://martin.ankerl.com/2007/11/04/clearlooks-compact-gnome-theme/#comments</comments>
		<pubDate>Sun, 04 Nov 2007 20:59:42 +0000</pubDate>
		<dc:creator>Martin Ankerl</dc:creator>
				<category><![CDATA[freeware]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[news]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[tricks]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[clearlooks]]></category>
		<category><![CDATA[comparison]]></category>
		<category><![CDATA[gtk]]></category>
		<category><![CDATA[release]]></category>
		<category><![CDATA[theme]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/?p=100</guid>
		<description><![CDATA[I have been using Ubuntu for quite a while now, but one thing I really dislike is that all the themes are huge space wasters compared to Windows XP. This finally got me angry enough to create a customized version of the Clearlooks theme that tries to be very compact but still maintain its beautiful [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://brainstorm.ubuntu.com/idea/6772/"><img style="float:right; margin-left:20px; margin-bottom:20px" src="http://brainstorm.ubuntu.com/idea/6772/image/1/" /></a>I have been using <a href="http://www.ubuntu.com/">Ubuntu</a> for quite a while now, but one thing I really dislike is that all the themes are huge space wasters compared to Windows XP. This finally got me angry enough to create a customized version of the <a href="http://clearlooks.sourceforge.net/">Clearlooks</a> theme that tries to be very compact but still maintain its beautiful look. I like the result quite a lot, I have been using this theme for more than two weeks now and it works great. It is especially nice for intense applications like <a href="http://www.eclipse.org">Eclipse</a>.</p>
<p><strong>UPDATE</strong>: <a href="http://martin.ankerl.com/2008/11/04/human-compact-themes-for-ubuntu-810/">Human Compact Theme for Ubuntu 8.10 (Intrepid Ibex)</a> is available!</p>
<h1>Comparison</h1>
<p>Move your mouse over the image to see how the dialog looks like with clearlooks-compact. The buttons and spacing are smaller, which results in much more visible space for the actual content.</p>
<style type="text/css"><!-- #clearlooks a { display:block; background-image:url(/files/clearlooks.png); width:435px; height:421px; } #clearlooks a:hover {background-image:url(/files/clearlooks-compact.png); } --> </style>
<p><center></p>
<div id="clearlooks">
<a href="#">&nbsp;</a>
</div>
<p></center></p>
<h1>More Screenshots</h1>
<p>Here are some more screenshots that I have taken with Clearlooks Compact enabled. Especially the Eclipse shot is great, there the theme really shines. It is even more compact than the Windows XP look.</p>
<p><a href='http://martin.ankerl.com/wp-content/uploads/2008/01/calc.png' title='Gnome Calculator'><img src='http://martin.ankerl.com/wp-content/uploads/2008/01/calc.thumbnail.png' alt='Gnome Calculator' /></a> <a href='http://martin.ankerl.com/wp-content/uploads/2008/01/clearlooks-compact.png' title='Gnome File Selector'><img src='http://martin.ankerl.com/wp-content/uploads/2008/01/clearlooks-compact.thumbnail.png' alt='Gnome File Selector' /></a> <a href='http://martin.ankerl.com/wp-content/uploads/2008/01/eclipse-compact.png' title='Eclipse with Compact Theme'><img src='http://martin.ankerl.com/wp-content/uploads/2008/01/eclipse-compact.thumbnail.png' alt='Eclipse with Compact Theme' /></a> <a href='http://martin.ankerl.com/wp-content/uploads/2008/01/tracker.png' title='Tracker Search Tool'><img src='http://martin.ankerl.com/wp-content/uploads/2008/01/tracker.thumbnail.png' alt='Tracker Search Tool' /></a></p>
<p>If you are curious, I have used <a href="http://www.google.at/search?q=tahoma+ttf">Tahoma</a>, size 9 for the application font, and the <a href="http://www.ank.com.ar/fonts/">MiscFixed</a> for the sourcecode.</p>
<h1>Download &#038; Installation</h1>
<p>Installation is extremely simple, in Ubuntu 7.10 (Gutsy Gibbon) you can do it this way:</p>
<ol>
<li>Click System > Preferences > Appearance.
<li>Drag &#038; drop the link <a href="/files/ClearlooksCompact-1.5.tar.bz2">ClearlooksCompact-1.5.tar.bz2</a> into the Appearence window.
</ol>
<p>Beware that this is just definition of the Clearlooks control spacings. That means you have to have the clearlooks engine installed (which you most likely have, it is the default theme of Ubuntu). To change back, click on the currently active Theme, choose &#8220;Customize&#8221;, and select other controls instead of &#8220;Clearlooks Compact&#8221;.</p>
<h1>History</h1>
<p>I will regularly update this page when I update the theme with a new screenshot and the development history:</p>
<dl>
<dt>April 9th, 2009</dt>
<dd>Version 1.5: a bit smaller checkbox + selection box, less blurry and smaller progress bar.</dd>
<dt>April 5th, 2009</dt>
<dd>Version 1.4: added LGPL, index.theme, version number.</dd>
<dt>April 11th, 2008</dt>
<dd>Version 1.3: Small panel menu</dd>
<dt>November 11th, 2007</dt>
<dd>Version 1.2: Major update: Smaller handlers sizes, smaller scrollbars, no scrollbar spacing, less overall padding, and some more.</dd>
<dt>November 7th, 2007</dt>
<dd>Version 1.1: Now even more compact by reducing the default icon size to 16&#215;16 pixels.</dd>
<dt>November 4th, 2007</dt>
<dd>Version 1.0: First release of Clearlooks Compact.</dd>
</dl>
<div style='clear:both'></div><img src="http://martin.ankerl.com/?ak_action=api_record_view&id=100&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2007/11/04/clearlooks-compact-gnome-theme/feed/</wfw:commentRss>
		<slash:comments>82</slash:comments>
		</item>
	</channel>
</rss>
