<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>The corrosion of Aaron Stone</title>
 <link href="http://sodabrew.com/atom.xml" rel="self"/>
 <link href="http://sodabrew.com"/>
 <updated>2012-05-05T16:49:31-07:00</updated>
 <id>http://sodabrew.com</id>
 <author>
   <name>Aaron Stone</name>
   <email>aaron@serendipity.cx</email>
 </author>

 
 <entry>
   <title>Writing C Unit Tests in Ruby</title>
   <link href="http://sodabrew.com/2012/04/writing-c-unit-tests-in-ruby.html"/>
   <updated>2012-04-26T00:00:00-07:00</updated>
   <id>http://sodabrew.com/2012/04/writing-c-unit-tests-in-ruby</id>
   <content type="html">&lt;p&gt;Let&amp;#8217;s say you usually code in Ruby, and your company and its build systems are built around Rakefiles and the like. Today you&amp;#8217;ve written some C code, and you want to add unit tests. In this blog post, I present a method of writing those C unit tests in Ruby using &lt;a href='http://github.com/ffi/ffi'&gt;FFI&lt;/a&gt; and &lt;a href='http://rspec.info/'&gt;RSpec&lt;/a&gt;.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='c'&gt;&lt;span class='cm'&gt;/**&lt;/span&gt;
&lt;span class='cm'&gt; * This is a very silly function that clearly requires some unit tests.&lt;/span&gt;
&lt;span class='cm'&gt; */&lt;/span&gt;
&lt;span class='kt'&gt;int&lt;/span&gt; &lt;span class='nf'&gt;foo_count_letters&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;const&lt;/span&gt; &lt;span class='kt'&gt;char&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;source&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='kt'&gt;size_t&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;count&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='p'&gt;{&lt;/span&gt;
  &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='n'&gt;source&lt;/span&gt; &lt;span class='o'&gt;||&lt;/span&gt; &lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='n'&gt;count&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

  &lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;count&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;source&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;count&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;++&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;source&lt;/span&gt;&lt;span class='o'&gt;++&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='p'&gt;;&lt;/span&gt;

  &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;First, compile your C code as position independent and symbols exported. This allows you to dlopen() the executable:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='sh'&gt;&lt;span class='nv'&gt;$ &lt;/span&gt;gcc -pie -rdynamic -o foo foo.c
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Next, add the FFI gem to your Gemset, in &lt;code&gt;Gemfile&lt;/code&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;source&lt;/span&gt; &lt;span class='ss'&gt;:rubygems&lt;/span&gt;

&lt;span class='n'&gt;gem&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;ffi&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then write your rspec tests &lt;code&gt;spec/foo_spec.rb&lt;/code&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;#!/usr/bin/env ruby&lt;/span&gt;
&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;ffi&amp;#39;&lt;/span&gt;

&lt;span class='c1'&gt;# This module is your bridge from Ruby to C and back&lt;/span&gt;
&lt;span class='k'&gt;module&lt;/span&gt; &lt;span class='nn'&gt;FOO&lt;/span&gt;
  &lt;span class='kp'&gt;extend&lt;/span&gt; &lt;span class='no'&gt;FFI&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Library&lt;/span&gt;

  &lt;span class='c1'&gt;# Use an absolute path to the executable under test, otherwise ffi will search LD_LIBRARY_PATH.&lt;/span&gt;
  &lt;span class='n'&gt;ffi_lib&lt;/span&gt; &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;absolute_path&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;join&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;dirname&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='bp'&gt;__FILE__&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;..&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;

  &lt;span class='c1'&gt;# Function signatures for each function to be tested&lt;/span&gt;
  &lt;span class='n'&gt;attach_function&lt;/span&gt; &lt;span class='ss'&gt;:foo_count_letters&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:string&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:pointer&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:int&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;unit tests for foo.c&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;before&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:each&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;should really foo&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='c1'&gt;# This function takes a pointer-to-uint32 out-param&lt;/span&gt;
    &lt;span class='n'&gt;out&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;FFI&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;MemoryPointer&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt; &lt;span class='ss'&gt;:uint32&lt;/span&gt;

    &lt;span class='n'&gt;res&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;FOO&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;foo_count_letters&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;Hello&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;out&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;

    &lt;span class='c1'&gt;# Read back the pointers to Ruby data types, then use rspec&amp;#39;s verification functions&lt;/span&gt;
    &lt;span class='n'&gt;out&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;get_uint32&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='mi'&gt;5&lt;/span&gt;
    &lt;span class='n'&gt;res&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I&amp;#8217;m excited about this approach because the tests run under &lt;code&gt;rspec&lt;/code&gt; along with the rest of your spec tests.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Moving my Blog to GitHub</title>
   <link href="http://sodabrew.com/2012/04/moving-my-blog-to-github.html"/>
   <updated>2012-04-25T00:00:00-07:00</updated>
   <id>http://sodabrew.com/2012/04/moving-my-blog-to-github</id>
   <content type="html">&lt;p&gt;Today I moved my blog from my own server to GitHub. I exported my blog from Movable Type to Jekyll source files, checked it a GitHub repo, and pointed my domain&amp;#8217;s DNS at GitHub Pages.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Introducing a Memcached Module for Varnish 3</title>
   <link href="http://sodabrew.com/2012/01/introducing-varnish-memcached-module.html"/>
   <updated>2012-01-28T13:01:59-08:00</updated>
   <id>http://sodabrew.com/2012/01/introducing-varnish-memcached-module</id>
   <content type="html">&lt;p&gt;&lt;a href='http://varnish-cache.org'&gt;Varnish&lt;/a&gt; makes your websites go faster. &lt;a href='http://memcached.org'&gt;Memcached&lt;/a&gt;, makes your websites go faster. Blog posts abound on using Varnish&amp;#8217;s excellent embedded C functionality to link libmemcached into your VCLs, and Poul himself has written about his surprise in learning that many VCLs were actually thin wrappers around a C library where all of the business logic of a VCL would live.&lt;/p&gt;

&lt;p&gt;Starting in Varnish 3, the balance can now shift back towards the VCL itself as the driver of business logic, with first-class &amp;#8220;vmod&amp;#8221; modules providing new VCL functions. (If you&amp;#8217;ve been around a while, you might recognize the same progression that PHP took in the late 90&amp;#8217;s and early 2000&amp;#8217;s, back when PHP looked like a promising future.)&lt;/p&gt;

&lt;p&gt;Without further ado, I present &lt;a href='http://github.com/sodabrew/libvmod-memcached'&gt;libvmod-memcached&lt;/a&gt;, a Varnish Memcached Module. Here&amp;#8217;s a quick example script that flushed the cache for a page every 20 hits.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='cpp'&gt;&lt;span class='n'&gt;import&lt;/span&gt; &lt;span class='n'&gt;memcached&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

&lt;span class='n'&gt;sub&lt;/span&gt; &lt;span class='n'&gt;vcl_init&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
	&lt;span class='n'&gt;memcached&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='n'&gt;servers&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;localhost&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;

&lt;span class='n'&gt;sub&lt;/span&gt; &lt;span class='n'&gt;vcl_hit&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
	&lt;span class='k'&gt;if&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='n'&gt;memcached&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='n'&gt;incr&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;req&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='n'&gt;url&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
		&lt;span class='n'&gt;memcached&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='n'&gt;set&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;req&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='n'&gt;url&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;86400&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
	&lt;span class='p'&gt;}&lt;/span&gt;
	&lt;span class='k'&gt;if&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='n'&gt;memcached&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='n'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;req&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='n'&gt;url&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;20&amp;quot;&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
		&lt;span class='n'&gt;purge_url&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;req&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='n'&gt;url&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
	&lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Note that VCL does not allow arbitrary variables, so I&amp;#8217;m doing two memcached queries here. Fixing that will be another blog post!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Things Dilburn learned at Burning Man</title>
   <link href="http://sodabrew.com/2011/09/what-we-learned-at-burning-man.html"/>
   <updated>2011-09-26T14:58:19-07:00</updated>
   <id>http://sodabrew.com/2011/09/what-we-learned-at-burning-man</id>
   <content type="html">&lt;p&gt;The Dilburn campers jotted some useful notes on a little whiteboard at our camp. Eventually I wanted to erase the whiteboard, so here&amp;#8217;s what it said!&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Burning Man is what you make it.&lt;/li&gt;
	&lt;li&gt;RVs are really nice.&lt;/li&gt;
	&lt;li&gt;Art cars are fun!&lt;/li&gt;
	&lt;li&gt;Hexayurts are the way of the future.&lt;/li&gt;
	&lt;li&gt;Tents are dusty.&lt;/li&gt;
	&lt;li&gt;White carports don't reflect enough sun.&lt;/li&gt;
	&lt;li&gt;Bring extra rebar and sledgehammers. Not just extra. Bring too much.&lt;/li&gt;
	&lt;li&gt;Coffee.&lt;/li&gt;
	&lt;li&gt;Couches.&lt;/li&gt;
	&lt;li&gt;NO PACKAGING!&lt;/li&gt;
	&lt;li&gt;Repack everything into bins, sorted by type-of-thing.&lt;/li&gt;
	&lt;li&gt;Bring power tools. Charged.&lt;/li&gt;
	&lt;li&gt;Try camping on the 7:30 side. It's crowded, and different than the 4:30 side.&lt;/li&gt;
	&lt;li&gt;Create wind and sun breaks.&lt;/li&gt;
	&lt;li&gt;Designate a shit table.&lt;/li&gt;
	&lt;li&gt;Give foot baths.&lt;/li&gt;
	&lt;li&gt;Drinks are communal. Expect your beer cooler to be raided, so just have everyone pay in upfront.&lt;/li&gt;
	&lt;li&gt;There's no such thing as a quick trip at Burning Man - never say, &quot;I'll be right back!&quot;&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>Upgrading an HP dv2000</title>
   <link href="http://sodabrew.com/2011/05/upgrading-hp-dv2000.html"/>
   <updated>2011-05-25T18:17:40-07:00</updated>
   <id>http://sodabrew.com/2011/05/upgrading-hp-dv2000</id>
   <content type="html">&lt;p&gt;My gal has a laptop that she really likes, an HP dv2000 - dv2225nr to be exact - even though it&amp;#8217;s slooow. I&amp;#8217;d gotten pretty near to talking her into replacing it when the new job provided a spiffy ThinkPad that she can bring home now and then. Needing only a personal machine to sync her iPhone and surf the web, I said, &amp;#8220;What if we just put in a hundred bucks to make it less slow and do a Windows Vista detox?&amp;#8221;&lt;/p&gt;

&lt;p&gt;Ok, $185 bucks later, and I have some recommendations to make to the lazywebs about this laptop model.&lt;/p&gt;

&lt;p&gt;Things I learned:&lt;/p&gt;

&lt;p&gt;The AMD Turion 64 x2 with GeForce Go 6150 chipset in this system will happily accept sticks of 4GB DDR2 RAM, probably for a maximum capacity of 8GB. But I stopped at mixing a 4GB stick with an existing 1GB stick, for a total of 5GB.&lt;/p&gt;

&lt;p&gt;Check in the BIOS how much RAM is set aside for that GeForce Go 6150. The default is probably 64MB from the factory (with the default 1GB memory configuration, this makes sense I suppose), but you can go to 128MB. Now that 128MB is basically a rounding error on the total memory size, use it.&lt;/p&gt;

&lt;p&gt;I tried to clone the original hard drive, but taking it out of the machine caused it to lose its magic smoke. That meant my Windows 7 Upgrade edition was no longer valid for a clean install on a new 7200RPM drive. Follow these directions to get around that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finish the installation with the activate-later option.&lt;/li&gt;

&lt;li&gt;Once you&amp;#8217;re up and running, run &lt;tt&gt;regedit&lt;/tt&gt; as Administrator&lt;/li&gt;

&lt;li&gt;Change this key from 1 to 0:&lt;br /&gt;&lt;tt&gt;HKEY_LOCAL_MACHINE/Software/Microsoft/Windows/CurrentVersion/Setup/OOBE/MediaBootInstall&lt;/tt&gt;&lt;/li&gt;

&lt;li&gt;Close &lt;tt&gt;regedit&lt;/tt&gt;&lt;/li&gt;

&lt;li&gt;Run &lt;tt&gt;cmd&lt;/tt&gt; as Administrator&lt;/li&gt;

&lt;li&gt;Run &lt;tt&gt;slmgr /rearm&lt;/tt&gt; at the command line&lt;/li&gt;

&lt;li&gt;Close &lt;tt&gt;cmd&lt;/tt&gt;&lt;/li&gt;

