<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
    <channel>
        <title>sowbug.org</title>
        <link>http://www.sowbug.org/mt/</link>
        <description>If all you have is a Bloom filter, everything looks like a set whose membership you wish to test with a possibility of false positives.</description>
        <language>en</language>
        <copyright>Copyright 2008</copyright>
        <lastBuildDate>Wed, 14 May 2008 09:13:23 -0800</lastBuildDate>
        <generator>http://www.sixapart.com/movabletype/</generator>
        <docs>http://www.rssboard.org/rss-specification</docs>
        
        <item>
            <title>Fixing Cygwin XWin/xterm launch problems</title>
            <description><![CDATA[<p>For years now, I've been using Cygwin X for ssh sessions on Windows. I've learned to live with an odd problem where the startxwin.bat script supplied with the distribution successfully starts up an xterm maybe only 30% of the time, and the rest of the time it does nothing.</p>

<p>Recently it got even worse with newer Cygwin versions, where the second and subsequent invocations of the script would complain about a prior instance of XWin.exe running. The dialog even taunts you by saying that the process was invoked with "-silent-dup-error."</p>

<p>After a bit of sleuthing that inspired some targeted web searches, I found the following two solutions:</p>

<p>1. Edit startxwin.bat to say this instead of the other XWin line:</p>

<p>  tasklist | \WINDOWS\system32\find.exe "XWin.exe"<br />
  if errorlevel 1 %RUN% XWin -multiwindow -clipboard -silent-dup-error</p>

<p>On Windows XP Home you won't have tasklist.exe. I leave it as an exercise to the reader to find a solution to that problem on the web.</p>

<p>This solves the -annoyingly-loud-dup-error bug.</p>

<p>2. Shut down all Cygwin processes, including especially XWin.exe. Then from your Windows command prompt, execute c:\cygwin\bin\ash. Then from the ash prompt that pops up, run /bin/rebaseall. That will take a few seconds, and then you can exit the ash shell and try your new startxwin.bat script again.</p>

<p>#1 is straightforward: someone on the development team must have recently broken -silent-dup-error in Cygwin. So this is a workaround. Incidentally, I don't know how such a major bug like this could happen if the team actually <i>uses</i> its own product, but enough of snide comments for now.</p>

<p>#2 is more obscure. Running startxwin.sh from a normal Cygwin shell produces "child_copy" errors, which is key search term leading to some web discussion from Cygwin developers about the rebaseall command. If this is anything like the rebasing I know from Windows development, then it means that the set of DLLs in your specific installation are modified to load more cleanly. I'm used to this being nothing more than a speed-of-loading thing, but perhaps the configuration of the distributed binaries was also triggering some subtle nondeterministic problem.</p>

<p>Anyway, out of 20 trials so far, I'm at 100% success. Finally I can start treating xterm sessions like software again! (I used to keep them around on my desktop even if I didn't need them, because they were genuinely scarce entities.)</p>]]></description>
            <link>http://www.sowbug.org/mt/2008/05/fixing-cygwin-xwinxterm-launch.html</link>
            <guid>http://www.sowbug.org/mt/2008/05/fixing-cygwin-xwinxterm-launch.html</guid>
            
            
            <pubDate>Wed, 14 May 2008 09:13:23 -0800</pubDate>
        </item>
        
        <item>
            <title>Goodbye, Google. Hello, FSX!</title>
            <description><![CDATA[<p>I'm doing something pretty goofy today: I'm leaving Google. My tattered old employee badge goes back to HR during my exit interview at 4:00 this afternoon. After that I'll be an ex-Googler.</p>

<p>Working at Google was as amazing as everyone says it is. Sure, the perks were nice. I'll miss the delicious meals, the ski trips, the commuter shuttle, and TGIF. But any company could provide such benefits, given enough free cash flow. What makes Google unique is its culture of respect. The tough interview process means that engineers are treated with respect from their first day. In such a supportive environment, even the most timid person works with self-confidence, which is marvelous to witness. This element of the company's culture was the biggest difference between Google and every other place I've worked in the past. I hope to take it with me throughout the rest of my career.</p>

<p>Which brings me to the future. What's next? I'd originally intended to take a year off and bang on a few software ideas that have been rattling around my head. I'd then pick the most promising one, find some friends, and start up a new venture. As it turned out, things went faster than I expected, and not exactly in the order I'd expected, but the result was the same.</p>

<p>My new venture is a software startup called FSX. I think of the company as a mashup of eBay, Charles Schwab, and American Idol. FSX will use a highly accurate, simulated brokerage to identify skilled stock portfolio managers. For the majority of participants, the fun of FSX's community and fantasy stock exchange will be its own reward. But there will be a tiny number of managers who we find can consistently outperform the field. For those newly discovered stars, we'll provide a market of investors willing to entrust real investment funds to their management.</p>

<p>The business idea is risky, no doubt. The <a href="http://www.amazon.com/Random-Walk-Down-Wall-Street/dp/0393315290/sowbug-20">Random Walk Down Wall Street</a> crowd has seen all this before. But the premise that stock-picking is a legitimate, repeatable skill also forms the foundation of the hedge fund and mutual fund industries. If you (or your pension plan) have any of your money in a managed mutual fund or hedge fund, then you believe the premise, too.</p>

<p>The technical challenges are less risky, but to me they're even more fascinating. The uptime and integrity demands are arguably higher than those of a real brokerage. A slow trade in a real brokerage might cost one customer a certain amount of money. In fact, depending on how the ticker goes, the mistake might even earn the customer more money. But every complaint about FSX's performance damages its status as a faithful brokerage simulation, and that in turn damages the value of its entire community. Building a top-tier brokerage website would be hard enough. Our goals are much higher than that.</p>

<p>eBay built a global marketplace out of Pez dispensers and Elmo dolls. They made it possible for you to find that one guy out there who wants to buy your dusty old deluxe chartreuse dinglehopper. He completes his dinglehopper collection, you get some cash and some extra space on your shelf, and the world's a better place. FSX will do the same thing for investments and investment managers. If you think you have management talent, we'll prove it for you. If you want hedge fund-level talent cheaper than the cheapest mutual fund, we'll find it for you.</p>

<p>If you'd like to see a preview, add the <a href="http://www.facebook.com/apps/application.php?id=2339204748">Fantasy Stock Exchange</a> application to your Facebook account. If you're a smart software engineer in Silicon Valley and want to join something big while it's still small, <script TYPE="text/javascript">document.write('<A href="mailto:' + 'mike' + '.tsao@' + 'gm' + 'ail.com' + '">email me</a>')</script>.</p>]]></description>
            <link>http://www.sowbug.org/mt/2008/04/goodbye-google-hello.html</link>
            <guid>http://www.sowbug.org/mt/2008/04/goodbye-google-hello.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">code</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">geek</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">work</category>
            
            
            <pubDate>Wed, 23 Apr 2008 15:00:00 -0800</pubDate>
        </item>
        
        <item>
            <title>Home PC Virtualized</title>
            <description><![CDATA[<p>One of my home PCs has crossed the Singularity. I had an old Windows PC from 2003 that I've kept around because it has lots of important stuff on it, including node-locked commercial software. This weekend I duplicated it into a VMWare image and successfully booted it up inside a newer workstation. I don't need the original physical PC anymore, so after taking out the hard drives I'm carting it off to Google's recycling station.</p>

<p>I wish I'd done this since I was a kid. I could have mirrored all my old Apple II data onto a few Macintosh disks and continued to run Drol and Star Blazer inside an emulator, and then when I lost the Mac faith back in 1997 I could have migrated to whatever Mac-on-Windows emulator must have existed back then. True, there's probably little practical value to reading my Magic Window-formatted book reports from seventh grade, but the geek value is enormous.</p>

<p>Mirroring the PC would probably have been easy with VMWare Converter, but I didn't take that path at first. I was cheaping out and going with free Microsoft Virtual PC 2007, which meant I had to create the drive image myself. Here are the steps I took:<br />
<ol><br />
	<li>Move all "live" data (stuff I could see myself accessing more than once a decade) onto a file server.</li><br />
	<li>Uninstall soon-to-be inapplicable software, such as video drivers and CD/DVD authoring applications.</li><br />
	<li>Defragment the hard drive.</li><br />
	<li>Boot into a live CD and run GParted to shrink the drive partition as much as possible, leaving just a bit of room so that Windows can still comfortably run.</li><br />
	<li>Copy the drive partition to a file on a second drive using a command roughly like this: <code>dd if=/dev/hda1 of=/mnt/other_drive/hda1.img bs=1M</code></li><br />
	<li>Also copy the MBR and other fluff: <code>dd if=/dev/hda of=/mnt/other_drive/hda_header.img count=63</code> (I determined the 63 value by using GParted to figue out where Partition 1 started)</li><br />
	<li>Boot back into Windows and assemble the two parts into a single .vhd file. In retrospect, it would have been much easier to calculate the point where hda1 ended and just copy from block 0 all the way to there, but I was learning as I went.</li><br />
	<li>Try to trick Virtual PC into accepting the new file as a hard drive. After no luck, do a bit of research on the web to find out the format of the last sector in a .vhd. Write a quick C program to generate it (reprinted at end).</li><br />
	<li>Tack on the final sector. Confirm that Virtual PC now lets me create a virtual machine using this as the drive.</li><br />
	<li>Boot the virtual PC. See that it hangs on mup.sys. After finding on the web that a mup.sys hang is a symptom of any of the top 1,000 possible things that could go wrong with your computer, give up on Virtual PC and try VMWare Workstation.</li><br />
	<li>Learn that my particular PC is actually hanging on sptd.sys. Delete that. Try again. Success.</li><br />
	<li>Now fire up VMWare Converter. Import the working .vhd into VMWare. Clean up the PC and shut it down.</li><br />
	<li>7zip the new VMWare machine into a .7z file (getting about 50% compression!). Drop the .7z file onto a file server for safekeeping.</li><br />
	<li>All done!</li><br />
</ol></p>

<p>Here's the code to generate the .vhd footer for a fixed-size drive (though if you read my instructions start to finish you'll just do what I wish I'd done and avoid Virtual PC):</p>

<pre>#include &lt;windows.h&gt;
#include &lt;objbase.h&gt;

<p>typedef struct  {<br />
    unsigned char cookie[8];<br />
    unsigned char features[4];<br />
    unsigned char file_format_version[4];<br />
    unsigned char data_offset[8];<br />
    unsigned char time_stamp[4];<br />
    unsigned char creator_application[4];<br />
    unsigned char creator_version[4];<br />
    unsigned char creator_host_os[4];<br />
    unsigned char original_size[8];<br />
    unsigned char current_size[8];<br />
    unsigned char disk_geometry[4];<br />
    unsigned char disk_type[4];<br />
    unsigned char checksum[4];<br />
    unsigned char unique_id[16];<br />
    unsigned char saved_state[1];<br />
    unsigned char reserved[427];<br />
} hard_disk_footer;</p>

<p>void write_int16(unsigned char *p, unsigned short val) {<br />
    *p++ = (unsigned char)(val>>8);<br />
    *p++ = (unsigned char)val;<br />
}</p>

<p>void write_int32(unsigned char *p, unsigned int val) {<br />
    *p++ = (unsigned char)(val>>24);<br />
    *p++ = (unsigned char)(val>>16);<br />
    *p++ = (unsigned char)(val>>8);<br />
    *p++ = (unsigned char)val;<br />
}</p>

<p>void write_int64(unsigned char *p, ULONGLONG val) {<br />
    *p++ = (unsigned char)(val>>56);<br />
    *p++ = (unsigned char)(val>>48);<br />
    *p++ = (unsigned char)(val>>40);<br />
    *p++ = (unsigned char)(val>>32);<br />
    *p++ = (unsigned char)(val>>24);<br />
    *p++ = (unsigned char)(val>>16);<br />
    *p++ = (unsigned char)(val>>8);<br />
    *p++ = (unsigned char)val;<br />
}</p>

<p>int _tmain(int argc, _TCHAR* argv[])<br />
{<br />
    hard_disk_footer hdf = { 0 };</p>

<p>    memcpy(hdf.cookie, "conectix", 8);<br />
    write_int32(hdf.features, 2);<br />
    write_int32(hdf.file_format_version, 0x00010000);<br />
    write_int32(&hdf.data_offset[4], 0xFFFFFFFF);<br />
    memcpy(hdf.creator_application, "vpc ", 4);</p>

<p>    unsigned int totalSectors = 62914560;  // 30GB<br />
    unsigned int sectorsPerTrack;<br />
    unsigned int heads;<br />
    unsigned int cylinderTimesHeads;<br />
    unsigned int cylinders;</p>

<p>    if (totalSectors > 65535 * 16 * 255) {<br />
        totalSectors = 65535 * 16 * 255;<br />
    }</p>

<p><br />
    if (totalSectors >= 65535 * 16 * 63) {<br />
        sectorsPerTrack = 255;<br />
        heads = 16;<br />
        cylinderTimesHeads = totalSectors / sectorsPerTrack;<br />
    } else {<br />
        sectorsPerTrack = 17;<br />
        cylinderTimesHeads = totalSectors / sectorsPerTrack;<br />
        heads = (cylinderTimesHeads + 1023) / 1024;<br />
        if (heads < 4) {<br />
            heads = 4;<br />
        }<br />
        if (cylinderTimesHeads >= (heads * 1024) || heads > 16) {<br />
            sectorsPerTrack = 31;<br />
            heads = 16;<br />
            cylinderTimesHeads = totalSectors / sectorsPerTrack; <br />
        }<br />
        if (cylinderTimesHeads >= (heads * 1024)) {<br />
            sectorsPerTrack = 63;<br />
            heads = 16;<br />
            cylinderTimesHeads = totalSectors / sectorsPerTrack;<br />
        }<br />
    }<br />
    cylinders = cylinderTimesHeads / heads;</p>

<p>    write_int16(hdf.disk_geometry, cylinders);<br />
    hdf.disk_geometry[2] = (unsigned char)heads;<br />
    hdf.disk_geometry[3] = (unsigned char)sectorsPerTrack;</p>

<p>    write_int32(hdf.disk_type, 2); // fixed</p>

<p>    ULONGLONG totalSize = UInt32x32To64(totalSectors, 512);<br />
    write_int64(hdf.current_size, totalSize);</p>

<p>    CoCreateGuid((GUID*)&hdf.unique_id);</p>

<p>    unsigned int checksum = 0;<br />
    write_int32(hdf.checksum, 0);<br />
    unsigned int counter;<br />
    <br />
    unsigned char *p = (unsigned char *)&hdf;<br />
    for (counter = 0 ; counter < sizeof(hard_disk_footer); counter++) {<br />
        checksum += p[counter];<br />
    }<br />
    write_int32(hdf.checksum, ~checksum);</p>

<p>    FILE *f = fopen("e:\\hdr.out", "wb");<br />
    fwrite(&hdf, 1, sizeof(hard_disk_footer), f);<br />
    return 0;<br />
}</pre></p>]]></description>
            <link>http://www.sowbug.org/mt/2008/04/home-pc-virtualized.html</link>
            <guid>http://www.sowbug.org/mt/2008/04/home-pc-virtualized.html</guid>
            
            
            <pubDate>Sun, 20 Apr 2008 16:48:28 -0800</pubDate>
        </item>
        
        <item>
            <title>Your options, your taxes, and you</title>
            <description><![CDATA[<p>If life were Hollywood, I'd be typecast as The Guy Who Understands AMT As It Applies To Your Company's Stock Options. I get asked certain questions often enough that it's time to write up my answers. But remember, I'm not a tax lawyer or accountant; I just play one in movies. So get real tax advice from a professional.</p>

<p>Two questions are popular. First: "I just joined a company and got some stock options. There's something in the agreement about early-exercising. I understand how options work, but I don't understand why anyone would exercise early. What's the deal?" Second: "Oh boy, we're going public in six months, and the lockup expires 6 months after that! Should I exercise my options now to get the long-term capital gain rate on my zillions in profits?"</p>

<p>There are two considerations when you exercise ISOs (Incentive Stock Options): capital gains, and alternative minimum tax.</p>

<p>If you sell an asset more than a year after you acquired it, you're federally taxed on the profit at 15%. Less than that and it's the same as your ordinary income tax rate, which is probably 28%. So if you exercise your options, that means you buy the underlying stock, and that starts the cap gains period running, and you might cut your federal tax on the profits in half. Note that there are some funny rules for ISOs that effectively change this period for early-exercised stock to two years; either way, it's beneficial from the cap gains perspective to exercise as early as possible.</p>

<p>However, AMT can really screw you over. AMT is like an alternate universe that's even weirder than the normally taxed universe. You're potentially taxed on imaginary income, for example. In our case, the imaginary income is the difference between so-called fair market value of your stock on the day you exercise, and if that amount is large, you have to pay AMT on it, even if your stock ends up worthless by the time you're actually able to sell it.</p>

<p>Here's an example.</p>

<ul>
	<li>On 1 Jan 2008 Joe gets 10,000 options of ABC Corp. at strike price of 5 cents.</li>
	<li>On 1 Jan 2010, ABC files for IPO for the coming month of June. The Board of Directors determines FMV of ABC is $75/share.</li>
	<li>On 2 Jan 2010, Joe is very excited about the upcoming IPO, so he exercises his options, writing a check for $500 (10,000 x 5 cents).</li>
	<li>On 1 Jun 2010, ABC goes public at $100. After an accounting scandal, the stock tanks. Joe ends up selling his shares for $1 each, or $10,000 total, the day the employee lockup expires. Joe's bummed out because he was briefly a millionaire, but still happy because he made a profit of $9,500.</li>
	<li>On 1 Apr 2011, Joe's accountant determines that Joe owes AMT. Joe "earned" imaginary income of $749,500 on 2 Jan 2010. The accountant asks Joe to write a check to the IRS for approximately $250,000.00 to pay his 2010 taxes. Joe says "wait a minute, why am I paying taxes of $250,000 on a profit of $9,500??" His accountant says "Because you suck."</li>
</ul>

<p>Joe should have either exercised on 1/1/2008, or never early-exercised at all. Early exercise avoids AMT and starts the cap gains holding period. Never early-exercising means you pay higher taxes on the gains, but you avoid AMT (and, of course, you don't put any money at risk by exercising).</p>

<p>Obviously, things change if you assume the share price will go down. But you wouldn't be working at that company if you believed that.</p>

<p>Final disclaimer: all of this is probably wrong or at least out of date. For example, I heard from a friend that for 2007 you're allowed to recover quite a bit more than usual of AMT paid in prior years, so the situation is possibly not as awful as it has been in the past. Again, hire a professional.</p>]]></description>
            <link>http://www.sowbug.org/mt/2008/04/your-options-your-taxes-and-yo.html</link>
            <guid>http://www.sowbug.org/mt/2008/04/your-options-your-taxes-and-yo.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">geek</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">misc</category>
            
            
            <pubDate>Wed, 16 Apr 2008 11:14:02 -0800</pubDate>
        </item>
        
        <item>
            <title>Salad Nutrition Facts</title>
            <description><![CDATA[<p>The salad I just bought at the grocery store says it contains three servings. Yet it includes only one plastic fork. How rude!</p>]]></description>
            <link>http://www.sowbug.org/mt/2008/04/salad-nutrition-facts.html</link>
            <guid>http://www.sowbug.org/mt/2008/04/salad-nutrition-facts.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">misc</category>
            
            
            <pubDate>Tue, 01 Apr 2008 12:17:35 -0800</pubDate>
        </item>
        
        <item>
            <title>Nokia A/V cable pinouts</title>
            <description><![CDATA[<p>The Nokia CA-75U's pinouts are identical to the Creative Zen Vision A/V cable's pinouts.</p>]]></description>
            <link>http://www.sowbug.org/mt/2008/03/nokia-av-cable-pinouts.html</link>
            <guid>http://www.sowbug.org/mt/2008/03/nokia-av-cable-pinouts.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">geek</category>
            
            
            <pubDate>Thu, 27 Mar 2008 20:15:48 -0800</pubDate>
        </item>
        
        <item>
            <title>Latest inductee to my personal Developer Tool Hall of Fame</title>
            <description><![CDATA[<p>With apologies to <a href="http://www.somebits.com/weblog/">Nelson</a>, <a href="http://www.weitz.de/regex-coach/">The Regex Coach</a> is good software. It's an interactive regular expression authoring tool for Windows. Rather than typing a given regex directly into your Java/Python/Perl/C++-with-PCRE-library code and building your entire program, you type the expression into the top window, type a sample string in the bottom window, and if it matches, the matching part is highlighted. Such a time saver.</p>

<p>My one feature request: menu items that copy the regex to the clipboard, but properly escaped to paste into less regex-aware languages like Java. E.g., <code>([A-Za-z]+)\\\.[0-9]?</code> would be copied for Java as <code>([A-Za-z]+)\\\\\\.[0-9]?</code> (at least, I think that's right). The version of the feature that copies into a Bash command line would emit something like <code>\\\\\\\\\\\\\\\\\\\\</code>.</p>]]></description>
            <link>http://www.sowbug.org/mt/2007/11/latest-inductee-to-my-personal.html</link>
            <guid>http://www.sowbug.org/mt/2007/11/latest-inductee-to-my-personal.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">code</category>
            
            
            <pubDate>Mon, 26 Nov 2007 10:19:07 -0800</pubDate>
        </item>
        
        <item>
            <title>Portrait of Mommy, by Thomas</title>
            <description><![CDATA[<span class="mt-enclosure mt-enclosure-image"><a href="http://www.sowbug.org/mt/Thomas%20draws%20Mom%20%28Small%29.jpg"><img alt="Thomas draws Mom (Small).jpg" src="http://www.sowbug.org/mt/Thomas draws Mom (Small)-thumb-320x240.jpg" width="320" height="240" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;"/></a></span>

<p>Thomas drew this picture of Mary the other day. He explained it to me: she has legs, eyes, a mouth, arms, and eyebrows. You have to squint a bit to see the resemblance, but I think overall it's pretty good. Incidentally, Mary generally looks like this when Thomas spills yogurt on the couch.</p>]]></description>
            <link>http://www.sowbug.org/mt/2007/11/portrait-of-mommy-by-thomas.html</link>
            <guid>http://www.sowbug.org/mt/2007/11/portrait-of-mommy-by-thomas.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">home</category>
            
            
            <pubDate>Fri, 23 Nov 2007 21:45:05 -0800</pubDate>
        </item>
        
        <item>
            <title>My CFI Jeff</title>
            <description><![CDATA[<p><a href="http://www.jeffz.org/">Jeff Zacharias</a> is my certificated flight instructor, or CFI. He's the guy who taught me how to fly. I found him after sending an email to a bunch of local CFIs describing my specific goals and needs. His reply was the first and the best among several. We scheduled a demo flight on November 26, 2006, out of San Carlos, and it went fine.</p>

<p>After the lesson I asked Jeff all the usual questions you're supposed to ask a prospective CFI, in particular what percentage of his students pass their checkride on the first try. His answer was more or less "not applicable," because he hadn't sent anyone yet to a checkride. Usually you expect an answer somewhere very close to 100%, so this was technically a disqualifying answer, but I had a good feeling about Jeff, so we settled on a weekly schedule from 6 a.m. to 9 a.m. Wednesday mornings at San Carlos.</p>

<p>Twice I did my best to kill Jeff. First, in March we were at Livermore Airport doing touch-and-go landings, and on the takeoff roll the plane began veering toward the left of the runway. I had been trying to avoid dragging the brakes during taxi and takeoff, so I'd overcorrected by leaving my feet on the floor unless I really meant to effect a control input. (As I write this eight months later it sounds ridiculous; you're constantly putting in at least some pedal input just about whenever the plane's in motion.) As I realized what was happening, I froze. I was afraid to lift my feet and put them back on the pedals. I recall a visceral fear that I'd flip the plane if I touched the pedals, much as you might if you quickly spun your car's steering wheel on the highway.</p>

<p>We were at nearly 50 knots and headed for the rough along the side of the runway. Today I know several different ways to handle this situation, but at the time as a junior student I'd have certainly nosed-over the plane at a deadly speed.</p>

<p>This was the first time during our instruction that Jeff had to take control from me. The recovery was straightforward: jam on the right rudder pedal, pull back to lighten the load on the wheels, and moments later we were in the air and safe.</p>

<p>We discussed what happened later that day in email. Jeff's attitude was these sorts of incidents are part of learning (specifically that p-factor is huge when you're already off the nosewheel and at full throttle), and that it was no big deal. I took comfort in his response, and didn't let it crush my self-confidence.</p>

<p>The second time I tried to kill Jeff was a few weeks later in April. We were at Hayward Executive, getting closer to my first solo flight, practicing all sorts of emergencies and unusual situations (broken flaps, broken trim, engine-out, short but very high approach). I was too high but the flaps were "broken" in an up position, so I had to execute a forward slip, which is a maneuver in which the pilot yaws the plane but rolls in the opposite direction in order to thwart the airplane's naturally clean aerodynamics and cause it to begin to descend quickly without gaining airspeed. For some reason that day I decided to pull slightly back on the yoke during the maneuver, forgetting that one usually needs to push the plane's nose down in order to keep it safely above stalling speed.</p>

<p>If that was too technical, here it is again in layman's terms: if a plane keeps moving forward fast enough, then the wings lift it and it stays airborne. If the plane slows down too much, it turns into the aerodynamic equivalent of a rock, which, as you may know, falls right out of the sky. You don't want to stall the airplane, and you especially don't want to stall it when you're doing a forward slip, because that leads to a condition called a spin that is generally fatal below 1,000 feet.</p>

<p>The moment Jeff realized what was happening, he reflexively shoved his hands at the yoke, thereby pointing the nose down and increasing our airspeed. He simultaneously issued a wryly phrased admonishment that it would be better if I didn't kill us both. I believe we got close to 52 knots, which is quite close to the stalling speed of a Cessna 172 in the flaps-up configuration (even though the airspeed indicator can be inaccurate in low-speed and slipped conditions), and I'm not sure I'd have corrected in time on my own.</p>

<p>Anyway, as you have no doubt deduced, I failed on both attempts, and we lived to fly again. But my respect for Jeff's restraint, patience, and perspective increased dramatically after these two incidents. I'd have vowed never to fly again with a spaz like me, but it rolled right off Jeff. I think this epitomizes what makes a good instructor good: a determined, unflappable willingness to sit quietly in the right seat and let your student make mistakes, while at the same time staying alert to prevent fatal mistakes.</p>

<p>I could go on, but this is the web, and your attention span is consequently short. So here are some bullet points:<br />
<ul><br />
	<li>Jeff videotaped my solo and edited it into a DVD. Amazingly cool and kind of him.</li><br />
	<li>Jeff was almost never late to a lesson, even though we started at 6 a.m. on weekdays. The one time he was late, I coincidentally forgot to set my own alarm and slept in, and we almost simultaneously called each other, apologizing and begging to reschedule to 7:00.</li><br />
	<li>During the three hours of my checkride that took place over nearly a month, Jeff went through heroics to ensure I was prepared to succeed. He showed up on his own time to make sure my checkride paperwork was correct. He offered to fly me IFR to get me to Watsonville, where my examiner was stranded. He juggled his work and personal schedule to fit in spur-of-the-moment lessons when I was feeling out of practice. It was gratifying to have another human being on Earth who cared at least as much as I did that my checkride went smoothly (which, other than scheduling, it did).</li><br />
	<li>Jeff always responded quickly and thoughtfully to my emails. I have no idea how many unbilled hours he spent composing his replies over the last year, but I'm sure the total is substantial.</li><br />
	<li>If Jeff has an ego, he never showed it to me. Like me, he's a software guy, and when you get two of those types talking about any technical subject, eventually they're going to get into some kind of disagreement that rises to the level of religion. Aviation has just as many styles, dialects, schools of thought, and gray areas as software development, but nothing between Jeff and me ever escalated -- though he did have to try pretty hard to disabuse me of some notions. I've been fairly described as abrasive and stubborn in the past, so I have to give Jeff credit.</li><br />
</ul></p>

<p>All this, and he's a genuinely nice guy, too. Oh, and that question I asked him last year about his percentage of students passing their test on the first try? His answer is now 100%. :) If you're looking for an instructor, give him a call.</p>]]></description>
            <link>http://www.sowbug.org/mt/2007/11/my-cfi-jeff.html</link>
            <guid>http://www.sowbug.org/mt/2007/11/my-cfi-jeff.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">fly</category>
            
            
            <pubDate>Fri, 23 Nov 2007 19:35:02 -0800</pubDate>
        </item>
        
        <item>
            <title>First Tsao Family Flight</title>
            <description><![CDATA[<p>Today I flew with my first passengers: my family! Mary, Emily, and Thomas willingly or unknowingly got in N54JA, a Cessna 172SP, and we attempted to fly from SQL (San Carlos Airport) to HAF (Half Moon Bay Airport).</p>

<p>I picked 54JA among the other available planes because it was near the Gazebo, which is a little raised platform at SQL with picnic benches. It's a great place to leave the kids during preflight. I did my normal preflight and then added booster seats into the back row of the airplane and plugged in everyone's headsets. We packed everyone in, and we were off!</p>

<p>I stayed in the pattern once in case anyone freaked out, and then we departed Runway 30 toward VPCRY. As we passed the mountain peaks, we began hitting a little turbulence. I self-announced on HAF's CTAF as we overflew the airport at 2,500, then we began a 180 over the ocean to do the official 1,000-feet-above-pattern-altitude overflight. At this point I noticed people were entering 30's pattern by coming in well north of the airport (versus overflying and then looping left onto the 45), so I turned left, followed their pattern, and began descending to TPA. The mountain turbulence was really starting to bug Mary, but I pressed on a couple miles behind a Cherokee.</p>

<p>As I turned onto base, I decided to call it off; it was just too gusty for an enjoyable landing. I could have easily made a safe landing, but I knew that even with my limited experience my idea of "safe" was well outside my passengers' idea of "safe <i>and</i> comfortable." So I self-announced that I was aborting the landing and departing the pattern on 30's base leg, and we climbed to 2,500 and headed back home to SQL.</p>

<p>The flight was 0.7 hours on the Hobbs with less than half an hour in the air. When the turbulence began the kids fell asleep (their usual defense mechanism). As they got out of the plane back at San Carlos they claimed to have had fun.</p>

<p>I'm glad to have gotten my first flight with passengers out of the way; part of me had imagined doing hundreds more hours of pattern work before taking any passengers, but once I finally got my license, my confidence level was high enough that I wanted to take the whole family right out of the gate. That said, it's a heck of a lot of work to fly to HAF with two toddlers for ice cream. Next time I'd like to go somewhere interesting or do something fun, so that the 30 minutes of preflight and 15 minutes of post-flight cleanup are worth it.</p>

<p><a href="http://marytsao.blogspot.com/">Mary</a> will probably be posting pictures soon.</p>]]></description>
            <link>http://www.sowbug.org/mt/2007/11/first-tsao-family-flight.html</link>
            <guid>http://www.sowbug.org/mt/2007/11/first-tsao-family-flight.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">fly</category>
            
            
            <pubDate>Fri, 23 Nov 2007 16:36:36 -0800</pubDate>
        </item>
        
        <item>
            <title>Got my ticket (Part 2)</title>
            <description><![CDATA[<p>These are the topics I hope to cover in the future:</p>

<ul>
	<li>My excellent CFI (certificated flight instructor), <a href="http://jeffz.org/">Jeff Zacharias</a></li>
	<li>Why I started flight training to begin with, and why most of those reasons turned out to be wrong</li>
	<li>The time I almost killed Jeff</li>
	<li>The other time I almost killed Jeff</li>
	<li>My theory why many students stop flight training midway through</li>
	<li>How to complete flight training on a budget (subtitled "Everything that I wish I'd done, in hindsight")</li>
	<li>Capsule reviews of various aviation products and services</li>
</ul>

<p>Some of these posts are already written, but I deferred publication until now. The reason I kept my flight training fairly quiet while it was in progress is because I've noticed that the topic of pilot training tends to dominate all conversation with friends and family, partly because it's genuinely interesting, but mostly because the experience is immersive. It's hard for someone in the midst of becoming a pilot to avoid turning all possible discussion toward the topic of aviation. Now that the most intense part is past, I hope I can start discussing it without becoming too much of a bore. :)</p>]]></description>
            <link>http://www.sowbug.org/mt/2007/11/got-my-ticket-part-2.html</link>
            <guid>http://www.sowbug.org/mt/2007/11/got-my-ticket-part-2.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">fly</category>
            
            
            <pubDate>Fri, 23 Nov 2007 08:31:02 -0800</pubDate>
        </item>
        
        <item>
            <title>Got my ticket</title>
            <description><![CDATA[<p>As of a few hours ago, I am officially a private pilot! Today I passed my FAA practical test, informally known as the "checkride." This means I'm now legal to fly passengers in airplanes, subject to about 700 exceptions, qualifications, and limitations.</p>

<p>You know that heavy lead vest the dentist puts on you when you get your head X-rayed? Imagine wearing about three of those for five months straight, and then one afternoon taking them off and suddenly being as light as you used to be. That's how I feel! Beginning in July of this year I've been "just a few weeks" away from my checkride, and I've put much of my life on hold as a result. Little did I know that weather would delay my cross-country flights for many weeks, that a dozen little things would conspire to delay my checkride prep again and again, and that my checkride itself would take six weeks to schedule and almost a month to complete. I'm excited to have my life back.</p>

<p>I'll write more later.</p>]]></description>
            <link>http://www.sowbug.org/mt/2007/11/got-my-ticket.html</link>
            <guid>http://www.sowbug.org/mt/2007/11/got-my-ticket.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">fly</category>
            
            
            <pubDate>Thu, 22 Nov 2007 17:32:00 -0800</pubDate>
        </item>
        
        <item>
            <title>HOWTO: upload old mail to Google Apps</title>
            <description><![CDATA[<p>The <a href="http://code.google.com/apis/apps/email_migration/developers_guide_protocol.html">documentation</a> showing how to upload mail to your Premiere (not Standard!) Google Apps account is good, but there are a few practical matters either implied or missing from it. Here's how to post an email from your Linux command line.</p>

<p>First, let's assume you have a user test@example.com with a password 1234567890. Get your auth token as follows:</p>

<pre>$ echo -n "Email=test@example.com&Passwd=1234567890&accountType=HOSTED&service=apps" \
| POST https://www.google.com/accounts/ClientLogin</pre>

<p><br />
This will either ask you for a CAPTCHA (resolve <a href="http://code.google.com/support/bin/answer.py?answer=55394&topic=11282">as described here</a> and then repeat), or tell you the credentials:</p>

<pre>SID=a-long-string-of-characters
LSID=another-long-string-of-characters
Auth=yet-another-long-string-of-characters</pre>

<p><br />
Now you should put a test RFC 822 message into a file called test_letter:</p>

<pre>From someone@somewhere.com  Sat Jul 15 19:00:40 2006
Return-Path: <someone@somewhere.com>
Received: from somewhere.com (localhost.localdomain [127.0.0.1])
        by somewhere.com (8.13.4/8.13.4) with ESMTP id k6G20eq4024585
        for <someone@somewhere.com>; Sat, 15 Jul 2006 19:00:40 -0700
Received: (from someone@localhost)
        by somewhere.com (8.13.4/8.13.4/Submit) id k6G20eBj024584
        for someone; Sat, 15 Jul 2006 19:00:40 -0700
Date: Sat, 15 Jul 2006 19:00:40 -0700
From: Someone <someone@somewhere.com>
Message-Id: <200607160200.k6G20eBj024584@somewhere.com>
To: someone@somewhere.com
Subject: hi

<p>hello</pre></p>

<p><br />
Then you need to XML-escape it. I used this sed script, called escape-xml.sed:</p>

<pre>s/\&amp;/\&amp;amp;/g
s/&lt;/\&amp;lt;/g
s/&gt;/\&amp;gt;/g</pre>

<p><br />
... and I performed the escaping with this command line:</p>

<pre>sed -f escape-xml.sed test_letter > escaped_test_letter</pre>

<p><br />
Now wrap the whole thing in a full Atom request:</p>

<pre>&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;feed xmlns="http://www.w3.org/2005/Atom"
    xmlns:batch="http://schemas.google.com/gdata/batch"
    xmlns:gd="http://schemas.google.com/g/2005"&gt;
&lt;atom:entry xmlns:atom='http://www.w3.org/2005/Atom'&gt;
  &lt;atom:category scheme='http://schemas.google.com/g/2005#kind'
    term='http://schemas.google.com/apps/2006#mailItem'/&gt;
  &lt;apps:rfc822Msg xmlns:apps='http://schemas.google.com/apps/2006'&gt;
From someone@somewhere.com  Sat Jul 15 19:00:40 2006
Return-Path: &amp;lt;someone@somewhere.com&amp;gt;
Received: from somewhere.com (localhost.localdomain [127.0.0.1])
        by somewhere.com (8.13.4/8.13.4) with ESMTP id k6G20eq4024585
        for &amp;lt;someone@somewhere.com&amp;gt;; Sat, 15 Jul 2006 19:00:40 -0700
Received: (from someone@localhost)
        by somewhere.com (8.13.4/8.13.4/Submit) id k6G20eBj024584
        for someone; Sat, 15 Jul 2006 19:00:40 -0700
Date: Sat, 15 Jul 2006 19:00:40 -0700
From: Someone &amp;lt;someone@somewhere.com&amp;gt;
Message-Id: &amp;lt;200607160200.k6G20eBj024584@somewhere.com&amp;gt;
To: someone@somewhere.com
Subject: hi

<p>hello</p>

<p>  &lt;/apps:rfc822Msg&gt;<br />
  &lt;apps:mailItemProperty xmlns:apps='http://schemas.google.com/apps/2006'<br />
   value='IS_STARRED'/&gt;<br />
  &lt;apps:mailItemProperty xmlns:apps='http://schemas.google.com/apps/2006' value='IS_UNREAD'/&gt;<br />
&lt;apps:label xmlns:apps='http://schemas.google.com/apps/2006' labelName='Event Invitations'/&gt;<br />
&lt;apps:label xmlns:apps='http://schemas.google.com/apps/2006' labelName='Friends'/&gt;<br />
&lt;/atom:entry&gt;<br />
&lt;/feed&gt;</pre></p>

<p><br />
and put it in a file called xml_test_letter. At this point you have your credentials, and a file that constitutes the body of a valid Atom request to insert the mail into the account associated with the credentials. The problem I ran into here is that the POST tool won't let you use a Content-Type header of the form foo/bar+baz, but the Google API appears to accept only the type application/atom+xml. I found the POST tool on my local system (it's just a Perl script) and fixed it:</p>

<pre>        die "$progname: Illegal Content-type format\n"
            unless $options{'c'} =~ m,^[\w\-]+/[\w<font color="#ff0000">+</font>\-]+(?:\s*;.*)?$,</pre>

<p><br />
(note the new plus sign added into the regex). Now you're ready to do the request:</p>

<pre>$ cat xml_test_letter | \
POST -H 'Authorization: GoogleLogin auth=yet-another-long-string-of-characters' \
-c 'application/atom+xml' \
https://apps-apis.google.com/a/feeds/migration/2.0/example.com/test/mail/batch</pre>

<p><br />
This should return a result indicating that the new mail is in test@example.com's account. Unfortunately, in my case it told me that because I have a standard account, I can't bulk-upload mail. But I'm confident that if I had the right kind of account, then this process would have worked.</p>]]></description>
            <link>http://www.sowbug.org/mt/2007/11/howto-upload-old-mail-to-googl.html</link>
            <guid>http://www.sowbug.org/mt/2007/11/howto-upload-old-mail-to-googl.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">geek</category>
            
            
            <pubDate>Fri, 16 Nov 2007 10:59:19 -0800</pubDate>
        </item>
        
        <item>
            <title>Getting close</title>
            <description><![CDATA[<pre>$ crontab -l
0 0 15 11 * chmod -R 555 /music/holiday
0 0 1 1 * chmod -R 0 /music/holiday</pre>]]></description>
            <link>http://www.sowbug.org/mt/2007/11/getting-close.html</link>
            <guid>http://www.sowbug.org/mt/2007/11/getting-close.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">geek</category>
            
            
            <pubDate>Tue, 13 Nov 2007 10:39:11 -0800</pubDate>
        </item>
        
        <item>
            <title>NaNoWriMo Extension for Firefox</title>
            <description><![CDATA[<p>If you've found your way here because of NaNoWriMo, then you're probably wondering why <a href="http://www.sowbug.org/nanowrimo_meter/">my Firefox extension</a> started on November 2 rather than November 1. I reprint here <a href="https://addons.mozilla.org/en-US/firefox/discussions/?AddOnID=1432">my response in the Mozilla discussion</a>:</p>

<p><code>Hey everyone, I'm the author of this extension. As pointed out in the discussion, the start date for 2007 was incorrect. It was miscalculated to be November 1, 2007 *as of the current time*, and because that was always not-later-than now on November 1, the extension thought that NaNoWriMo hadn't started yet. On November 2 and beyond, it works correctly. I realized this just as NaNoWriMo was starting and quickly submitted 0.4, which fixes the problem. However, the Mozilla extension reviewers appear to be far behind on their extension-reviewing queue, so they haven't approved 0.4 yet, and that's why it doesn't appear on the site. Meanwhile, I have put 0.4 on my personal website at (link). Note that you should generally not install random extensions you find out on the web; if you're uncomfortable doing this, just wait until the Mozilla folks approve 0.4, and you'll get prompted for an update. Sorry for the distraction. Get back to your novel!</code></p>

<p><b>Updated 11/9/2007: The official Mozilla site now has 0.4.</b></p>]]></description>
            <link>http://www.sowbug.org/mt/2007/11/nanowrimo-extension-for-firefo.html</link>
            <guid>http://www.sowbug.org/mt/2007/11/nanowrimo-extension-for-firefo.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">geek</category>
            
            
            <pubDate>Mon, 05 Nov 2007 09:54:45 -0800</pubDate>
        </item>
        
    </channel>
</rss>