&lt;li&gt;Activate by going to System -&amp;gt; Change product key&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Windows 7 64-bit runs great, uses all of the RAM and all that jazz. [Insert pointless argument about pointer sizes and 64-bit bloat and how I&amp;#8217;d be better off with 3.5GB usable RAM at 32-bits. I don&amp;#8217;t care; everything else I touch these days is 64-bit. Consistency FTW.]&lt;/p&gt;

&lt;p&gt;Finally, the 1.6GHz Turion TL-50 CPU sits in an S1G1 socket, so $20 got me a 2GHz TL-60 with double the L1 cache and a 31W TDP, down from 35W. Runs faster, cooler, and I pretend that the battery lasts a little more. That&amp;#8217;s what I told my girlfriend, anyhow! Winning!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>DilBURN: Get Fired!</title>
   <link href="http://sodabrew.com/2011/04/dilburn.html"/>
   <updated>2011-04-16T15:01:09-07:00</updated>
   <id>http://sodabrew.com/2011/04/dilburn</id>
   <content type="html">&lt;h2 id='dilburn_get_fired_a_burning_man_2011_theme_camp'&gt;Dilburn: Get Fired! a Burning Man 2011 theme camp.&lt;/h2&gt;

&lt;h3 id='short_description'&gt;Short description:&lt;/h3&gt;

&lt;p&gt;Escape the corporate ratrace - come to Dilburn to get &amp;#8220;fired.&amp;#8221; Pick up your dream job title in the lobby. Come join our office cubicle mixer after hours!&lt;/p&gt;

&lt;h3 id='long_description'&gt;Long description:&lt;/h3&gt;

&lt;p&gt;Burners can wander our office cubicle maze in search of more meaningful paths. Your first job in cubitraz that may not have met your dreams. Take back your dream! Our wide ties, blue blazers, and black rimmed glasses will teleport you to an alternate reality where you get to be the executive outer space cab driver, senior couch potato, regional manager of coitus, horse and buggy driver, sunbath coordinator, daydream distributor, professional shusher &amp;#8211; shhh, we&amp;#8217;re trying to work here!&lt;/p&gt;

&lt;p&gt;Relax to our muzak and let our inspirational posters boost your productivity by the minute. Be sure to stop by for the office mixer! This is not your daddy&amp;#8217;s cube farm!&lt;/p&gt;

&lt;h3 id='strawman_layout'&gt;Strawman layout:&lt;/h3&gt;

&lt;p&gt;&lt;img src='files/dilburn-layout.jpg' alt='Dilburn Layout' /&gt;&lt;/p&gt;

&lt;h3 id='layout_description'&gt;Layout description:&lt;/h3&gt;

&lt;p&gt;The office portion of the camp will open to the road. This is the theme camp / interactive space; a cubicle farm and maze under a 25&amp;#8217; to 30&amp;#8217; shade structure. Behind the cubicles, vehicles will be used as a perimeter and personal tents arranged inside. Approximately 10 personal tents and smaller shades are expected. Shared spaces will include a 20&amp;#8217; diameter shade structure, 10&amp;#8217;x20&amp;#8217; carport cooking and eating space, evaporation device, shower bag structure, and various comfy camping chairs. We will attempt to use solar power, and may supplement with a small Honda-type generator.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Domains for Sale</title>
   <link href="http://sodabrew.com/2011/04/domains-for-sale.html"/>
   <updated>2011-04-16T14:56:10-07:00</updated>
   <id>http://sodabrew.com/2011/04/domains-for-sale</id>
   <content type="html">&lt;p&gt;I have a few domains for sale. Would you like to buy one? Contact me and let&amp;#8217;s discuss!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Whole Wheat Oatmeal Teff Chocolate Chip Cookies</title>
   <link href="http://sodabrew.com/2010/02/whole-wheat-oatmeal-teff-chocolate-chip-cookies.html"/>
   <updated>2010-02-26T10:41:14-08:00</updated>
   <id>http://sodabrew.com/2010/02/whole-wheat-oatmeal-teff-chocolate-chip-cookies</id>
   <content type="html">&lt;p&gt;The title is quite a mouthful, and so are these cookies! Crunchy, soft, crumbly, textured, tasty, and as it happens, vegan and parve! I made this recipe up last weekend while it was raining in San Francisco, and had a hankering for cookies. Ate a bunch, and brought the rest in to work to share and meet my coworkers. We all knew it was a rainy weekend, because the company message board was full of &amp;#8220;extra cookies in the break room!&amp;#8221; messages :)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2/3 cup whole wheat flour&lt;/li&gt;

&lt;li&gt;2/3 c. oatmeal&lt;/li&gt;

&lt;li&gt;1/3 c. teff flour&lt;/li&gt;

&lt;li&gt;1/2 c. sugar (white, demerara, brown, etc.)&lt;/li&gt;

&lt;li&gt;1/3 c. olive oil&lt;/li&gt;

&lt;li&gt;1/3 c. dark chocolate chips&lt;/li&gt;

&lt;li&gt;2 tbsp. vanilla&lt;/li&gt;

&lt;li&gt;1 tsp. baking soda&lt;/li&gt;

&lt;li&gt;1 tsp. baking powder&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now you&amp;#8217;re probably looking through that list and thinking, &amp;#8220;Ok, all that looks familiar, except for that teff stuff. What&amp;#8217;s that!?&amp;#8221; Teff is a grain grown in Ethiopia. It&amp;#8217;s one of the most protein-dense grains, and also the smallest whole grain. Ethiopians use it to make their native style of bread, called &lt;em&gt;injera&lt;/em&gt;, which I can best describe as a sourdough crêpe. Bob&amp;#8217;s Red Mill sells &lt;a href='http://www.bobsredmill.com/teff-flour.html'&gt;teff flour&lt;/a&gt;, available at most natural foods stores and Whole Foods.&lt;/p&gt;

&lt;p&gt;Next time I make this recipe, I might also throw in some frozen concentrated orange juice to add a little bit more binding to the finished batter. Eggs would do the trick, too, but I didn&amp;#8217;t have any in the fridge when I whipped this up.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Ikea Hacking: Gorm Wine Rack</title>
   <link href="http://sodabrew.com/2010/01/ikea-hacking-gorm-wine-rack.html"/>
   <updated>2010-01-04T13:32:11-08:00</updated>
   <id>http://sodabrew.com/2010/01/ikea-hacking-gorm-wine-rack</id>
   <content type="html">&lt;p&gt;Ikea has at least half a dozen options for wine storage, but its Gorm shelf system takes the cake for versatility. The Gorm is made of solid, unfinished pine, allowing you to hack it more easily than Ikea products made of cardboard, &lt;strike&gt;spit shine&lt;/strike&gt; veneer, and plastic cams. Gorms can stand alone, be chained together, mixed-and-matched with any part in the series, and, because of its simple, solid wood construction, sawed, drilled, screwed, painted, or stained to your heart&amp;#8217;s content.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://www.flickr.com/photos/sodabrew/4251773978/'&gt;&lt;img src='http://farm3.static.flickr.com/2759/4251773978_abdac4dbf3_m.jpg' alt='Gorm Wine and Glass Rack by sodabrew, on Flickr' /&gt;&lt;/a&gt; For this hack, I started with a &lt;a href='http://www.ikea.com/us/en/catalog/products/30058508'&gt;Gorm 30&amp;#8221;w x 13&amp;#8221;d x 68&amp;#8221;h kit&lt;/a&gt;, using three of the four shelves, and mixed in three more &lt;a href='http://www.ikea.com/us/en/catalog/products/10058514'&gt;Gorm wine rack shelves&lt;/a&gt;. Before I left Ikea, I went over to the parts department and got eight more screws to match the ones that hold the backstays onto the Gorm.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://www.flickr.com/photos/sodabrew/4251786904/'&gt;&lt;img src='http://farm3.static.flickr.com/2748/4251786904_1256a74a7b_m.jpg' alt='Adding stemware hangers to a Gorm shelf by sodabrew, on Flickr' /&gt;&lt;/a&gt; I picked up two &lt;a href='http://www.bedbathandbeyond.com/product.asp?order_num=-1&amp;amp;SKU=14914927'&gt;chrome wine glass racks&lt;/a&gt; and a &lt;a href='http://www.bedbathandbeyond.com/product.asp?order_num=-1&amp;amp;SKU=103162&amp;amp;RN=59'&gt;dozen wine glasses&lt;/a&gt; from Bed, Bath &amp;amp; Beyond, screwed the racks to the underside of the top Gorm shelf (with those extra screws from Ikea), and voilà, my very own wine bar!&lt;/p&gt;
&lt;em&gt;Gorm assembly hint: get a 10mm socket for your drill-driver.&lt;/em&gt;
&lt;p&gt;&lt;a href='http://amzn.com/B000T9U9JE'&gt;&lt;img src='http://ecx.images-amazon.com/images/I/31G0beqf%2BML._SL500_SS75_.jpg' alt='10mm nut driver' /&gt;&lt;/a&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Python Meta Decorators</title>
   <link href="http://sodabrew.com/2009/12/python-meta-decorators.html"/>
   <updated>2009-12-08T12:08:16-08:00</updated>
   <id>http://sodabrew.com/2009/12/python-meta-decorators</id>
   <content type="html">&lt;p&gt;Recently, I was working on a project in Python framework that was built around decorators. Each of my functions needed something like six decorators, each with its own arguments, but mostly all the same. I thought, &amp;#8220;This is a classic case of cut-and-paste coding; there has to be a better way!&amp;#8221; I toiled over decorators for a while, and finally came up with this pattern:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;monkey&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;arg&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;outer&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;f&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;inner&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;args&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;**&lt;/span&gt;&lt;span class='n'&gt;kwargs&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
      &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;Monkey: &lt;/span&gt;&lt;span class='si'&gt;%s&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;%&lt;/span&gt; &lt;span class='n'&gt;arg&lt;/span&gt;
      &lt;span class='n'&gt;f&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;args&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;**&lt;/span&gt;&lt;span class='n'&gt;kwargs&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;inner&lt;/span&gt;
  &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;outer&lt;/span&gt;

&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;zombie&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;arg&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;outer&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;f&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;inner&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;args&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;**&lt;/span&gt;&lt;span class='n'&gt;kwargs&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
      &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;Zombie: &lt;/span&gt;&lt;span class='si'&gt;%s&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;%&lt;/span&gt; &lt;span class='n'&gt;arg&lt;/span&gt;
      &lt;span class='n'&gt;f&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;args&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;**&lt;/span&gt;&lt;span class='n'&gt;kwargs&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;inner&lt;/span&gt;
  &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;outer&lt;/span&gt;

&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;wrapper&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;m&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;z&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;outer&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;f&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
    &lt;span class='nd'&gt;@monkey&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;m&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='nd'&gt;@zombie&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;z&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;inner&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;args&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;**&lt;/span&gt;&lt;span class='n'&gt;kwargs&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
      &lt;span class='n'&gt;f&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;args&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;**&lt;/span&gt;&lt;span class='n'&gt;kwargs&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;inner&lt;/span&gt;
  &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;outer&lt;/span&gt;

&lt;span class='nd'&gt;@wrapper&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;coconut&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;brains&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;mytesta&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;foo&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
  &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='n'&gt;foo&lt;/span&gt;

&lt;span class='nd'&gt;@wrapper&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;bacon&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;chainsaw&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;mytestb&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;foo&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
  &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='n'&gt;foo&lt;/span&gt;

&lt;span class='n'&gt;mytesta&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;Hello World&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;mytestb&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;Hello World&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;What I&amp;#8217;m doing here is first setting up two standard argument-taking decorators, @monkey and @zombie. Then I&amp;#8217;m setting up a decorator that returns a decorated function, whose arguments are built at decoration time. This lets me template out a complex decoration pattern where only a few arguments need to change for each function, and pass just those arguments into my meta-decorator.&lt;/p&gt;

&lt;p&gt;This is the output:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='sh'&gt;Monkey: coconut
Zombie: brains
Hello World

Monkey: bacon
Zombie: chainsaw
Hello World
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>The Globe</title>
   <link href="http://sodabrew.com/2009/10/the-globe.html"/>
   <updated>2009-10-20T18:54:31-07:00</updated>
   <id>http://sodabrew.com/2009/10/the-globe</id>
   <content type="html">&lt;p&gt;Since it&amp;#8217;s my birthday, I&amp;#8217;ll share my new favorite drink:&lt;/p&gt;

&lt;p&gt;The Globe from the &lt;a href='http://sfist.com/2009/04/17/sfist_drinks_the_globe_cocktail.php'&gt;SFist&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3 oz. 209 Gin&lt;/li&gt;

&lt;li&gt;1 oz. St. Germain&lt;/li&gt;

&lt;li&gt;1 oz. lime juice&lt;/li&gt;

&lt;li&gt;1/2 oz. agave nectar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Shake and serve up with a mint garnish.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Convert a Postfix queue to mbox format</title>
   <link href="http://sodabrew.com/2009/10/convert-postfix-queue-to-mbox.html"/>
   <updated>2009-10-12T20:48:05-07:00</updated>
   <id>http://sodabrew.com/2009/10/convert-postfix-queue-to-mbox</id>
   <content type="html">&lt;p&gt;Today I wanted to convert the contents of my postfix &amp;#8216;deferred&amp;#8217; queue, which was all spam stuck in my MTA, to mbox format so that I could feed it into various spam-learning systems.&lt;/p&gt;

&lt;p&gt;First I converted my Postfix queue to human-readable format with postcat:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='sh'&gt;&lt;span class='nb'&gt;cd&lt;/span&gt; /var/spool/postfix/deferred
mkdir spam
&lt;span class='k'&gt;for &lt;/span&gt;i in &lt;span class='o'&gt;{&lt;/span&gt;0..9&lt;span class='o'&gt;}&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;A..F&lt;span class='o'&gt;}&lt;/span&gt;; &lt;span class='k'&gt;do &lt;/span&gt;mkdir spam/&lt;span class='nv'&gt;$i&lt;/span&gt;; &lt;span class='k'&gt;done&lt;/span&gt;
&lt;span class='k'&gt;for &lt;/span&gt;i in &lt;span class='sb'&gt;`&lt;/span&gt;ls */*&lt;span class='sb'&gt;`&lt;/span&gt;; &lt;span class='k'&gt;do &lt;/span&gt;postcat &lt;span class='nv'&gt;$i&lt;/span&gt; &amp;gt; spam/&lt;span class='nv'&gt;$i&lt;/span&gt;; &lt;span class='k'&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This made a copy of each file in postcat format, but that&amp;#8217;s only halfway there &amp;#8211; postcat has its own output format that isn&amp;#8217;t anything like an mbox or a maildir. Inspecting the output, and brushing up on my sed, I came up with this:&lt;/p&gt;

&lt;p&gt;A final pass over all of the messages, and I had my mbox file to train SpamAssassin with:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='sh'&gt;&lt;span class='k'&gt;for &lt;/span&gt;i in &lt;span class='sb'&gt;`&lt;/span&gt;ls */*&lt;span class='sb'&gt;`&lt;/span&gt;; &lt;span class='k'&gt;do &lt;/span&gt;sh mkmbox.sh &amp;lt; &lt;span class='nv'&gt;$i&lt;/span&gt; &amp;gt;&amp;gt; spam.mbox; &lt;span class='k'&gt;done&lt;/span&gt;
sa-learn --spam --mbox spam.mbox
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>Recipe for Seitan Stew</title>
   <link href="http://sodabrew.com/2009/10/seitan-stew-recipe.html"/>
   <updated>2009-10-10T17:13:49-07:00</updated>
   <id>http://sodabrew.com/2009/10/seitan-stew-recipe</id>
   <content type="html">&lt;p&gt;Found in a backcopy of Vegetarian Journal, March 1996:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 cup of water plus 1/2 cup water&lt;/li&gt;

&lt;li&gt;1 ounce dried wild mushrooms&lt;/li&gt;

&lt;li&gt;1 Tablespoon oil&lt;/li&gt;

&lt;li&gt;1 large onion, chopped&lt;/li&gt;

&lt;li&gt;2 carrots, diced&lt;/li&gt;

&lt;li&gt;3 small turnips, peeled and cut in quarters&lt;/li&gt;

&lt;li&gt;4-5 small potatoes, cut in half&lt;/li&gt;

&lt;li&gt;1/2 pound mushrooms, halved&lt;/li&gt;

&lt;li&gt;3 dried tomatoes, made into powder&lt;/li&gt;

&lt;li&gt;8 ounces seitan, cut in small chunks&lt;/li&gt;

&lt;li&gt;1 teaspoon dried rosemary&lt;/li&gt;

&lt;li&gt;1 teaspoon dried thyme&lt;/li&gt;

&lt;li&gt;1 teaspoon dried sage&lt;/li&gt;

&lt;li&gt;1 Tablespoon miso&lt;/li&gt;

&lt;li&gt;1 Tablespoon arrowroot&lt;/li&gt;

&lt;li&gt;2 Tablespoons fresh chopped parsley&lt;/li&gt;

&lt;li&gt;Black pepper to taste&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Boil one cup of the water and soak the dried mushrooms (if they are morels or shiitake) for 30 minutes. Save soaking water. If using porcini add when recommended.&lt;/p&gt;

&lt;p&gt;Heat oil in pan over medium heat. Add onion, carrot, turnips, and potatoes. Sauté for 3 to 5 minutes until onion begins to soften. Add fresh mushrooms, tomato powder, and 1/4 cup water. Cook for 5 more minutes. Then add seitan chunks, dried herbs, and rehydrated mushrooms that have been cut in pieces. Cook for 5 more minutes.&lt;/p&gt;

&lt;p&gt;Add soaking water drained of any debris and porcini, if using them. Add the miso and stir. Cook for about 10 more minutes until vegetables are almost tender.&lt;/p&gt;

&lt;p&gt;Combine the remaining 1/4 cup water with the arrowroot and add to the pan over medium heat, stirring until thickened. If too thick add water 1 tablespoon at a time. If too thin add arrowroot 1 teaspoon at a time. Season with black pepper. Add parsley just before serving.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Health care reform story spotlights selfish stupidity</title>
   <link href="http://sodabrew.com/2009/10/health-care-reform-story-spotlights-selfish-stupidity.html"/>
   <updated>2009-10-08T15:56:30-07:00</updated>
   <id>http://sodabrew.com/2009/10/health-care-reform-story-spotlights-selfish-stupidity</id>
   <content type="html">&lt;p&gt;A &lt;a href='http://news.yahoo.com/s/ap/20091007/ap_on_go_pr_wh/us_ap_poll_health_care'&gt;recent AP story&lt;/a&gt; about health care spotlights the sort of close-minded, numb stupidity that fuels anti-reformers:&lt;/p&gt;
&lt;blockquote&gt;Andrew Newcomb, 28, who works in sales and lives near Destin, Fla., said he doesn't think taxpayers should have to take on the costs of covering the uninsured.

&quot;I don't want my tax money to pay for some pill-popper to fake some injury and go to the hospital when I don't ever go to the hospital,&quot; said Newcomb, adding he can afford to go to the doctor and pay $60 for a checkup.&lt;/blockquote&gt;
&lt;p&gt;Andrew, since you never go to the hospital, I&amp;#8217;m sure it won&amp;#8217;t ever be a problem. But if you do get sick, be sure to &lt;a href='http://video.google.com/videosearch?q=alan+grayson+die+quickly'&gt;die quickly&lt;/a&gt;. Otherwise you might cost us taxpayers a lot of money at a taxpayer-funded emergency room.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Updating Soekris firmware using Kermit</title>
   <link href="http://sodabrew.com/2009/09/updating-soekris-firmware-using-kermit.html"/>
   <updated>2009-09-23T18:59:44-07:00</updated>
   <id>http://sodabrew.com/2009/09/updating-soekris-firmware-using-kermit</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve had trouble getting minicom&amp;#8217;s xmodem to fully upload a Soekris firmware image over USB serial adapters, and I&amp;#8217;ve never been a big fan of minicom in the first place. I like good old Kermit. Recently I discovered how to get Kermit to speak xmodem, and used it to update the firmware on my Soekris Net4801.&lt;/p&gt;

&lt;p&gt;First, install kermit and lrzsz. Next, connect your Soekris box. Now fire up kermit and go!&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='sh'&gt;&lt;span class='nv'&gt;$ &lt;/span&gt;kermit

&lt;span class='nb'&gt;set &lt;/span&gt;protocol xmodem-crc download &lt;span class='o'&gt;{}&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;lsx %s&lt;span class='o'&gt;}&lt;/span&gt; &lt;span class='o'&gt;{}&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;lrx %s&lt;span class='o'&gt;}&lt;/span&gt; &lt;span class='o'&gt;{}&lt;/span&gt;
&lt;span class='nb'&gt;set &lt;/span&gt;line /dev/ttyUSB0
&lt;span class='nb'&gt;set &lt;/span&gt;speed 19200
&lt;span class='nb'&gt;set &lt;/span&gt;carrier-watch off
&lt;span class='nb'&gt;set &lt;/span&gt;flow none
connect

&amp;gt; download -

send /binary firmware-file-name
connect

&amp;gt; flashupdate
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>Python's Lame Lexical Closures</title>
   <link href="http://sodabrew.com/2009/08/python-lame-lexical-closures.html"/>
   <updated>2009-08-12T07:14:08-07:00</updated>
   <id>http://sodabrew.com/2009/08/python-lame-lexical-closures</id>
   <content type="html">&lt;p&gt;Here&amp;#8217;s a simple generator function in Python that you can use in a test harness to find out how many times the function was called. Call the function once with an argument, and then each time you call the function again it will return that argument and increment an internal counter. Call the function with the named argument &amp;#8216;got_called&amp;#8217; and it will reset and return its current call count.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;GotCalled&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;ret&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
  &lt;span class='sd'&gt;&amp;quot;&amp;quot;&amp;quot;Stub that counts how many times it was called.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
  &lt;span class='n'&gt;count&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;_GotCalled&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;unused_args&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;**&lt;/span&gt;&lt;span class='n'&gt;kwargs&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;kwargs&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;got_called&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
      &lt;span class='n'&gt;lame&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;count&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt;
      &lt;span class='n'&gt;count&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;
      &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;lame&lt;/span&gt;
    &lt;span class='k'&gt;else&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;
      &lt;span class='n'&gt;count&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;+=&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;
      &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;ret&lt;/span&gt;

  &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;_GotCalled&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;But note how count is a list. And I&amp;#8217;m incrementing and returning the first member of the list. Guess what &amp;#8211; you can&amp;#8217;t use a variable directly in this situation! It&amp;#8217;ll error out on the &amp;#8216;count += 1&amp;#8217; because the act of assigning to the variable in the inner function &lt;i&gt;creates a new instance of that
variable&lt;/i&gt;, one that hasn&amp;#8217;t been used before and so fails the + part of the +=. LAME.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Perl Hash Slices</title>
   <link href="http://sodabrew.com/2009/07/perl-hash-slices.html"/>
   <updated>2009-07-17T15:56:58-07:00</updated>
   <id>http://sodabrew.com/2009/07/perl-hash-slices</id>
   <content type="html">&lt;p&gt;One of my favorite things to do with Perl hashes is slice them with this incredibly concise syntax. The first time I saw this, I Just Got It (TM). Lifting a chunk of text from the excellent (though dated) online book &lt;i&gt;[Picking Up Perl](http://www.ebb.org/PickingUpPerl/)&lt;/i&gt;, here&amp;#8217;s how it works:&lt;/p&gt;

&lt;h3 id='slices'&gt;Slices&lt;/h3&gt;

&lt;p&gt;It turns out you can slice hashes just like you were able to slice arrays. This can be useful if you need to extract a certain set of values out of a hash into a list.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='perl'&gt;&lt;span class='k'&gt;use&lt;/span&gt; &lt;span class='n'&gt;strict&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='k'&gt;my&lt;/span&gt; &lt;span class='nv'&gt;%table&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='sx'&gt;qw/schmoe joe smith john simpson bart/&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='k'&gt;my&lt;/span&gt; &lt;span class='nv'&gt;@friends&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;@table&lt;/span&gt;&lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;schmoe&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;smith&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;};&lt;/span&gt;
&lt;span class='c1'&gt;# @friends has qw/joe john/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Note the use of the &lt;i&gt;@&lt;/i&gt; in front of the hash name. This shows that we are indeed producing a normal list, and you can use this construct in any list context you would like.&lt;/p&gt;

&lt;h3 id='context_considerations'&gt;Context Considerations&lt;/h3&gt;

&lt;p&gt;We have now discussed all the different ways you can use variables in list and scalar context. At this point, it might be helpful to review all the ways we have used variables in different contexts. The table that follows identifies many of the ways variables are used in Perl.&lt;/p&gt;
&lt;table&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;strong&gt;Expression&lt;/strong&gt;&lt;/td&gt;
    &lt;td&gt;&lt;strong&gt;Context&lt;/strong&gt;&lt;/td&gt;
    &lt;td&gt;&lt;strong&gt;Variable&lt;/strong&gt;&lt;/td&gt;
    &lt;td&gt;&lt;strong&gt;Evaluates to&lt;/strong&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;&lt;code&gt;$scalar&lt;/code&gt; &lt;/td&gt;&lt;td&gt; scalar &lt;/td&gt;&lt;td&gt; &lt;code&gt;$scalar&lt;/code&gt;, a scalar&lt;/td&gt;&lt;td&gt; the value held in &lt;code&gt;$scalar&lt;/code&gt;&lt;/td&gt; &lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;&lt;code&gt;@array&lt;/code&gt; &lt;/td&gt;&lt;td&gt; list &lt;/td&gt;&lt;td&gt; &lt;code&gt;@array&lt;/code&gt;, an array&lt;/td&gt;&lt;td&gt; the list of values (in order) held in &lt;code&gt;@array&lt;/code&gt;&lt;/td&gt; &lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;&lt;code&gt;@array&lt;/code&gt; &lt;/td&gt;&lt;td&gt; scalar &lt;/td&gt;&lt;td&gt; &lt;code&gt;@array&lt;/code&gt;, an array&lt;/td&gt;&lt;td&gt; the total number of elements in &lt;code&gt;@array&lt;/code&gt; (same as &lt;code&gt;$\#array + 1&lt;/code&gt;)&lt;/td&gt; &lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;&lt;code&gt;$array\[$x\]&lt;/code&gt; &lt;/td&gt;&lt;td&gt; scalar &lt;/td&gt;&lt;td&gt; &lt;code&gt;@array&lt;/code&gt;, an array&lt;/td&gt;&lt;td&gt; the &lt;code&gt;($x+1)&lt;/code&gt;th element of &lt;code&gt;@array&lt;/code&gt;&lt;/td&gt; &lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;&lt;code&gt;$\#array&lt;/code&gt; &lt;/td&gt;&lt;td&gt; scalar &lt;/td&gt;&lt;td&gt; &lt;code&gt;@array&lt;/code&gt;, an array&lt;/td&gt;&lt;td&gt; the subscript of the last element in &lt;code&gt;@array&lt;/code&gt; (same as &lt;code&gt;@array -1&lt;/code&gt;)&lt;/td&gt; &lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;&lt;code&gt;@array\[$x, $y\]&lt;/code&gt; &lt;/td&gt;&lt;td&gt; list &lt;/td&gt;&lt;td&gt; &lt;code&gt;@array&lt;/code&gt;, an array&lt;/td&gt;&lt;td&gt; a slice, listing two elements from &lt;code&gt;@array&lt;/code&gt; (same as &lt;code&gt;($array[$x], $array[$y])&lt;/code&gt;)&lt;/td&gt; &lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;&lt;code&gt;&quot;$scalar&quot;&lt;/code&gt; &lt;/td&gt;&lt;td&gt; scalar \(interpolated\) &lt;/td&gt;&lt;td&gt; &lt;code&gt;$scalar&lt;/code&gt;, a scalar&lt;/td&gt;&lt;td&gt; a string containing the contents of &lt;code&gt;$scalar&lt;/code&gt;&lt;/td&gt; &lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;&lt;code&gt;&quot;@array&quot;&lt;/code&gt; &lt;/td&gt;&lt;td&gt; scalar \(interpolated\) &lt;/td&gt;&lt;td&gt; &lt;code&gt;@array&lt;/code&gt;, an array&lt;/td&gt;&lt;td&gt; a string containing the elements of &lt;code&gt;@array&lt;/code&gt;, separated by spaces&lt;/td&gt; &lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;&lt;code&gt;%hash&lt;/code&gt; &lt;/td&gt;&lt;td&gt; list &lt;/td&gt;&lt;td&gt; &lt;code&gt;%hash&lt;/code&gt;, a hash&lt;/td&gt;&lt;td&gt; a list of alternating keys and values from &lt;code&gt;%hash&lt;/code&gt;&lt;/td&gt; &lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;&lt;code&gt;$hash\{$x\}&lt;/code&gt; &lt;/td&gt;&lt;td&gt; scalar &lt;/td&gt;&lt;td&gt; &lt;code&gt;%hash&lt;/code&gt;, a hash&lt;/td&gt;&lt;td&gt; the element from &lt;code&gt;%hash&lt;/code&gt; with the key of &lt;code&gt;$x&lt;/code&gt;&lt;/td&gt; &lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;&lt;code&gt;@hash\{$x, $y\}&lt;/code&gt; &lt;/td&gt;&lt;td&gt; list &lt;/td&gt;&lt;td&gt; &lt;code&gt;%hash&lt;/code&gt;, a hash&lt;/td&gt;&lt;td&gt; a slice, listing two elements from &lt;code&gt;%hash&lt;/code&gt; \(same as &lt;code&gt;($hash\{$x\}, $hash\{$y\}\)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</content>
 </entry>
 
 <entry>
   <title>On Republicans and Obama's healthcare plans</title>
   <link href="http://sodabrew.com/2009/06/obama-healthcare-and-republicans.html"/>
   <updated>2009-06-15T22:56:47-07:00</updated>
   <id>http://sodabrew.com/2009/06/obama-healthcare-and-republicans</id>
   <content type="html">&lt;p&gt;From this AP story on &lt;a href='http://news.yahoo.com/s/ap/20090616/ap_on_go_pr_wh/us_obama_doctors'&gt;Obama pressing doctors to back health care overhaul&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;GOP Rep. Tom Price of Georgia &amp;#8211; a former orthopedic surgeon &amp;#8211; reacted preemptively to Obama&amp;#8217;s speech by accusing him of seeking a &amp;#8220;government takeover&amp;#8221; of health care. Speaking to reporters on a conference call organized by the Republican National Committee, Price said a committee that Obama&amp;#8217;s administration has established to study the effectiveness of various medical treatments would turn into a &amp;#8220;rationing board&amp;#8221; to overrule doctors and deny patients care. Sen. Jon Kyl, R-Ariz., and other Republicans introduced legislation to ban the rationing of care on such a basis.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;em&gt;Hello, pot? Yeah, this is kettle. You're black! &lt;/em&gt;
&lt;p&gt;If these guys are going to draft legislation that prevents all insurance companies from denying coverage, awesome. If they allow private insurers to cut coverage but not a future public insurance, that&amp;#8217;s just one more scummy way that Republicans write laws specifically to doom government agencies to fail, then rail against those same agencies saying they shouldn&amp;#8217;t exist.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Slicehost as secondary DNS and backup MX</title>
   <link href="http://sodabrew.com/2009/06/slicehost-secondary-dns-backup-mx.html"/>
   <updated>2009-06-02T11:18:50-07:00</updated>
   <id>http://sodabrew.com/2009/06/slicehost-secondary-dns-backup-mx</id>
   <content type="html">&lt;p&gt;This blog runs on my own server, on my own DSL line, with my own domains and DNS, running my own email service using some of my own email code.&lt;/p&gt;

&lt;p&gt;Until those days when the lines are down and the tubes are tied up and the power is out and the magic smoke goes poof. Those days, I want nothing more than a normal hosted email service like everyone else.&lt;/p&gt;

&lt;p&gt;But let&amp;#8217;s get real. No I don&amp;#8217;t! I like running my own stuff! Of course it&amp;#8217;s embarrassing to bounce email when my server is offline, so what&amp;#8217;s really important is to follow the best-practices for running a proper site, including secondary DNS and backup MX.&lt;/p&gt;

&lt;p&gt;The first thing to do when figuring out secondary DNS is to figure out how many domains you have. I only run email for 3 domains, but I have a raft of neat domains that I own. Most secondary DNS services charge on a per-domain basis, so getting secondary service for 25 domains will cost a bundle, and doesn&amp;#8217;t even begin to solve the problem of a backup MX.&lt;/p&gt;

&lt;p&gt;Looking around some more, I found that some hosting services provide unlimited DNS service along with a subscription for a hosted virtual machine. The best of those services is &lt;a href='http://slicehost.com/'&gt;Slicehost&lt;/a&gt;, starting at $20/month for a basic virtual machine instance with 256 MB of RAM and 10 GB of disk. I highly recommend this service and the basic configuration for your backup MX.&lt;/p&gt;

&lt;p&gt;Ok, so we&amp;#8217;ve got a virtual machine instance, now what? Gotta install something on it! I recommend whatever is the most recent Ubuntu LTS. You don&amp;#8217;t need or want any new hotness for your backup MX. You need and want stupidly simple and someone-else-is-supporting-this reliable. Ubuntu LTS. Do it.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Back in the code days</title>
   <link href="http://sodabrew.com/2009/04/back-in-the-code-days.html"/>
   <updated>2009-04-14T14:13:32-07:00</updated>
   <id>http://sodabrew.com/2009/04/back-in-the-code-days</id>
   <content type="html">&lt;p&gt;Why, when I was a kid, we had to write code while walking 20 miles to the computer building, in 12 feet of snow in the middle of winter. And it was uphill both ways! Course we couldn&amp;#8217;t wear gloves, because it was too hard to line up the hole punch on the punched card. They didn&amp;#8217;t have knapsacks in those days, so we just had to keep our card stack on a string tied to our belt. Now, a hole punch cost a nickel, and in those days nickels had pictures of bumblebees on &amp;#8216;em. &amp;#8220;Give me five bees for a quarter,&amp;#8221; you&amp;#8217;d say. Now where were we? Oh yeah, the important thing was I had a stack of punch cards on my belt, was the style at the time. They didn&amp;#8217;t have standard 5081 cards in stock, because of the war. The only thing you could get was graph papyrus, and you had to draw all the tables by hand.&lt;/p&gt;

&lt;p&gt;Best. Slashdot. &lt;a href='http://ask.slashdot.org/comments.pl?sid=1197237&amp;amp;amp;cid=27559751'&gt;Comment&lt;/a&gt;. Evar.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Yemenite and Rhodes Haroset</title>
   <link href="http://sodabrew.com/2009/04/yemenite-haroset.html"/>
   <updated>2009-04-09T23:56:29-07:00</updated>
   <id>http://sodabrew.com/2009/04/yemenite-haroset</id>
   <content type="html">&lt;span style='float: right; margin: 0 0 20px 20px; display: inline;'&gt;
&lt;iframe scrolling='no' marginheight='0' src='http://rcm.amazon.com/e/cm?t=thecorofaarst-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=as1&amp;amp;asins=0684835592&amp;amp;md=10FE9736YVPPT7A0FBG2&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr' marginwidth='0' frameborder='0' style='width:120px;height:240px;' /&gt;
&lt;/span&gt;
&lt;p&gt;From The World of Jewish Cooking, by Gil Marks:&lt;/p&gt;
&lt;big&gt;Yemenite&lt;/big&gt;
&lt;ul&gt;
&lt;li&gt;15 dried figs, chopped&lt;/li&gt;

&lt;li&gt;2 to 3 tablespoons sesame seeds, lightly toasted&lt;/li&gt;

&lt;li&gt;1 teaspoon ground cinnamon&lt;/li&gt;

&lt;li&gt;1 teaspoon ground ginger&lt;/li&gt;

&lt;li&gt;Dash of ground coriander or cardamom&lt;/li&gt;

&lt;li&gt;1 small chili or pinch of cayenne&lt;/li&gt;

&lt;li&gt;Dry red wine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finely chop the figs, dates, sesame seeds, cinnamon, ginger, coriander or cardamom, and chili or cayenne. Stir in enough wine to make a paste. Storein the refrigerator. Serve at room temperature.&lt;/p&gt;
&lt;big&gt;Rhodes&lt;/big&gt;
&lt;ul&gt;
&lt;li&gt;1/2 cup pitted dates, finely chopped&lt;/li&gt;

&lt;li&gt;1/2 cup raisins&lt;/li&gt;

&lt;li&gt;1 orange, peeled, seeded, and chopped&lt;/li&gt;

&lt;li&gt;1/4 cup honey&lt;/li&gt;

&lt;li&gt;1/2 cup almonds, finely chopped&lt;/li&gt;

&lt;li&gt;cinnamon&lt;/li&gt;

&lt;li&gt;about 1/4 cup sweet red wine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cook dates, raisins, orange, and honey, stirring, until thick (about 20 minutes). Remove from heat and add remaining ingredients.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Register.com teaches SSL customers how to phish</title>
   <link href="http://sodabrew.com/2009/03/registercom-teaches-ssl-customers-how-to-phish.html"/>
   <updated>2009-03-05T23:58:40-08:00</updated>
   <id>http://sodabrew.com/2009/03/registercom-teaches-ssl-customers-how-to-phish</id>
   <content type="html">&lt;p&gt;I just bought an SSL certificate for this domain from Register.com. The price was great ($38 for 3 years! Just Google for &amp;#8220;discount ssl certificate&amp;#8221; to get a Register.com AdWord banner discount), the process went really smoothly, the certificate installed easily into Apache, and is working well for me so far.&lt;/p&gt;

&lt;p&gt;&lt;img src='/files/register.com-like-a-phish-thumb.png' alt='Register Phishing' /&gt;&lt;/p&gt;

&lt;p&gt;In the middle of the process, while I was downloading the certs and reading their directions, I came across this doozy of a page. What Register.com is giving you are &lt;b&gt;static pictures of locks to make users
feel safe&lt;/b&gt;. In other words, &lt;b&gt;teaching people to trust the telltale
signs of phishing tactics!&lt;/b&gt; And I&amp;#8217;m downright shocked at the favicon of a lock. That&amp;#8217;s a straight-up bald-faced attempt at making the site look like it&amp;#8217;s being seen by the browser as secured. Not cool!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Multitouching more of New York</title>
   <link href="http://sodabrew.com/2009/01/multitouching-more-of-new-york.html"/>
   <updated>2009-01-22T10:45:15-08:00</updated>
   <id>http://sodabrew.com/2009/01/multitouching-more-of-new-york</id>
   <content type="html">&lt;p&gt;This new Google New York project at &lt;a href='http://nycgo.com'&gt;nycgo.com&lt;/a&gt;, using Google Maps and Earth with lots of local data is neat. But where it gets really incredible is the touchscreen interface that reminds me of &lt;a href='http://www.imdb.com/title/tt0181689/'&gt;Minority Report&lt;/a&gt;. Specifically, I&amp;#8217;m thinking about the large immersive gesture system that Tom Cruise uses to gather information about his situation.&lt;/p&gt;

&lt;p&gt;Which is, of course, already something of a reality! Jeff Han &lt;a href='http://www.ted.com/index.php/talks/jeff_han_demos_his_breakthrough_touchscreen.html'&gt;demonstrated a large multitouch screen&lt;/a&gt; with correspondingly incredible user interface at TED in 2006. Now Art Lebedev of Optimus Maximus keyboard fame is working on the &lt;a href='http://www.etre.com/blog/2008/01/optimus_tactus_artemy_lebedev/'&gt;Optimus Tactus&lt;/a&gt;, a concept keyboard where the keys are replaced with a touch screen, and the &amp;#8220;keyboard&amp;#8221; itself becomes reconfigurable to suit the application &amp;#8211; keys for typing, mixer controls for audio, video jogs and patches, and so on.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Next document</title>
   <link href="http://sodabrew.com/2009/01/next-document.html"/>
   <updated>2009-01-16T15:55:36-08:00</updated>
   <id>http://sodabrew.com/2009/01/next-document</id>
   <content type="html">&lt;p&gt;draft-ietf-sieve-include!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>mod_perlite on O'Reilly Broadcast</title>
   <link href="http://sodabrew.com/2009/01/modperlite-on-oreilly-broadcast.html"/>
   <updated>2009-01-16T15:46:47-08:00</updated>
   <id>http://sodabrew.com/2009/01/modperlite-on-oreilly-broadcast</id>
   <content type="html">&lt;p&gt;w00t &amp;#8211;&lt;/p&gt;
&lt;a href='http://broadcast.oreilly.com/2009/01/cgi-is-dead-mod-perlite-is-ali.html'&gt;http://broadcast.oreilly.com/2009/01/cgi-is-dead-mod-perlite-is-ali.html
&lt;/a&gt;
&lt;p&gt;Back in December, Byrne and I had a telephone interview with chromatic talking about mod_perlite, one of the &lt;a href='http://broadcast.oreilly.com/2008/12/five-features-perl-5-needs-now.html'&gt;five features Perl 5 needs now&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Firefox needs to chillax</title>
   <link href="http://sodabrew.com/2008/11/firefox-needs-to-chillax.html"/>
   <updated>2008-11-21T10:58:55-08:00</updated>
   <id>http://sodabrew.com/2008/11/firefox-needs-to-chillax</id>
   <content type="html">&lt;p&gt;Top causes for wakeups:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;8% ( 68.5) firefox-bin : futex_wait (hrtimer_wakeup)&lt;/li&gt;

&lt;li&gt;3% ( 27.0) firefox-bin : schedule_timeout (process_timeout)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let my CPU get to C3 once in a while, plz!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Sieve Reject</title>
   <link href="http://sodabrew.com/2008/11/sieve-reject-08.html"/>
   <updated>2008-11-17T11:13:03-08:00</updated>
   <id>http://sodabrew.com/2008/11/sieve-reject-08</id>
   <content type="html">&lt;p&gt;At long last, I posted the &lt;a href='http://tools.ietf.org/id/draft-ietf-sieve-refuse-reject'&gt;next draft&lt;/a&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Neat!</title>
   <link href="http://sodabrew.com/2008/10/multiblog.html"/>
   <updated>2008-10-23T11:36:12-07:00</updated>
   <id>http://sodabrew.com/2008/10/multiblog</id>
   <content type="html">&lt;p&gt;MTMultiBlog FTW! At some point I&amp;#8217;d like to make my scrappy sidebar blog itself look more like my own twitter-alike.&lt;br /&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Open Letter for Bicycles on Public Transit</title>
   <link href="http://sodabrew.com/2008/10/bicycles-on-public-transit.html"/>
   <updated>2008-10-14T13:34:41-07:00</updated>
   <id>http://sodabrew.com/2008/10/bicycles-on-public-transit</id>
   <content type="html">&lt;p&gt;Thoughts on living in San Francisco, and on getting around this place&amp;#8230;&lt;/p&gt;

&lt;p&gt;San Francisco is an extremely car-congested city. Even if I owned a car, I&amp;#8217;d be fighting every day for parking and space on the roads. Why would I do that to myself? So, I bike to work, or I take the bus and walk a few blocks from the bus stop. When I used to live on the Peninsula, I took Caltrain to work. Before that, I lived in Oakland and took BART to work.&lt;/p&gt;

&lt;p&gt;So let&amp;#8217;s focus on problem areas: First, the roads are in terrible condition, with potholes big enough to eat bicycle tires whole - sometimes even smack in the middle of a dedicated bicycle lane! Second, our bridges do not have consistent bicycle paths. Third, our public transit is outright hostile to bicycles.&lt;/p&gt;

&lt;p&gt;Let me dwell on that third point. Each and every public transit agency has different policies about when, how many, and what kind of bicycles are allowed on-board a bus, light-rail (SF Muni), electrified-rail (BART) or heavy-rail train (Caltrain).&lt;/p&gt;

&lt;p&gt;It should be national policy to encourage and subsidize the expansion of bicycle commuting capacity in all public transportation systems. The cost of adding one rack-seat combo to a bus or train is a heavy burden upon a municipal transit agency, but in terms of societal cost vs. cars &amp;#8211; that require roads, traffic signals, gas stations, parking lots, garages &amp;#8211; that dollar spent subsidizing the municipal transit agency&amp;#8217;s bike-on-board rack is suddenly a fraction of what we&amp;#8217;d otherwise spend to enable that same person to commute by car.&lt;/p&gt;

&lt;p&gt;Bicycles on board public transit. It just makes sense.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Hacking</title>
   <link href="http://sodabrew.com/2008/09/hacking.html"/>
   <updated>2008-09-26T11:40:04-07:00</updated>
   <id>http://sodabrew.com/2008/09/hacking</id>
   <content type="html">&lt;p&gt;Nothing this week :-(&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Work</title>
   <link href="http://sodabrew.com/2008/09/work.html"/>
   <updated>2008-09-26T11:27:59-07:00</updated>
   <id>http://sodabrew.com/2008/09/work</id>
   <content type="html">&lt;p&gt;Very busy.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Running nmbd on OpenBSD</title>
   <link href="http://sodabrew.com/2008/09/running-nmbd-on-openbsd.html"/>
   <updated>2008-09-12T12:45:52-07:00</updated>
   <id>http://sodabrew.com/2008/09/running-nmbd-on-openbsd</id>
   <content type="html">&lt;p&gt;Some days I need to share files across subnets at home, and always end up frustrated that some part of the infrastructure is there to give me a headache. Like, say, that Windows file shares still cannot readily browse across subnets! (Neither did Rendezvous/Bonjour on the Mac, originally, but it does now.) Consequently I set up just nmbd on my OpenBSD firewall, which routes between my various wireless and wired networks, so provide the NetBIOS name resolution across subnets needed to allow for cross-subnet Windows network browsing. Note, crucially, that I&amp;#8217;m not running smbd. No files are being shared here, no users are being authenticated, I am strictly using nmbd as a name server.&lt;span class='Apple-style-span' style='font-family: Verdana; font-size: 13px; line-height: normal'&gt;Take the &lt;em&gt;smb.conf&lt;/em&gt; from &lt;a href='http://www.linuxplanet.com/linuxplanet/tutorials/6451/'&gt;part 1&lt;/a&gt; and add these lines to the &lt;em&gt;[global]&lt;/em&gt; section:
&lt;pre&gt;   domain master = yes    preferred master = yes     local master = yes    wins support = yes    wins proxy = yes&lt;/pre&gt;
&lt;/span&gt;&lt;span class='Apple-style-span' style='font-family: &amp;apos;Courier New&amp;apos;; font-size: 11px; line-height: 13px; white-space: pre'&gt;   os level = 65&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt&lt;/p&gt;

&lt;p&gt;http://www.ietf.org/rfc/rfc2136.txt&lt;/p&gt;

&lt;p&gt;http://www.apple.com/support/downloads/bonjourforwindows.html&lt;/p&gt;

&lt;p&gt;http://www.chaoticsoftware.com/ProductPages/NetworkBeacon.html&lt;/p&gt;

&lt;p&gt;http://developer.apple.com/networking/bonjour/faq.html&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Coding for a Reentrant Flex</title>
   <link href="http://sodabrew.com/2008/09/coding-for-a-reentrant-flex.html"/>
   <updated>2008-09-12T12:45:52-07:00</updated>
   <id>http://sodabrew.com/2008/09/coding-for-a-reentrant-flex</id>
   <content type="html"></content>
 </entry>
 
 <entry>
   <title>Bottle Return</title>
   <link href="http://sodabrew.com/2008/07/bottle-return.html"/>
   <updated>2008-07-29T03:31:55-07:00</updated>
   <id>http://sodabrew.com/2008/07/bottle-return</id>
   <content type="html">&lt;p&gt;When I was in the Czech Republic in March 2007, I went to see a movie called &lt;a href='http://www.imdb.com/title/tt0809951/'&gt;Vratné lahve&lt;/a&gt;, which in Czech means &amp;#8220;Bottle Return&amp;#8221; &amp;#8211; although they titled the movie &amp;#8220;Empties&amp;#8221; in English. There&amp;#8217;s a unique feature of Czech supermarkets, a bottle return department, where you return glass bottles of juice, water, and especially beer, and they are returned to the bottling company to be washed a reused without going through an American-style crushing and remanufacturing process. The movie centers around a fellow who loses his job as a teacher of literature and finds work as the man in the bottle return booth at a local supermarket. In the opening sequence of the film, the man is reading a poem to his class, &lt;em&gt;Za
trochu lásky...&lt;/em&gt; by Jaroslav Vrchlický.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Za trochu lásky šel bych svĕta kraj,&lt;br /&gt;šel s hlavou odkrytou a šel bych bosý,&lt;br /&gt;šel v ledu - ale v duši vĕčný máj,&lt;br /&gt;šel vichřicí - však slyšel zpívat kosy,&lt;br /&gt;šel pouští - a mĕl v srdci perly rosy.&lt;br /&gt;Za trochu lásky šel bych svĕta kraj,&lt;br /&gt;jak ten, kdo zpívá u dveří a prosí.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I&amp;#8217;ve been looking for an English translation of this poem since I saw the movie, and thanks to the help of the &lt;a href='http://community.livejournal.com/linguaphiles/3983803.html'&gt;linguaphiles&lt;/a&gt; community of LJ, and my Czech friend Dana, I now have one!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For a bit of love, I would go to the end of the world,&lt;br /&gt;I would go bareheaded and I would go barefoot,&lt;br /&gt;I would go through the ice - but with eternal May in my soul,&lt;br /&gt;I would go through the storm - but would hear blackbirds singing,&lt;br /&gt;I would go into the wilderness - and would have of pearls or dew in the heart&lt;br /&gt;For a bit of love, I would go to the end of the world,&lt;br /&gt;as one who sings begging at the door.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Na zdraví!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Plugin Strategies in Open Source, Part 2</title>
   <link href="http://sodabrew.com/2008/06/plugin-strategies-in-open-source-part-2.html"/>
   <updated>2008-06-04T16:28:50-07:00</updated>
   <id>http://sodabrew.com/2008/06/plugin-strategies-in-open-source-part-2</id>
   <content type="html">&lt;p&gt;In any project, feature-creep can be a problem. In an open source project, this can be particularly acute when there are few developers. Worse yet, someone becomes super-active just until their major new feature lands and then they disappear! And then there&amp;#8217;s the problem of noisy people who won&amp;#8217;t stop whining about getting some peculiar feature, or some major new functionality, either or both of which are just not interesting to anybody else.&lt;/p&gt;

&lt;p&gt;An effective plugin strategy actually embraces these people and their pet features, providing a mechanism for decoupling code from the code project, yet allowing key features to be injected into the running system from a separate and contained plugins area. Note the words &lt;em&gt;separate&lt;/em&gt; and &lt;em&gt;contained&lt;/em&gt;. Both are very important.&lt;/p&gt;

&lt;p&gt;The plugins area must be separate because you want to protect the clear messaging of your application&amp;#8217;s features. You also want to keep plugins separate because there can be a tendency to make &lt;em&gt;everything&lt;/em&gt; a plugin. Don&amp;#8217;t. Just don&amp;#8217;t. Really. Core features are core. They are not plugins. Nobody wants a framework that does nothing until you&amp;#8217;ve loaded a jillion plugins into it in order to create a working application. So separate is a double-edged sword: keep the non-essential stuff away from the core applications, and keep all the essential stuff inside the core application. Sometimes it means swallowing a plugin into the app. If it makes sense, do it.&lt;/p&gt;

&lt;p&gt;The plugins must be contained. And, ideally, also self-contained. That is, you have a directory like &amp;#8216;/your/app/plugins/some_crappy_plugin&amp;#8217; for each plugin. The plugins are contained within &amp;#8216;/your/app/plugins&amp;#8217; and each one is further self-contained another directory level below that. Then, provide an API that allows the plugins to act at a distance. Yes, act at a distance. Normally this is something that you don&amp;#8217;t want because it is hard to figure out. But in the case of plugins, it is just right. The plugin does not need to patch into the main app code, but rather register itself with the main app and declare which of its functions should be called from which parts of the main app. It&amp;#8217;s runtime integration, runtime configurability, and runtime enable/disable. Sure it can be slower. But it&amp;#8217;s so much better than having people distributing patches that implement their functionality by hacking up your beautiful code.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Handling exit within an eval</title>
   <link href="http://sodabrew.com/2008/03/handling-exit-within-an-eval.html"/>
   <updated>2008-03-15T17:16:24-07:00</updated>
   <id>http://sodabrew.com/2008/03/handling-exit-within-an-eval</id>
   <content type="html">&lt;p&gt;So I&amp;#8217;ve run into a problem with &lt;a href='http://modperlite.org/'&gt;mod_perlite&lt;/a&gt;, and it&amp;#8217;s that I cannot just override Perl&amp;#8217;s exit function with a straight perl_destruct call, a longjmp back to the Apache handler, or anything else at all.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://theory.uwinnipeg.ca/modperl/docs/2.0/api/ModPerl/Util.html#C_exit_'&gt;Here&amp;#8217;s how it&amp;#8217;s handled in mod_perl&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.perlmonks.org/?node_id=636127'&gt;And then there&amp;#8217;s this possible workaround using goto&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.mail-archive.com/perl-qa-help@perl.org/msg01189.html'&gt;Shockingly, this works, too&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here&amp;#8217;s my favorite&amp;#8230;&lt;/p&gt;

&lt;h3 id='barpl'&gt;bar.pl&lt;/h3&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='perl'&gt;&lt;span class='nb'&gt;exit&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id='foopm'&gt;Foo.pm&lt;/h3&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='perl'&gt;&lt;span class='nb'&gt;package&lt;/span&gt; &lt;span class='n'&gt;Foo&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

&lt;span class='k'&gt;sub &lt;/span&gt;&lt;span class='nf'&gt;new&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
  &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nb'&gt;bless&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='p'&gt;};&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;

&lt;span class='k'&gt;sub &lt;/span&gt;&lt;span class='nf'&gt;DESTROY&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
  &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;Foo is destroyed\n&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;

&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id='foopl'&gt;foo.pl&lt;/h3&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='perl'&gt;&lt;span class='k'&gt;use&lt;/span&gt; &lt;span class='n'&gt;Foo&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

&lt;span class='k'&gt;my&lt;/span&gt; &lt;span class='nv'&gt;$foo&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;Foo&lt;/span&gt;&lt;span class='o'&gt;-&amp;amp;&lt;/span&gt;&lt;span class='ow'&gt;gt&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;&lt;span class='k'&gt;new&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

&lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;I have a foo!\n&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

&lt;span class='k'&gt;BEGIN&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='nn'&gt;CORE::GLOBAL::&lt;/span&gt;&lt;span class='n'&gt;exit&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;sub &lt;/span&gt;&lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='nb'&gt;goto&lt;/span&gt; &lt;span class='n'&gt;EXIT&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='p'&gt;};&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;

&lt;span class='nb'&gt;eval&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
  &lt;span class='n'&gt;bar&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;bar.pl&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='p'&gt;};&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='vg'&gt;$@&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
  &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;$@ happens\n&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;

&lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;And I&amp;#39;m still here\n&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

&lt;span class='k'&gt;sub &lt;/span&gt;&lt;span class='nf'&gt;bar&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
  &lt;span class='nb'&gt;eval&lt;/span&gt; &lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='nv'&gt;$_&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;];&lt;/span&gt;
  &lt;span class='n'&gt;EXIT:&lt;/span&gt;
  &lt;span class='k'&gt;print&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;Exiting!\n&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='nb'&gt;goto&lt;/span&gt; &lt;span class='n'&gt;REALLY_EXIT&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;

&lt;span class='n'&gt;REALLY_EXIT:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Yep, that actually works!&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='text'&gt;I have a foo!  
Exiting!  
Foo is destroyed.  
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>Plugin Strategies in Open Source, Part 1</title>
   <link href="http://sodabrew.com/2008/03/plugin-strategies-in-open-source-part-1.html"/>
   <updated>2008-03-15T17:11:01-07:00</updated>
   <id>http://sodabrew.com/2008/03/plugin-strategies-in-open-source-part-1</id>
   <content type="html">&lt;p&gt;Once upon a time, I worked &lt;a href='#note'&gt;*&lt;/a&gt; on an open source groupware application called &lt;a href='http://informationgateway.org'&gt;TWIG&lt;/a&gt;, The Web Information Gateway. I started posting fixes, wrote some code to scratch my itches, and pretty soon I got CVS commit access. I wrote a new module for scheduling meetings, and the guys on the development team loved it, so I committed it, and life was good. Pretty soon, I was using this module to schedule meetings in rooms that got to be conflicting and overlapped. I also had heard that back at my high school, there was a &lt;a href='http://www.huffingtonpost.com/esther-wojcicki'&gt;particular teacher&lt;/a&gt; who thought she was the Goddess-of-all-Writing and therefore could simply walk up to the whiteboard in the main computer lab and erase other teachers from the schedule in order to accommodate her clearly superior, holy and blessed classes.&lt;/p&gt;

&lt;p&gt;So I wrote a reservations module that integrated into this groupware platform, and it worked, and I got positive feedback from the folks back at my old high school, folks on the twig users mailing list, and from the development team, so I committed it.&lt;/p&gt;

&lt;p&gt;The maintainer flipped out. &amp;#8220;NO MORE MODULES!&amp;#8221; he said, &amp;#8220;REMOVE THIS OR I WILL REVOKE YOUR CVS ACCESS!&amp;#8221;&lt;/p&gt;

&lt;p&gt;Other developers and users came to my defense and said, &amp;#8220;But this module is useful, it&amp;#8217;s excellent, it complements the scheduling and meetings features. It&amp;#8217;s killer!&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;DIE MODULES, DIE!&amp;#8221; the maintainer said.&lt;/p&gt;

&lt;p&gt;The project died.&lt;/p&gt;
&lt;a name='note' title='note' /&gt;&lt;em&gt;Actually, I still use TWIG personally, and I still hack on it when I have
time, and every now and then there are new users who post to the mailing list,
and I generally respond to help them out within a few hours. But the project is
effectively dead.&lt;/em&gt;</content>
 </entry>
 
 <entry>
   <title>libSieve Hacking</title>
   <link href="http://sodabrew.com/2008/02/libsieve-hacking-2.html"/>
   <updated>2008-02-22T13:57:39-08:00</updated>
   <id>http://sodabrew.com/2008/02/libsieve-hacking-2</id>
   <content type="html">&lt;p&gt;This month a number of Sieve extensions became published RFCs, along with an update to the Sieve base spec itself:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;[&lt;a href='http://tools.ietf.org/html/rfc5228'&gt;RFC 5228&lt;/a&gt;]&lt;/strong&gt; Sieve: An Email Filtering Language.&lt;/li&gt;

	&lt;li&gt;&lt;strong&gt;[&lt;a href='http://tools.ietf.org/html/rfc5229'&gt;RFC 5229&lt;/a&gt;]&lt;/strong&gt; Sieve Email Filtering: Variables Extension.&lt;/li&gt;

	&lt;li&gt;&lt;strong&gt;[&lt;a href='http://tools.ietf.org/html/rfc5230'&gt;RFC 5230&lt;/a&gt;]&lt;/strong&gt; Sieve Email Filtering: Vacation Extension.&lt;/li&gt;

	&lt;li&gt;&lt;strong&gt;[&lt;a href='http://tools.ietf.org/html/rfc5231'&gt;RFC 5231&lt;/a&gt;]&lt;/strong&gt; Sieve Email Filtering: Relational Extension.&lt;/li&gt;

	&lt;li&gt;&lt;strong&gt;[&lt;a href='http://tools.ietf.org/html/rfc5232'&gt;RFC 5232&lt;/a&gt;]&lt;/strong&gt; Sieve Email Filtering: Imap4flags Extension.&lt;/li&gt;

	&lt;li&gt;&lt;strong&gt;[&lt;a href='http://tools.ietf.org/html/rfc5233'&gt;RFC 5233&lt;/a&gt;]&lt;/strong&gt; Sieve Email Filtering: Subaddress Extension.&lt;/li&gt;

	&lt;li&gt;&lt;strong&gt;[&lt;a href='http://tools.ietf.org/html/rfc5235'&gt;RFC 5235&lt;/a&gt;]&lt;/strong&gt; Sieve Email Filtering: Spamtest and Virustest Extensions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Time for teh libSieve hacken!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>TWIG Hacking</title>
   <link href="http://sodabrew.com/2008/01/twig-hacking.html"/>
   <updated>2008-01-05T20:06:50-08:00</updated>
   <id>http://sodabrew.com/2008/01/twig-hacking</id>
   <content type="html">&lt;p&gt;For the first time in a long time, I spent a weekend hacking on TWIG! :-D Tons of things work now in TWIG 4, lots of code flow improvements, CSS and Javascript improvements for Web 2.0 (more on that in a minute), database cleanliness and efficiency improvements, Reservations feature checked back in for the first time in a very long time, HelpDesk works, and the guts of a totally new Mail backend based on the IlohaMail IMAP library.&lt;/p&gt;

&lt;p&gt;Back when the world was about separation content from presentation, TWIG 2 was all about mixing them together in the early tradition weekend-hack PHP apps, despite TWIG being a very large and otherwise well organized framework. Now that we&amp;#8217;re in Web 2.0 days, the point at which content mixes with presentation to form an output web page has moved from being entirely on the server to being partially on the server and partially on the client. This is the Ajax way.&lt;/p&gt;

&lt;p&gt;When I first started working on TWIG 4, I thought I would need a structural mechanism to allow data to be mixed into the source HTML or to be retrieved via Ajax. But it&amp;#8217;s been on the table for so long now that Web 2.0 caught up with us and every reason for not relying on Javascript &amp;#8211; old browsers, mobile devices, screen readers &amp;#8211; now support at least basic Ajax functionality. With this now nearly universal support for running Javascript and requesting data via Ajax, I&amp;#8217;ve now worked it into TWIG 4 as a requirement and a basic part of the architecture.&lt;/p&gt;

&lt;p&gt;Next time, writing your own mashups using the TWIG query API and native Wiki feature!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Another MySQL headache</title>
   <link href="http://sodabrew.com/2007/11/another-mysql-headache.html"/>
   <updated>2007-11-27T16:55:11-08:00</updated>
   <id>http://sodabrew.com/2007/11/another-mysql-headache</id>
   <content type="html">&lt;p&gt;In &lt;a href='http://www.dbmail.org/mantis/view.php?id=655'&gt;http://www.dbmail.org/mantis/view.php?id=655&lt;/a&gt;, Mr. Maenaka writes:&lt;blockquote&gt;MySQL's automatic reconnection is unsafe because of the following reason.First, SET NAMES query is a required arbitration between server and client if both's character encoding is different. This should be done at the time of connection open. (Of course you can issue SET NAMES between every query with the huge overhead though.) By the way, MySQL's automatic reconnection is made transparent to the client. So the client never know that SET NAMES should be issued again.  Therefore, if the connection is restored this way, the character encoding mismatch may occur (and some or all data is garbled or lost). &lt;/blockquote&gt;No, really, seriously, you auto-reconnect without setting my connection-specific settings in the new connection? What kind of crack are you smoking at MySQL AB!? &lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Two request monty for persistent services on non-persistent hosts</title>
   <link href="http://sodabrew.com/2007/11/two-request-monty-for-persistent-services-on-non-persistent-hosts.html"/>
   <updated>2007-11-07T12:15:46-08:00</updated>
   <id>http://sodabrew.com/2007/11/two-request-monty-for-persistent-services-on-non-persistent-hosts</id>
   <content type="html">&lt;p&gt;A problem I&amp;#8217;ve been thinking about for a long time was how to build a backend service for a stateless web frontend. All of the solutions I have seen involve building a daemon that lives on the server and holds the persistent data. Or, in the case of PHP, weird ass service side session cookie things built right into the language.&lt;/p&gt;

&lt;p&gt;The solution I want is a hack that is as full featured as building a daemon and does not require modifying the operating environment. And today it hit me: the two request monty.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s the setup: you have a script that&amp;#8217;s running in the web server, it has an execution time limit, you&amp;#8217;re allowed to create and listen on sockets. Yes, I&amp;#8217;m thinking of PHP safe mode here. To create the service, your web app makes a request back to the host web server, spinning up the service script. That script then creates a socket listening to some local port, tries to increase its max execution time, sets a timer for just under whatever that time limit is, writes this information to some common location (typically the database behind your web app) then begins listening on the socket for requests for whatever kind of persistent data you need. When the timer fires, the script makes a request back to the host web server, spinning up a new service script. The new service spins up on some other port, connects to the first service and grabs all of its data, then writes its information to the database and begins serving persistent data to your application.&lt;/p&gt;

&lt;p&gt;Total hack beyond hack, but satisfies the requirements: does not require a new daemon, does not require new modules on the server, runs in safe mode, runs with time limits.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Perl in Apache with mod_perlite</title>
   <link href="http://sodabrew.com/2007/11/perl-in-apache-with-mod-perlite.html"/>
   <updated>2007-11-06T14:10:12-08:00</updated>
   <id>http://sodabrew.com/2007/11/perl-in-apache-with-mod-perlite</id>
   <content type="html">&lt;p&gt;Lately at &lt;a href='http://sixapart.com/'&gt;work&lt;/a&gt; a few folks have been batting around possible solutions to the perceived problem of how hard it is to run Perl code from Apache. Of course there are very good solutions, mod_cgi, mod_fastcgi, and best of all mod_perl. But there are very good reasons why web hosts shy away from CGI, and why they're deathly afraid of FastCGI and mod_perl. In a nutshell, it all comes down to persistence. PHP is incredibly popular because there &lt;em&gt;is no persistence!&lt;/em&gt;&lt;/p&gt;&lt;p&gt; &lt;a href='http://majordojo.com/2007/11/how-to-fix-cgi.php'&gt;Byrne Reese&lt;/a&gt; had the idea of taking mod_php and ripping out the calls to the PHP interpreter, replacing them with a Perl interpreter. &quot;I don't think it's quite that simple...&quot; I said. But Byrne was 80% correct. The other 20% is grabbing the Apache - PerlIO layer from mod_perl and using that to shovel data from STDIN and STDOUT in and out of the Perl script. The resulting code is pretty simple!

&lt;/p&gt;&lt;p&gt; Fundamentally, mod_perlite tries not to solve all your problems. It is specifically targeted at being 80% good at the 80% problem. With luck, we'll be able to get it onto 64% of web servers like PHP and pals.&lt;/p&gt;&lt;p&gt;
 To Do:&lt;ul id='null'&gt;	&lt;li&gt;Thrash at the Apache - PerlIO interface some more.&lt;/li&gt;	&lt;li&gt;Develop a script caching model (ala Zend Accelerator or APC).&lt;/li&gt;	&lt;li&gt;Add a script run-timer to kill long-running scripts (ala PHP's max_execution_time limit).&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>SSL Key Management App</title>
   <link href="http://sodabrew.com/2007/11/ssl-key-management-app.html"/>
   <updated>2007-11-02T14:17:14-07:00</updated>
   <id>http://sodabrew.com/2007/11/ssl-key-management-app</id>
   <content type="html">&lt;p&gt;The crux of my SSL management headache is that I have a lot of domains, but only four public IP addresses. I bet that most home-operated sites are like that. I also have a number of different applications running &amp;#8211; HTTPS, SMTPS, and IMAPS in particular. For each HTTPS domain, I need to have an SSL key that is bound to that domain. But since most of the domains are virtual hosts on a single IP, I don&amp;#8217;t know the domain until after the SSL negotiation. TLS is supposed to solve some of this, I think, but there&amp;#8217;s enough SSL out there that I need to deal with it. A tool that can tell me that I have { X } number of HTTPS domains but only { X, n &amp;#62; 0 : X-n } IPs, and allow me to pick which ones get keys, then generate the keys for me, would be grand! Furthermore, I often create convenience sub-domains for particular applications to facilitate portable DNS inside and outside of my home firewall. smtp.serendipity.cx, for example, resolves differently inside and outside my firewall. Outside the firewall, it resolves the same as serendipity.cx. Inside the firewall, it does not, since I don&amp;#8217;t NAT my servers from the inside. So I need separate SSL keys for these two domains. But they&amp;#8217;re also different apps, so there&amp;#8217;s no IP conflict. Am I making sense? Yeah, so I need an open source SSL key management app. Or I need to write one ;-)&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Rolling in Internets</title>
   <link href="http://sodabrew.com/2007/10/rolling-in-internets.html"/>
   <updated>2007-10-26T18:18:41-07:00</updated>
   <id>http://sodabrew.com/2007/10/rolling-in-internets</id>
   <content type="html">&lt;p&gt;Well, it finally happened. I caved. I bought Internets &lt;span class='Apple-style-span' style='font-weight: bold'&gt;&lt;span class='Apple-style-span' style='font-style: italic'&gt;everywhere&lt;/span&gt;&lt;/span&gt; with a Sprint plan and the Novatel USB727 doohickey. Bonus points to Novatel for packing a GPS and a EVDO rev A modem into such a small package and providing working Linux instructions involving only standard kernel serial drivers!&lt;/p&gt;
&lt;img src='http://hydricacid.com/wp/wp-content/uploads/2007/10/nvu727dora_lpi.gif' alt='Novatel USB727' /&gt;
&lt;p&gt;My critique of the instructions is also a strength: they&amp;#8217;re looong, repeated several times for various distributions, but also totally idiot-proofed. At the very end, the steps to quickly get the modem dialing from the command line are presented.&lt;/p&gt;

&lt;p&gt;Instruction for using the Sprint U727 in Linux, (and very likely the Verizon USB727, too). Here&amp;#8217;s what works for me:&lt;ul&gt;	&lt;li&gt;First, add this line to /etc/modprobe.conf:&lt;tt&gt;options usbserial vendor=0x1410 product=0x4100&lt;/tt&gt;&lt;/li&gt;	&lt;li&gt;Create &lt;tt&gt;/etc/wvdial.conf&lt;/tt&gt; with these contents:
&lt;code&gt;
[Dialer Defaults]
Modem = /dev/ttyUSB0
Baud = 460800
Init1 = ATZ
Init2 = ATQ0 V1 E1 S0=0 &amp;amp;C1 &amp;amp;D2 +FCLASS=0
ISDN = 0
Modem Type = USB Modem
Phone = #777
Username = ''
Password = ''
Carrier Check = no
Stupid Mode = yes&lt;/code&gt;&lt;/li&gt;	&lt;li&gt;Then, each time you want to use the modem:&lt;/li&gt;&lt;/ul&gt;&lt;ol id='null'&gt;	&lt;li&gt; Insert the USB modem.&lt;/li&gt;	&lt;li&gt;Wait for the device to be recognized as a cdrom.&lt;/li&gt;	&lt;li&gt;&lt;tt&gt;eject /dev/cdrom&lt;/tt&gt;(since I don't have any other cdrom - you might need to eject /dev/cdrom1 or something)&lt;/li&gt;	&lt;li&gt;Wait a beat.&lt;/li&gt;	&lt;li&gt;&lt;tt&gt;wvdial&lt;/tt&gt;&lt;/li&gt;	&lt;li&gt;&lt;tt&gt;route add default ppp0&lt;/tt&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Things that make MySQL dumb</title>
   <link href="http://sodabrew.com/2007/10/things-that-make-mysql-dumb.html"/>
   <updated>2007-10-19T17:56:18-07:00</updated>
   <id>http://sodabrew.com/2007/10/things-that-make-mysql-dumb</id>
   <content type="html">&lt;p&gt;&lt;a href='http://forums.mysql.com/read.php?92,133026,133102'&gt;http://forums.mysql.com/read.php?92,133026,133102&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hi. Since the updates on a memory table should be very fast, the locks are taken for a very short time only. I won&amp;#8217;t expect that they become a bottleneck. But I must admit that I don&amp;#8217;t have any experiences with applications like this. If they do indeed become a bottleneck, you could try to use a transactional engine that uses row level locks, like InnoDB. But I guess that the overhead will outweigh the improvements in locking.&lt;/p&gt;

&lt;p&gt;Regards Ingo&lt;/p&gt;

&lt;p&gt;Ingo Strüwing, Senior Software Developer - Storage Engines MySQL AB, www.mysql.com&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ouch, man. That&amp;#8217;s my cerebellum you&amp;#8217;re destroying.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Coloring in the planet</title>
   <link href="http://sodabrew.com/2007/10/coloring-in-the-planet.html"/>
   <updated>2007-10-19T17:55:27-07:00</updated>
   <id>http://sodabrew.com/2007/10/coloring-in-the-planet</id>
   <content type="html">&lt;a href='http://hydricacid.com/wp/wp-content/uploads/2007/10/bwerth.jpg' title='Earth swatches' style='text-decoration: none'&gt;&lt;img src='http://hydricacid.com/wp/wp-content/uploads/2007/10/bwerth.jpg' alt='Earth swatches' style='text-decoration: underline' /&gt;&lt;/a&gt;</content>
 </entry>
 
 <entry>
   <title>First of October ToDo list</title>
   <link href="http://sodabrew.com/2007/10/first-of-october-todo-list.html"/>
   <updated>2007-10-01T11:57:23-07:00</updated>
   <id>http://sodabrew.com/2007/10/first-of-october-todo-list</id>
   <content type="html">&lt;p&gt;Here we go&amp;#8230;&lt;ul&gt;	&lt;li&gt;&lt;em&gt;Done! &lt;/em&gt;Edit draft-ietf-ipv6-ra-flags-option-02 and draft-weiler-dnssec-dlv-04&lt;/li&gt;	&lt;li&gt;&lt;em&gt;Done! &lt;/em&gt;Submit &lt;a href='http://tools.ietf.org/wg/sieve/draft-ietf-sieve-refuse-reject/'&gt;draft-ietf-sieve-refuse-reject-05&lt;/a&gt;&lt;/li&gt;	&lt;li&gt;&lt;span class='Apple-style-span' style='font-style: italic'&gt;Done!&lt;/span&gt; Release libSieve 2.2.6&lt;ul&gt;	&lt;li&gt;Update docs&lt;/li&gt;	&lt;li&gt;New callbacks for address and header parser errors&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;Saw &lt;a href='http://www.975howard.com/'&gt;Raw &amp;amp; Uncut Festival&lt;/a&gt; and &lt;a href='http://www.musichallsf.com/artist_pages/balkan_beat_box_092907.htm'&gt;Balkan Beat Box&lt;/a&gt; on Saturday evening. Hurrah for fun!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>libSieve Todo List</title>
   <link href="http://sodabrew.com/2007/09/libsieve-todo-list.html"/>
   <updated>2007-09-06T18:22:37-07:00</updated>
   <id>http://sodabrew.com/2007/09/libsieve-todo-list</id>
   <content type="html">&lt;p&gt;A few things to do before I get to libSieve 2.2.6&amp;#8230;&lt;ul id='null'&gt;	&lt;li&gt;More checkins.&lt;/li&gt;	&lt;li&gt;Bracketed comments.&lt;/li&gt;	&lt;li&gt;Stress tests for header and address parsers.&lt;/li&gt;	&lt;li&gt;Resolve extant memory leaks (switch to a memory pool system? methinks yes).&lt;/li&gt;	&lt;li&gt;Benchmark parsing a monster script. Compare with previous versions.&lt;/li&gt;	&lt;li&gt;Stress test the stack with deeply nested if blocks.&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Whenever it takes me a while to close a bug…</title>
   <link href="http://sodabrew.com/2007/08/whenever-it-takes-me-a-while-to-close-a-bug.html"/>
   <updated>2007-08-06T12:06:39-07:00</updated>
   <id>http://sodabrew.com/2007/08/whenever-it-takes-me-a-while-to-close-a-bug</id>
   <content type="html">&lt;p&gt;Opened: 2006-03-01 00:32 Gist of fix required: accept &amp;#8220;{&amp;#8221; bytecount &amp;#8220;+}&amp;#8221; in addition to &amp;#8220;{&amp;#8221; bytecount &amp;#8221;}&amp;#8221; for RFC compliance. Closed: 2007-08-06 19:29&lt;/p&gt;

&lt;p&gt;Thanks nonetheless to the KDE folks for closing this bug; fewer complaints from my DBMail users! :-)&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Romanesca Cauliflower</title>
   <link href="http://sodabrew.com/2007/08/romanesca-cauliflower.html"/>
   <updated>2007-08-05T18:25:52-07:00</updated>
   <id>http://sodabrew.com/2007/08/romanesca-cauliflower</id>
   <content type="html">&lt;p&gt;This week&amp;#8217;s &lt;a href='http://twosmallfarms.com' title='Two Small Farms'&gt;Two Small Farms&lt;/a&gt; CSA basket came with this weird thing:&lt;img title='Romanesca cauliflower' src='http://hydricacid.com/wp/wp-content/uploads/2007/08/cauliflower_romanesco.jpg' height='300' alt='Romanesca cauliflower' style='width: 400px; height: 300px' width='400' /&gt;  Well, what to do? Cut it up and saute it in olive oil with some garlic! Yum :-)&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>libSieve hacking</title>
   <link href="http://sodabrew.com/2007/07/libsieve-hacking.html"/>
   <updated>2007-07-28T20:00:45-07:00</updated>
   <id>http://sodabrew.com/2007/07/libsieve-hacking</id>
   <content type="html">&lt;p&gt;Today I spent some time hacking on libSieve for the first time in way too long. I was telling a friend about the inefficiency of putting all of your keywords into a lexer because it has to go through tons of state shifts to get to the terminals. A better way to do it is to match a generic identifier with a regular expression, then look up the matches in a hash table of keywords. Well, enough was enough, time for me to do that! The old CMU sieve-lex.l, with 56 keywords each as its own lexer state, yielded this flex -v output:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='text'&gt;/bin/sh ../ylwrap sieve-lex.l lex.yy.c sieve-lex.c -- flex -v -s -olex.yy.c
flex version 2.5.33 usage statistics:
scanner options: -svB8 -Cem -olex.yy.c -Plibsieve_sieve
584/2000 NFA states
340/1000 DFA states (737 words)
72 rules
Compressed tables always back-up
Beginning-of-line patterns used
3/40 start conditions
179 epsilon states, 98 double epsilon states
8/100 character classes needed 22/500 words of storage, 0 reused
1235 state/nextstate pairs created
414/821 unique/duplicate transitions
347/1000 base-def entries created
448/2000 (peak 399) nxt-chk entries created
28/2500 (peak 266) template nxt-chk entries created
0 empty table entries
8 protos created
7 templates created, 23 uses
38/256 equivalence classes created
4/256 meta-equivalence classes created
0 (15 saved) hash collisions, 81 DFAs equal
0 sets of reallocations needed
1884 total table entries needed
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;After moving the keywords out of sieve-lex.l and into sieve-keywords.gperf, replacing them all with a generic state,&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='c'&gt;&lt;span class='n'&gt;ident&lt;/span&gt;&lt;span class='err'&gt;          &lt;/span&gt; &lt;span class='o'&gt;:?&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='n'&gt;zA&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='n'&gt;Z_&lt;/span&gt;&lt;span class='p'&gt;][&lt;/span&gt;&lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='n'&gt;zA&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='n'&gt;Z_0&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='mi'&gt;9&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;
&lt;span class='o'&gt;&amp;amp;&lt;/span&gt;&lt;span class='n'&gt;lt&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;&lt;span class='n'&gt;INITIAL&lt;/span&gt;&lt;span class='o'&gt;&amp;amp;&lt;/span&gt;&lt;span class='n'&gt;gt&lt;/span&gt;&lt;span class='p'&gt;;{&lt;/span&gt;&lt;span class='n'&gt;ident&lt;/span&gt;&lt;span class='p'&gt;}&lt;/span&gt;&lt;span class='err'&gt;       &lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='kt'&gt;int&lt;/span&gt; &lt;span class='n'&gt;k&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;libsieve_keyword&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;yytext&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;yyleng&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt; &lt;span class='p'&gt;...&lt;/span&gt; &lt;span class='n'&gt;error&lt;/span&gt; &lt;span class='n'&gt;handling&lt;/span&gt; &lt;span class='p'&gt;...&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;the flex -v output reads like this:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='text'&gt;flex version 2.5.33 usage statistics:
scanner options: -svB8 -Cem -olex.yy.c -Plibsieve_sieve
146/2000 NFA states
72/1000 DFA states (304 words)
19 rules
Compressed tables always back-up
Beginning-of-line patterns used
3/40 start conditions
79 epsilon states, 50 double epsilon states
11/100 character classes needed 165/500 words of storage, 1 reused
830 state/nextstate pairs created
144/686 unique/duplicate transitions
83/1000 base-def entries created
204/2000 (peak 392) nxt-chk entries created
88/2500 (peak 308) template nxt-chk entries created
0 empty table entries
13 protos created
11 templates created, 35 uses
28/256 equivalence classes created
8/256 meta-equivalence classes created
3 (3 saved) hash collisions, 79 DFAs equal
0 sets of reallocations needed
858 total table entries needed
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Ok, that&amp;#8217;s better. But what about that one ident with the :? up front? What if it were this:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='c'&gt;&lt;span class='n'&gt;ident&lt;/span&gt;&lt;span class='err'&gt;          &lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='n'&gt;zA&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='n'&gt;Z_&lt;/span&gt;&lt;span class='p'&gt;][&lt;/span&gt;&lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='n'&gt;zA&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='n'&gt;Z_0&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='mi'&gt;9&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;
&lt;span class='o'&gt;&amp;amp;&lt;/span&gt;&lt;span class='n'&gt;lt&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;&lt;span class='n'&gt;INITIAL&lt;/span&gt;&lt;span class='o'&gt;&amp;amp;&lt;/span&gt;&lt;span class='n'&gt;gt&lt;/span&gt;&lt;span class='p'&gt;;{&lt;/span&gt;&lt;span class='n'&gt;ident&lt;/span&gt;&lt;span class='p'&gt;}&lt;/span&gt;&lt;span class='err'&gt;       &lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='kt'&gt;int&lt;/span&gt; &lt;span class='n'&gt;k&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;libsieve_keyword&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;yytext&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;yyleng&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt; &lt;span class='p'&gt;...&lt;/span&gt; &lt;span class='n'&gt;error&lt;/span&gt; &lt;span class='n'&gt;handling&lt;/span&gt; &lt;span class='p'&gt;...&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;

&lt;span class='o'&gt;&amp;amp;&lt;/span&gt;&lt;span class='n'&gt;lt&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;&lt;span class='n'&gt;INITIAL&lt;/span&gt;&lt;span class='o'&gt;&amp;amp;&lt;/span&gt;&lt;span class='n'&gt;gt&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt;&lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='n'&gt;ident&lt;/span&gt;&lt;span class='p'&gt;}&lt;/span&gt;&lt;span class='err'&gt;       &lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='kt'&gt;int&lt;/span&gt; &lt;span class='n'&gt;k&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;libsieve_keyword&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;yytext&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;yyleng&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt; &lt;span class='p'&gt;...&lt;/span&gt; &lt;span class='n'&gt;error&lt;/span&gt; &lt;span class='n'&gt;handling&lt;/span&gt; &lt;span class='p'&gt;...&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;And flex -v says:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='text'&gt;flex version 2.5.33 usage statistics:
scanner options: -svB8 -Cem -olex.yy.c -Plibsieve_sieve
150/2000 NFA states
73/1000 DFA states (306 words)
20 rules
Compressed tables always back-up
Beginning-of-line patterns used
3/40 start conditions
81 epsilon states, 52 double epsilon states
11/100 character classes needed 165/500 words of storage, 3 reused
844 state/nextstate pairs created
145/699 unique/duplicate transitions
85/1000 base-def entries created
207/2000 (peak 420) nxt-chk entries created
96/2500 (peak 336) template nxt-chk entries created
0 empty table entries
14 protos created
12 templates created, 36 uses
28/256 equivalence classes created
8/256 meta-equivalence classes created
0 (4 saved) hash collisions, 79 DFAs equal
0 sets of reallocations needed
868 total table entries needed
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>Calendaring is still a pain</title>
   <link href="http://sodabrew.com/2007/07/calendaring-is-still-a-pain.html"/>
   <updated>2007-07-27T13:59:19-07:00</updated>
   <id>http://sodabrew.com/2007/07/calendaring-is-still-a-pain</id>
   <content type="html">&lt;p&gt;Why is calendaring still such a pain in the ass? There&amp;#8217;s been nothing but a proliferation of propriety solutions, web apps that store their data locally and do not share it, servers that speak antiquated versions of dodgy protocols, and clients that are continually being rebuilt from the ground up instead of evolved to be more useful over time.&lt;/p&gt;

&lt;p&gt;Killing Exchange is still the killer application. We can&amp;#8217;t think past that because, much as we&amp;#8217;d like to, we still have to work with our sales, marketing, executive, and other non-technical staffs that Just Won&amp;#8217;t Use Anything Else (TM). Or will they? Is the big problem here that everyone is so accustomed to Outlook that they cannot switch, or that organizations think this way and therefore attempt to deploy Exchange-compatible services to cater to a perceived need for Outlook clients?&lt;/p&gt;

&lt;p&gt;Is anybody actually running &lt;a href='http://www.mozilla.org/projects/calendar/'&gt;Mozilla Sunbird&lt;/a&gt; in a real office environment?&lt;/p&gt;

&lt;p&gt;Off in my project world, I was just thinking to myself, &lt;em&gt;&quot;Hmm, maybe I should build a WebDAV server into DBMail. The storage model is all key-value, so I could fake the whole thing as email headers.&quot;&lt;/em&gt; Then I found this &lt;a href='http://freshmeat.net/projects/imap_calendar_proxy/'&gt;DAV-IMAP&lt;/a&gt; proxy. I&amp;#8217;m not actually sure if it speaks DAV or just the subset required for Mozilla Sunbird. But whatever - the point is, it&amp;#8217;s a calendar in a mailbox. On a non-calendar-aware client, you could just read through your Calendar mailbox to see an ugly-but-workable view of your calendar events. On a calendar-aware client, you get the full awesomeness of a calendar. And shared calendars? That might just come for free if your mail server implements shared folders, as DBMail indeed does.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Crosspost test</title>
   <link href="http://sodabrew.com/2007/07/crosspost-test.html"/>
   <updated>2007-07-17T12:11:05-07:00</updated>
   <id>http://sodabrew.com/2007/07/crosspost-test</id>
   <content type="html">&lt;p&gt;This is a crosspost. Let&amp;#8217;s see if it works&amp;#8230; &lt;!--More--&gt; This is more stuff. It should be an lj-cut that links back to my blog. Wow cool if it works!&lt;img src='http://photos-a.ak.facebook.com/photos-ak-sf2p/v77/149/69/6713924/n6713924_32381476_197.jpg' border='0' alt='Bonus point to San Diego for having awesome beaches!' /&gt; &lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Working at Six Apart</title>
   <link href="http://sodabrew.com/2007/04/working-at-six-apart.html"/>
   <updated>2007-04-29T11:44:45-07:00</updated>
   <id>http://sodabrew.com/2007/04/working-at-six-apart</id>
   <content type="html">&lt;p&gt; I am setting sail for San Francisco, to a web development firm. My new daily grind awaits! Oh, heh, and hopefully they won&amp;#8217;t mind that this blog runs WordPress ;-)&lt;/p&gt;
&lt;a href='http://www.facebook.com/photo.php?pid=31881690&amp;amp;id=6713924' class='tt-facebook-photo'&gt;&lt;img src='http://photos-690.ak.facebook.com/ip002/v67/149/69/6713924/s6713924_31881690_4539.jpg' border='0' alt='This grinder is turning out lots of small grinders.' /&gt;&lt;/a&gt;</content>
 </entry>
 
 <entry>
   <title>Private: Simplifi Digital - Home Theater Audio</title>
   <link href="http://sodabrew.com/2007/03/simplifi-digital-under-linux-and-mac-os-x.html"/>
   <updated>2007-03-07T15:44:05-08:00</updated>
   <id>http://sodabrew.com/2007/03/simplifi-digital-under-linux-and-mac-os-x</id>
   <content type="html">&lt;p&gt;A while back I got a Simplifi Simplifi 5075D USB amplifier to build up my home theater system. But there was a catch: Simplifi Digital did not support Linux or Mac OS X, and I was not going near Windows MCE in my living room. What to do? Ask Simplifi Digital for a loaner box to test out the cross-platform support!&lt;/p&gt;

&lt;p&gt;I had been planning out my digital home theater system for a while, but always hit one stumbling block in designing the system: I needed a remote control to turn the amplifier on and off, and to change the volume, or I needed an IR blaster to do it from the computer. But an IR blaster doesn&amp;#8217;t know if its turning the device on or off and can&amp;#8217;t bring the amp to a known volume level at startup, say for use as an alarm clock or scheduling it to turn on your favorite show when you get home from work. Yes, I know &lt;em&gt;some&lt;/em&gt; amplifiers have distinct remote control commands for &amp;#8216;on&amp;#8217; and &amp;#8216;off&amp;#8217;, but that sort of esoteric minutiae is nearly impossible to figure out before buying the device.&lt;/p&gt;

&lt;p&gt;What I needed was an amplifier that could be completely controlled by my home theater system, without any buttons, switches, remote controls, or strange serial protocols requiring one-off, hacked up cabling. Enter &lt;a href='http://simplifidigital.com/'&gt;Simplifi Digital&lt;/a&gt;.&lt;/p&gt;
&lt;strong&gt;In a Nutshell&lt;/strong&gt;
&lt;p&gt;The Simplifi Digital 5075D USB amplifier works great under Linux, with many distributions supporting its 5.1 audio right out of the box. For those that don&amp;#8217;t, you configure it just like a SoundBlaster 24-bit USB audio card (details below). The 5075D does &lt;em&gt;not&lt;/em&gt; work under Mac OS X in anything but 2.0 channel mode. Instead, I recommend the Simplifi Digital 5075 Analog 5.1 amplifier and a Griffin FireWave 1394 sound card; this combination works in 2.1 right out of the box, and in 5.1 with Griffin&amp;#8217;s drivers (details below).&lt;/p&gt;
&lt;strong&gt;Linux in Detail&lt;/strong&gt;
&lt;p&gt;foo.&lt;/p&gt;
&lt;strong&gt;Mac OS X in Detail &lt;/strong&gt;
&lt;p&gt;foo.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Powerset</title>
   <link href="http://sodabrew.com/2007/02/powerset.html"/>
   <updated>2007-02-26T10:45:04-08:00</updated>
   <id>http://sodabrew.com/2007/02/powerset</id>
   <content type="html">&lt;p&gt;I had a pretty good job offer this past month from a natural language search firm looking for computational linguists &amp;#8211; a dream job, right up my alley &amp;#8211; but had to turn it down, for no other reason but the horrendously lopsided employment contract. Bottom ine: this management team does not trust the people it hires. So, for the benefit of those out there who have a habit of not reading what you sign, pay heed to some of the onerous provisions you may be committing yourself to.&lt;/p&gt;

&lt;p&gt;They did invite me to launch party, though, and between meeting famous linguists whose papers I studied in school, and watching the &lt;a href='http://valleywag.com/tech/hype-watch/the-questionable-personhood-of-powerset-235889.php' title='ValleyWag: D7TV crashes the Powerser Launch Party'&gt;party crashing&lt;/a&gt; going on, the entire scene almost had me break out in uncontrollable lulz.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Working at Decru</title>
   <link href="http://sodabrew.com/2006/12/working-at-decru.html"/>
   <updated>2006-12-09T00:12:37-08:00</updated>
   <id>http://sodabrew.com/2006/12/working-at-decru</id>
   <content type="html">&lt;p&gt;In November, I took a job at &lt;a href='http://www.decru.com/'&gt;Decru&lt;/a&gt;, a &lt;a href='http://www.netapp.com/'&gt;Network Appliance&lt;/a&gt; company, as a QA Engineer. I&amp;#8217;m in the Partner Relations group. Our job is to establish relationships with third party QA labs to run formal interoperability certifications between our products and their products. There&amp;#8217;s two other people in the group, and they&amp;#8217;re both really great to work with.&lt;/p&gt;

&lt;p&gt;Decru&amp;#8217;s products are a set of hardware encryption appliances that sit on Ethernet, Fibre Channel or SCSI links between users, servers, disk arrays and tape backup systems, encrypting the data as it goes to the storage device and decrypting the data it goes towards the users. Decru itself is a fun little company, very laid back and friendly people who are really keen on security, good code, and sane release schedules. This is a company that sells to Fortune 500&amp;#8217;s and the government, so there&amp;#8217;s no hot-dogging of features that don&amp;#8217;t work, don&amp;#8217;t make sense or won&amp;#8217;t be reliable. But this is still Silicon Valley, so while the products need to be really staid devices, the company itself is still a dynamic place with lots of neat ideas floating around.&lt;/p&gt;

&lt;p&gt;Company trivia: the co-founders knew that they wanted to start a company, and knew the crew that they wanted to start it with, and knew the wanted to do something in either storage or security. They combined the two, called up &amp;#8216;da crew&amp;#8217; (think bad Israeli accents) and thus Decru was formed.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Job Hunting</title>
   <link href="http://sodabrew.com/2006/10/job-hunting.html"/>
   <updated>2006-10-20T12:33:52-07:00</updated>
   <id>http://sodabrew.com/2006/10/job-hunting</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been interviewing all week with small and large firms in the San Jose / Silicon Valley area for work as a Software Engineer. Interviewing is a lot of fun &amp;#8211; dress just slightly better than the firm you&amp;#8217;re walking into, but not too much better, else they&amp;#8217;ll think you&amp;#8217;re a business person and not an engineer &amp;#8211; get tons of adrenaline flowing but stay calm and try not to forget everything you learned in school (which you&amp;#8217;ll inevitably be asked to draw out on the nearest whiteboard) &amp;#8211; and, most importantly, don&amp;#8217;t forget to interview &lt;em&gt;them! &lt;/em&gt;The company wants someone who wants to be there, so you have to ask a lot of questions about the company to see if you do want to be there. What&amp;#8217;s their management style? How well funded are they? Are they turning a profit on current products? How many people work there? Is there a program in place to reward extra effort that you put into projects? Do they order in dinner on the late work nights before a major product launch? And when it&amp;#8217;s over, don&amp;#8217;t tarry, just thank them, give an honest impression if you liked the work place, and be sure to follow up in 2-3 days.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Summer of Code!</title>
   <link href="http://sodabrew.com/2006/05/summer-of-code.html"/>
   <updated>2006-05-27T19:05:22-07:00</updated>
   <id>http://sodabrew.com/2006/05/summer-of-code</id>
   <content type="html">&lt;p&gt;I got in! &lt;a href='http://hydricacid.com/SoC2006/SoC2006-Joomla.html'&gt;Joomla!&lt;/a&gt; will be my project, with Lee Cher Yeong as my mentor. To celebrate, I&amp;#8217;m reading two books and building a barbeque pit.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Done with Midterms and SoC apps</title>
   <link href="http://sodabrew.com/2006/05/four-soc-applications.html"/>
   <updated>2006-05-09T09:23:24-07:00</updated>
   <id>http://sodabrew.com/2006/05/four-soc-applications</id>
   <content type="html">&lt;p&gt;I wrote four applications for the Summer of Code. The first one took like 12 hours to research and write, and the other three took 1-3 hours each. Once I got the hang of how I wanted to present stuff, it was just a matter of serializing it out of my head. In descending order of time put into the application (which happens to be inversely proportional to the amount of time I&amp;#8217;ve already spent on the project): &lt;a href='http://hydricacid.com/SoC2006/SoC2006-Joomla.html'&gt;Joomla&lt;/a&gt;, &lt;a href='http://hydricacid.com/SoC2006/SoC2006-PDX-Network.html'&gt;Network Monitoring&lt;/a&gt;, &lt;a href='http://hydricacid.com/SoC2006/SoC2006-libSieve.html'&gt;libSieve&lt;/a&gt;, &lt;a href='http://hydricacid.com/SoC2006/SoC2006-TWIG.html'&gt;TWIG&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Amazingly I got through my midterms alive, got back an A on an essay, and am not going crazy! I am totally sick with a yucky head cold, though. Damn you, not enough sleep demon! And on an unrelated note, I installed WorkRave to keep me from typing too much at a time. It would really benefit from having information from XIDLE to keep track of how long I&amp;#8217;m actually at the computer rather than just blindly counting down all the time.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Summer of Code 2006</title>
   <link href="http://sodabrew.com/2006/04/summer-of-code-2006.html"/>
   <updated>2006-04-28T13:00:57-07:00</updated>
   <id>http://sodabrew.com/2006/04/summer-of-code-2006</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m planning on putting out a few proposals to get into the SoC 2006. I had hoped to get TWIG in as a mentor, but that didn&amp;#8217;t go through. So I&amp;#8217;ll take a tangent, and definitely see if there&amp;#8217;s other good PHP work that can benefit everyone. My ideas are:&lt;/p&gt;

&lt;p&gt;&lt;a href='http://summer.cs.pdx.edu/?q=node/12'&gt;Portland State University&lt;/a&gt;: Open to &amp;#8220;projects that might fall through the cracks&amp;#8221; &amp;#8211; I&amp;#8217;m going to pitch XIDLE/XCB, TWIG and the network monitoring integration.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://xorg.freedesktop.org/wiki/SummerOfCodeIdeas'&gt;X.Org&lt;/a&gt;: See if they&amp;#8217;ll go for my XIDLE request to get that working again. Otherwise, check out their XCB stuff. I&amp;#8217;d like to learn it!&lt;/p&gt;

&lt;p&gt;&lt;a href='http://dev.joomla.org/content/view/1360/85/'&gt;Joomla&lt;/a&gt;: wants to do a phpGACL layer, a DB abstraction layer and an AJAX layer. I&amp;#8217;m good for all of those. I&amp;#8217;m not sure if I want to be reporting to this project, although the work looks good.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://wiki.horde.org/SummerOfCode2006'&gt;Horde&lt;/a&gt; LDAP Browser / Manager: Develop a Horde LDAP application capable of both browsing and managing an LDAP directory. Should also support importing and exporting LDIF files. Now this would just be funny. Basically I&amp;#8217;d port/rewrite my TWIG ldap browser into Horde. Or maybe funny-sad :-\&lt;/p&gt;

&lt;p&gt;&lt;a href='http://www.postgresql.org/developer/summerofcode'&gt;PostgreSQL&lt;/a&gt;: PL/PHP Build Improvments: PL/PHP is a PHP based procedural language for PostgreSQL. This project would clean up memory usage and the plphp_proc_desc struct, be built without Apache&amp;#8217;s SAPI module, allow large resultsets to be processed through transparent use of prefetching on a cursor when spi_exec is called, and support IN/OUT and named parameters.&lt;/p&gt;

&lt;p&gt;Proposal &lt;a href='http://www.perlfoundation.org/gc/grants/proposals.html'&gt;guidelines&lt;/a&gt; and &lt;a href='http://mediawiki.blender.org/index.php/BlenderDev/SoCIKProposal'&gt;example&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Asynchronous TWIG</title>
   <link href="http://sodabrew.com/2006/04/asynchronous-twig.html"/>
   <updated>2006-04-17T09:20:14-07:00</updated>
   <id>http://sodabrew.com/2006/04/asynchronous-twig</id>
   <content type="html">&lt;p&gt;Last week I got an itch to learn something about AJAX, and procrastinate a little bit on some work. I started out by trying to find some useful springboard to get into AJAXland, but discovered that a) most of the PHP toolkits for AJAX are really big and foreboding, and b) JSON notation is the new preferred X format in AJAX. So we&amp;#8217;ll call it Ajax and Jason, I guess.&lt;/p&gt;

&lt;p&gt;After a while, I scoped out a few bare-bones tutorials and hacked together my own script in their fashion. Then I found a Jason converter for PHP that follows the semantics of what will probably be a pair of PHP built-ins, json_encode and json_decode. Simple as that. Pass in an array and it spits out the array in Jason, ready for consumption by your JavaScript. Well, about six hours of hacking later, I now have TWIG 4&amp;#8217;s data tables slurping data asynchronously from Jason modules. Model-View separation suddenly became incredibly easy! In fact, when I copy-pasted code from the Wiki feature, the first to get its Jason upgrade, into the Mail feature, and tied it together with a simple public domain tree system, it pulled up my mailboxes but showed me the contents of the Wiki system! Wait, that&amp;#8217;s good! It took just five keystrokes to switch the request over to grab data from Mail :-)&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Looking for a new ThinkPad.</title>
   <link href="http://sodabrew.com/2006/03/looking-for-a-new-thinkpad.html"/>
   <updated>2006-03-28T10:55:53-08:00</updated>
   <id>http://sodabrew.com/2006/03/looking-for-a-new-thinkpad</id>
   <content type="html">&lt;p&gt;Ok, here&amp;#8217;s the new wishlist item: &lt;a href='http://www-131.ibm.com/webapp/wcs/stores/servlet/ProductDisplay?productId=4611686018425155327&amp;#038;catalogId=-840' title='ThinkPad X60s'&gt;ThinkPad X60s&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cash in hand: $400. More to raise: $1400.&lt;/p&gt;

&lt;p&gt;I wish I could go for something cheaper, but the battery life on this thing, especially with the extra battery pack, is just amazing. Two models ago, when new, I got an honest 8 hours. After a year and a half, it has died down to 5 hours. This new model has the same size batteries, and lower power consumption on the hard drive and CPU. The reviews have been awesome, just as they were with my poor old laptop :-|&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Stop, Thief!</title>
   <link href="http://sodabrew.com/2006/03/stop-thief.html"/>
   <updated>2006-03-20T15:47:19-08:00</updated>
   <id>http://sodabrew.com/2006/03/stop-thief</id>
   <content type="html">&lt;p&gt;My laptop was stolen at about 4am-ish this past Friday. I&amp;#8217;d been pulling all-nighters at the dining room table for weeks, and I&amp;#8217;d just turned in at about 2am. The thief let himself in one of the doors, headed for a housemate&amp;#8217;s room, scoping it out with a flashlight and woke her up. At first she thought it was a housemate needing help or something, but then the thief bolted out of her room, grabbed whatever he could from the dining room, stuffed it in a backpack stolen from the living room, and left out the side door, taking a bike as a get-away vehicle. He also got two wallets and two sets of keys, but chose to steal a bike to get away. Major bummer! I&amp;#8217;m starting a collection for the buy-a-new-laptop fund.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Sieve in DBMail: Check!</title>
   <link href="http://sodabrew.com/2006/03/sieve-in-dbmail-check.html"/>
   <updated>2006-03-08T02:27:31-08:00</updated>
   <id>http://sodabrew.com/2006/03/sieve-in-dbmail-check</id>
   <content type="html">&lt;p&gt;DBMail now has Sieve script support, starting with DBMail 2.1.4 and libSieve 2.1.10. A marathon two weeks of integration, three releases of libSieve, and two releases of the DBMail 2.1 development series, and it&amp;#8217;s together and working. And it was only on my todo list for two years. Probably the most interesting part of the experience was working on both sides of a library: maintaining the library and the downstream application consuming it. Even when it was tempting to Just Fix It (TM) when I came across a bug, most of the time these bugs were crashes caused by misunderstandings or garbage data flowing between the programs. Within a single program, you can just document that a function doesn&amp;#8217;t like garbage, refactor the function and its consumer, whatever. But when you&amp;#8217;ve got a library intended for consumption in its own right &amp;#8211; and an &lt;em&gt;almost&lt;/em&gt; frozen API &amp;#8211; Garbage In Garbage Out (TM) is a less than ideal situation. The better approach is to handle the garbage elegantly and return useful error messages, like this: Error: you gave me garbage but all you&amp;#8217;re going to get back is this lousy error message. And a t-shirt, I suppose ;-)&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Job Hunt</title>
   <link href="http://sodabrew.com/2006/03/school.html"/>
   <updated>2006-03-08T02:13:42-08:00</updated>
   <id>http://sodabrew.com/2006/03/school</id>
   <content type="html">&lt;p&gt;As of November 2006, I will be available for full-time employment. I am primarily interested in communications and email software development, focusing on backend network services and database storage. But anything fun and challenging will do the trick.&lt;/p&gt;

&lt;p&gt;In the interim, I have taken on several small businesses and individuals as clients for network operations and office computer maintenance services on a monthly basis. I have found this small-scale work to fun and rewarding, building positive references and networking with potential dream-job employers.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Funding my open source habit</title>
   <link href="http://sodabrew.com/2005/12/funding-my-open-source-habit.html"/>
   <updated>2005-12-05T09:30:00-08:00</updated>
   <id>http://sodabrew.com/2005/12/funding-my-open-source-habit</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been thinking that it might be time to start &amp;#8220;development bounties&amp;#8221; for all of my projects. I&amp;#8217;ve gotten a few gift certificates, a hard drive, and some offers of cash, and I know that it really changes my prioritization when someone says, &amp;#8220;Hey, I know you&amp;#8217;re busy. Can I entice you to make time with a few bucks or some stuff?&amp;#8221; And you know, it sure does change my priorities. I get right up off my butt and change my schedule. It&amp;#8217;s a paying gig, and I think the more of them you do the more offers you&amp;#8217;ll get.&lt;/p&gt;

&lt;p&gt;If I could fund most of my computing and open source habit with bounties, I&amp;#8217;d be pretty happy. A little back of the envelope shows that it could even be part of an ad-hoc career: a $50,000 a year salary is $1,000 a week. How many sub-projects are there out there that would take me about a week each, and be worth $1,000 to someone? Tons! How many could I land? Maybe not that many. Hmm.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>DBMail progress</title>
   <link href="http://sodabrew.com/2005/11/dbmail-progress.html"/>
   <updated>2005-11-30T15:21:56-08:00</updated>
   <id>http://sodabrew.com/2005/11/dbmail-progress</id>
   <content type="html">&lt;p&gt;This week I got a bunch of DBMail stuff done:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loadable database modules. Then Paul reorganized the files into a single, consistent dbmail/modules directory, and that inspired me to to authentication and sort modularization. Still a few tweaks left to do on auth, and the guts of sort are totally not figured out yet.&lt;/li&gt;

&lt;li&gt;Cleared the way for Sieve reintegration, handling username+mailbox@domain addressing, and better stderr debugging.&lt;/li&gt;

&lt;li&gt;Lots of updates on the DBMail Wiki so that people can find out what&amp;#8217;s cooking.&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>Back onto DBMail</title>
   <link href="http://sodabrew.com/2005/11/back-onto-dbmail.html"/>
   <updated>2005-11-26T06:55:25-08:00</updated>
   <id>http://sodabrew.com/2005/11/back-onto-dbmail</id>
   <content type="html">&lt;p&gt;Been a while since I was last hacking actively on DBMail, but I&amp;#8217;m back! Thanks much to a development bounty that&amp;#8217;s motivating me, and thanks to generally clearing my schedule of some useless junk . I also rather ought to use this blog more. The two things I&amp;#8217;ve been working on now for DBMail are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loadable modules for database drivers, &lt;em&gt;because I'm sick of recompiling between MySQL and PostgreSQL.&lt;/em&gt;&lt;/li&gt;

&lt;li&gt;Sieve support and integration, &lt;em&gt;because it's been on the back burner for almost two years, and a fellow on the DBMail list offered me $1000 to finish it!&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>Saved by Foremost</title>
   <link href="http://sodabrew.com/2005/05/saved-by-foremost.html"/>
   <updated>2005-05-28T17:50:32-07:00</updated>
   <id>http://sodabrew.com/2005/05/saved-by-foremost</id>
   <content type="html">&lt;p&gt;Many of the indirect blocks on the filesystem were hosed, so a big, big chunk of data cannot be organized back into a coherent chunk. &lt;em&gt;sigh&lt;/em&gt; Making things worse is that there&amp;#8217;s a filesystem-in-a-filesystem, because the backup image has an older backup image in it. So even with indirect block searches, there&amp;#8217;s no way to know which filesystem&amp;#8217;s block offsets you&amp;#8217;re looking at. &lt;a href='http://formost.sf.net/'&gt;Foremost&lt;/a&gt; is the tool that scanned the data and recovered a goodly many of my pictures.&lt;/p&gt;

&lt;p&gt;For the future, everyone should be using XFS, and regularly running &lt;code&gt;xfs_fsr&lt;/code&gt; which comes from the xfsdump package. It reorganizes a file&amp;#8217;s blocks so that they are contiguous. Apparently it&amp;#8217;s a daily cron job on IRIX. Make it part of your life on Linux.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Salvaging a backup</title>
   <link href="http://sodabrew.com/2005/05/salvaging-a-backup.html"/>
   <updated>2005-05-13T21:34:48-07:00</updated>
   <id>http://sodabrew.com/2005/05/salvaging-a-backup</id>
   <content type="html">&lt;p&gt;So I have this backup of a hard drive I sent in for RMA, and on that was a backup from my old laptop hard drive. Fortunately for me, the filesystem of the outer backup is corrupted to shit. I&amp;#8217;ve been trying various combinations of e2retrieve, e2salvage, debugfs, and have had no luck. Another fellow on the e2salvage-devel mailing list referred me to this set of tools, &lt;a href='http://dreamscape.org/toolkit/README.html'&gt;e2extract&lt;/a&gt;. Wish me luck.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Crappity crap, homework crap</title>
   <link href="http://sodabrew.com/2005/05/crappity-crap-homework-crap.html"/>
   <updated>2005-05-10T12:10:48-07:00</updated>
   <id>http://sodabrew.com/2005/05/crappity-crap-homework-crap</id>
   <content type="html">&lt;p&gt;Homework all shot to hell. Crap. Crap crap crap. Crap.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Finger’s all better, so I’ll make a Wishlist</title>
   <link href="http://sodabrew.com/2005/05/fingers-all-better-so-ill-make-a-wishlist.html"/>
   <updated>2005-05-08T12:46:08-07:00</updated>
   <id>http://sodabrew.com/2005/05/fingers-all-better-so-ill-make-a-wishlist</id>
   <content type="html">&lt;p&gt;It took nearly 3 weeks, but my finger&amp;#8217;s 100% back up to speed now, there&amp;#8217;s just a bunch of redness around the wound site. I&amp;#8217;m putting up a wishlist on my main page. I realized that there&amp;#8217;s a bunch of tech stuff I&amp;#8217;d like and keep re-researching everytime I think about it. Very silly. I&amp;#8217;m making a list.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Nope, no books after all</title>
   <link href="http://sodabrew.com/2005/04/nope-no-books-after-all.html"/>
   <updated>2005-04-21T23:59:37-07:00</updated>
   <id>http://sodabrew.com/2005/04/nope-no-books-after-all</id>
   <content type="html">&lt;p&gt;I didn&amp;#8217;t end up reading any books. Instead I&amp;#8217;ve been sleeping much more than usual, my finger is driving me up a wall, I&amp;#8217;ve had non-stop meetings every night and days now, too, and that&amp;#8217;s taking quite a toll. The hurry-up-and-wait of a 1 hour meeting is like 3 hours out of my day to prep for, participate in, and recover from each meeting.&lt;/p&gt;

&lt;p&gt;I took the bandage off my finger for the evening to let it air out a bit and get some feeling back in my fingertip. It&amp;#8217;s going to get bandaged up again before bedtime because it&amp;#8217;s still basically an open wound. I suppose if I weren&amp;#8217;t so tired, I&amp;#8217;d be more interested in all of the layers of skin I get to see now. Bah.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Finger mauling</title>
   <link href="http://sodabrew.com/2005/04/finger-mauling.html"/>
   <updated>2005-04-16T11:44:31-07:00</updated>
   <id>http://sodabrew.com/2005/04/finger-mauling</id>
   <content type="html">&lt;p&gt;I was going to go camping this weekend, but while packing up the trunk of the car discovered a wonderful razor edge on the decorative chrome trim of the 2004 Jetta. My right ring finger has a giant gash along the topside. Programming is probably not going to be happening this week at all, due to lack of curly-brace-button-pushing-fingers. Grumble. I may actually have to relax and read a book!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>TWIG NG testing on the web</title>
   <link href="http://sodabrew.com/2005/04/twig-ng-testing-on-the-web.html"/>
   <updated>2005-04-15T10:51:14-07:00</updated>
   <id>http://sodabrew.com/2005/04/twig-ng-testing-on-the-web</id>
   <content type="html">&lt;p&gt;My work on TWIG NG is now up on the TWIG website. The URL is secret for the time being, just in case my new security model breaks or I left any crufty code that would sink it. But it&amp;#8217;s exciting to have it up, even if it is just for a few people right now!&lt;/p&gt;

&lt;p&gt;On the DBMail side, looks like there&amp;#8217;s a critical mass of bugs now. Time to get cracking on them and heading to another release&amp;#8230;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Building a TWIG Roadmap</title>
   <link href="http://sodabrew.com/2005/04/building-a-twig-roadmap.html"/>
   <updated>2005-04-06T16:47:38-07:00</updated>
   <id>http://sodabrew.com/2005/04/building-a-twig-roadmap</id>
   <content type="html">&lt;p&gt;And so from here we embark on a journey to the future of TWIG. I&amp;#8217;m working on a roadmap that incorporates the various TWIG 3 proposals and renaming my own work at TWIG NG. All reasonable goals will become part of TWIG NG, and anything that can be done in a reasonable time frame will be moved into the TWIG 3 list. And so begins the who-wants-what shootout&amp;#8230;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>What the heck is this DocBook error?</title>
   <link href="http://sodabrew.com/2005/04/what-the-heck-is-this-docbook-error.html"/>
   <updated>2005-04-01T10:52:36-08:00</updated>
   <id>http://sodabrew.com/2005/04/what-the-heck-is-this-docbook-error</id>
   <content type="html">&lt;p&gt;I DocBookified the TWIG manual, but I can&amp;#8217;t compile it due to some strange errors that don&amp;#8217;t appear to be coming from the DTD&amp;#8230;&lt;/p&gt;
&lt;code&gt;jade -t tex -V tex-backend 
        -d print.dsl 
        /usr/share/sgml/xml.dcl AdminManual.db
jade:AdminManual.db:3:57:E: URL not supported by this version
jade:print.dsl:1:0:E: end of document in prolog
jade:E: specification document does not have the DSSSL architecture as a base architecture
make: *** [AdminManual.tex] Error 1&lt;/code&gt;</content>
 </entry>
 
 <entry>
   <title>Considering what will be TWIG 3</title>
   <link href="http://sodabrew.com/2005/03/considering-what-will-be-twig-3.html"/>
   <updated>2005-03-23T10:47:48-08:00</updated>
   <id>http://sodabrew.com/2005/03/considering-what-will-be-twig-3</id>
   <content type="html">&lt;p&gt;So now there&amp;#8217;s an alternate proposal for TWIG 3. It&amp;#8217;s much less ambitious, and completely based on improvements from the current codebase rather than my work so far. Sort of annoying. But there&amp;#8217;s an upside to this, and it&amp;#8217;s that I may be able to convince everyone else of the dire need for good UI&amp;#8217;s in TWIG for first-time install, setup, ongoing configuration, and first-time user logins. Frankly, if we can tackle all of that then I&amp;#8217;ll be happy calling it TWIG 3.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Finals over, DocBook is on</title>
   <link href="http://sodabrew.com/2005/03/finals-over-docbook-is-on.html"/>
   <updated>2005-03-17T14:00:56-08:00</updated>
   <id>http://sodabrew.com/2005/03/finals-over-docbook-is-on</id>
   <content type="html">&lt;p&gt;Finals this quarter weren&amp;#8217;t horrible so much as because the tests were hard, but I just wasn&amp;#8217;t in the state of mind for them. Total bummer. I&amp;#8217;m wishing myself luck in passing classes. Otherwise. No otherwise.&lt;/p&gt;

&lt;p&gt;On a more exciting note, I&amp;#8217;m in the process of rewriting the TWIG Admin Manual into DocBook. Apparently it was originally written with MS FrontPage, then lots of editing by hand, then let to rot for too many versions. DocBook is a semantic markup format that can easily produce HTML, PDF and other formats with pretty looking layout. I really don&amp;#8217;t want to spend more than a long afternoon on this; I&amp;#8217;m not going to rewrite the actual manual right now, just convert the data over to DocBook, generate something good looking but still horridly out of date, and make it much easier to be updated in the future.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Whew, cleared those bugs up</title>
   <link href="http://sodabrew.com/2005/03/whew-cleared-those-bugs-up.html"/>
   <updated>2005-03-13T10:18:07-08:00</updated>
   <id>http://sodabrew.com/2005/03/whew-cleared-those-bugs-up</id>
   <content type="html">&lt;p&gt;And thenceforth a fortnight later the bugs were done or passed along. Big relief. Can&amp;#8217;t wait for the next releases! I need to kick some butt on my computer science homework this weekend. It&amp;#8217;s almost mind numbing, because the instructor wants things done in just such a way, and worse yet, on tests, won&amp;#8217;t accept any form of written explanation. Code or die. On paper. This must make sense to people who come to these classes with their own experience and knowledge in square one, but mine&amp;#8217;s not. I hate coding real C on paper. Where they ding you for all sorts of stupid syntactic and even sylistic conventions. Dude, it&amp;#8217;s paper. Not paper tape, not punchcards, but pencil and paper. I code in vim.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Lagging on my bugs</title>
   <link href="http://sodabrew.com/2005/02/lagging-on-my-bugs.html"/>
   <updated>2005-02-18T05:51:38-08:00</updated>
   <id>http://sodabrew.com/2005/02/lagging-on-my-bugs</id>
   <content type="html">&lt;p&gt;I have two bugs on my plate for over a week, and I&amp;#8217;m really lagging on them. Stupid other things to do. DBMail 2.0.3 needs a bug fix for users who are over quota. Right now it bounces the message with a temporary failure. This leads to the MTA trying to deliver again. Temporary failure. Again. Temporary failure. Eventually the queue gets pretty blocked up. Not so good. And TWIG 2.8.1 needs a fix for the FindHTML function that gets called to process the To, From, CC, BCC headers for possible HTML in email addresses. Better handled by the imap_rfc822_parse_address function provided by the imap c-client. On a 40,000 address test corpus I ran, imap_rfc822 took 1.6 seconds to parse those 40k addresses. FindHTML took an hour before I killed the process. Not so good.&lt;/p&gt;

&lt;p&gt;So instead I&amp;#8217;m working on some homework and distracting myself with the TWIG website. Two years ago I had the idea to write the TWIG website in TWIG. So I hacked up a version to do that. And today I had an epiphany for how I can do it a lot smarter from within the TWIG 3 framework I&amp;#8217;ve began 8 months ago. Can&amp;#8217;t wait to have time to get this really cooking!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Looking at WiClear again</title>
   <link href="http://sodabrew.com/2005/02/looking-at-wiclear-again.html"/>
   <updated>2005-02-14T04:30:06-08:00</updated>
   <id>http://sodabrew.com/2005/02/looking-at-wiclear-again</id>
   <content type="html">&lt;p&gt;Wow, my first comment! Thanks to David, the author of WiClear for noticing me! Well, and that I was ripping on WiClear&amp;#8230; or more specifically, the WikiRenderer engine used by WiClear.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s true that I didn&amp;#8217;t do any sort of big comparison between DokuWiki and WiClear, but I noted that the syntax and engine of WiClear didn&amp;#8217;t seem like much. David says otherwise, and that it&amp;#8217;s all pretty customizable anyways. So, definitely worth a second look. The one toughie is that my lack of French makes it fairly difficult to dig into the websites for WiClear (mostly translated, though) or WikiRenderer (not translated much at all). When I have more time next week I&amp;#8217;ll look into the WikiRenderer code and see if it&amp;#8217;s worth jumping back to WiClear instead of DokuWiki. If it actually does have enough of the syntax needed to support the basics of my site, I can write whatever little bits I need to make the details work out.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>CSS in TWIG</title>
   <link href="http://sodabrew.com/2005/02/css-in-twig.html"/>
   <updated>2005-02-11T14:50:40-08:00</updated>
   <id>http://sodabrew.com/2005/02/css-in-twig</id>
   <content type="html">&lt;p&gt;So the raging debate on the &lt;a href='http://informationgateway.org/'&gt;TWIG&lt;/a&gt; mailing list seems to come down to this: Should CSS become an intrinsic part of our menu generation, or should there be &amp;#8220;static HTML&amp;#8221; menus and CSS menus and the user gets to choose. I say scrap the crufty full-HTML menus. They&amp;#8217;re dinosaurs from HTML 3. We can describe them in lightweight, structural HTML and use CSS to make it pretty, and that&amp;#8217;s that. The user should not be choosing to use an HTML 3 menu or a CSS menu, and then their choice of stylesheets that may or may not affect the HTML 3 menu and that will make the CSS menu look good. I believe it will lead to balkanized, useless styles that nobody wants to write because of the horrible interaction testing that would be needed. (quoting myself) I have no problem defining 7 types of menus:&lt;/p&gt;

&lt;p&gt;Style Defined Primary Style Defined Secondary Style Defined Tabs Style Defined Vertical Style Defined Dropdown List Style Defined Icons with Text Style Defined Icons without Text&lt;/p&gt;

&lt;p&gt;And throw the rest away.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>DokuWiki and WiClear</title>
   <link href="http://sodabrew.com/2005/02/dokuwiki-and-wiclear.html"/>
   <updated>2005-02-09T07:25:53-08:00</updated>
   <id>http://sodabrew.com/2005/02/dokuwiki-and-wiclear</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been searching out the perfect wiki engine lately, and while I have been lucky enough to have settled on &lt;a href='http://wiki.splitbrain.org/wiki:dokuwiki'&gt;DokuWiki&lt;/a&gt; because it&amp;#8217;s simple, pretty and works&amp;#8230; except that it&amp;#8217;s really not all that pretty once you try putting anything other than technical documentation into it. I&amp;#8217;m actually trying to run a whole website from within DokuWiki. It&amp;#8217;s working very well, has reduced my webmaster duties a lot because I can hand out user accounts and don&amp;#8217;t have to fiddle with repetitive HTML at all anymore&amp;#8230; but it&amp;#8217;s really pissing off the form-before-function people. So I&amp;#8217;ve found &lt;a href='http://wiclear.free.fr/'&gt;WiClear&lt;/a&gt; which is &lt;strong&gt;really good
looking&lt;/strong&gt; but has a pretty crappy wiki engine inside.&lt;/p&gt;

&lt;p&gt;And so off to add templating to DokuWiki&amp;#8230; &lt;a href='http://bugs.splitbrain.org/?do=details&amp;amp;amp;id=104'&gt;Bug #104&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Projects day</title>
   <link href="http://sodabrew.com/2005/02/projects-day.html"/>
   <updated>2005-02-06T11:53:13-08:00</updated>
   <id>http://sodabrew.com/2005/02/projects-day</id>
   <content type="html">&lt;p&gt;Sunday is projects day! So to spurn the upsettedness over TWIG, I committed some more work on TWIG3 &amp;#8211; it&amp;#8217;s been almost 8 months since my last commit. Shoot. One day TWIG3 will happen and it&amp;#8217;ll be awesome. Over on the DBMail front, I fixed a bug. Er, used someone else&amp;#8217;s fix to yet another person&amp;#8217;s well-researched bug. So basically I just typed a few things into CVS. But that&amp;#8217;s my responsibility just as much as fixing bugs myself. Good work without too much hassle. A job well done :-) And on the co-op-front, I need to finish up some attic wiring before the garage-dwellers string me up by my ankles.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Back from the woodwork</title>
   <link href="http://sodabrew.com/2005/02/back-from-the-woodwork.html"/>
   <updated>2005-02-05T19:07:32-08:00</updated>
   <id>http://sodabrew.com/2005/02/back-from-the-woodwork</id>
   <content type="html">&lt;p&gt;This week a former maintainer of TWIG came out of the woodwork to complain about some of the changes in TWIG 2.8.1. It was entirely out of the blue, and although he posted well to the mailing list and seemed to ask for input from the current maintainer group, he also dug up his old CVS account and started throwing things into CVS according to his preferences. I am more than a little bit dismayed. One simply does not &amp;#8220;look up my old password&amp;#8221; three years later and start changing things just because, three years ago, he used to run the project. Most of his code has been good, and had he at least had the courtesy to ask if anyone would mind him going straight to CVS I wouldn&amp;#8217;t be so peeved. But he didn&amp;#8217;t, and thus I am quite peeved.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Better now.</title>
   <link href="http://sodabrew.com/2005/01/better-now.html"/>
   <updated>2005-01-25T17:20:40-08:00</updated>
   <id>http://sodabrew.com/2005/01/better-now</id>
   <content type="html">&lt;p&gt;Ok, it&amp;#8217;s a little less ugly and more inline with my #069 color scheme. Still need to work on this grey text, though. It&amp;#8217;s fairly annoying.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>First Post</title>
   <link href="http://sodabrew.com/2005/01/first-post-1.html"/>
   <updated>2005-01-25T16:51:27-08:00</updated>
   <id>http://sodabrew.com/2005/01/first-post-1</id>
   <content type="html">&lt;p&gt;I decided that it would be a good idea to start keeping a blog. First thing I notice, though, is that the default wordpress template is UGLY. So I&amp;#8217;ll have to fix that.&lt;/p&gt;</content>
 </entry>
 
 
</feed>
