<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Ian Dennis Miller</title>
	<atom:link href="http://iandennismiller.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://iandennismiller.com/blog</link>
	<description>Essays and Whatnot</description>
	<lastBuildDate>Sun, 25 Jul 2010 02:46:41 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>handy utility: watchpaths</title>
		<link>http://iandennismiller.com/blog/2010/07/handy-utility-watchpaths/</link>
		<comments>http://iandennismiller.com/blog/2010/07/handy-utility-watchpaths/#comments</comments>
		<pubDate>Sun, 25 Jul 2010 02:44:42 +0000</pubDate>
		<dc:creator>idm</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[home brew]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[utility]]></category>

		<guid isPermaLink="false">http://iandennismiller.com/blog/2010/07/handy-utility-watchpaths/</guid>
		<description><![CDATA[Imagine you are working on a set of files on your computer, and each time you change one of those files, you want to run a program to process the files again. This comes up all over the place, whether it&#8217;s software development, statistics, image processing, or lots of other domains. Recently, I was editing [...]]]></description>
			<content:encoded><![CDATA[<p>Imagine you are working on a set of files on your computer, and each time you change one of those files, you want to run a program to process the files again. This comes up all over the place, whether it&#8217;s software development, statistics, image processing, or lots of other domains. Recently, I was editing some source code, and each time I changed a file, I wanted to run a series of tests to make sure everything still worked. I made this process automatic with the help of a really handy utility called watchpaths.</p>
<h4>Installing watchpaths</h4>
<p>First, download watchpaths and place it somewhere in your path. I use ~/bin, so try something like this:</p>
<p><code>cd ~/bin</code></p>
<p><code>wget http://watchpaths.googlecode.com/svn/trunk/bin/watchpaths</code></p>
<p><code>chmod 755 ~/bin/watchpaths</code></p>
<h4>Using watchpaths</h4>
<p>Let&#8217;s say I want to monitor a folder containing images, and each time a new image is added I want to sync the folder to a remote computer. Using watchpaths, that will look like:</p>
<p><code>watchpaths "rsync -a ~/my_pictures user@example.com:public_html" ~/my_pictures</code></p>
<p>To convert that command into English, it would sound like this:</p>
<p>&#8220;Watch the my_pictures folder for any changes (new files, deleted files, updated files, etc) and each time a change happens in that folder, synchronize the contents of that folder with my web server.&#8221;</p>
<h4>More Information</h4>
<p>The project page is <a href="http://code.google.com/p/watchpaths/">http://code.google.com/p/watchpaths/</a>, and if there is any interest, I am happy to incorporate feedback.</p>
]]></content:encoded>
			<wfw:commentRss>http://iandennismiller.com/blog/2010/07/handy-utility-watchpaths/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Disable sharing</title>
		<link>http://iandennismiller.com/blog/2010/06/disable-sharing/</link>
		<comments>http://iandennismiller.com/blog/2010/06/disable-sharing/#comments</comments>
		<pubDate>Mon, 14 Jun 2010 18:18:42 +0000</pubDate>
		<dc:creator>idm</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[observation]]></category>
		<category><![CDATA[entrepreneurship]]></category>
		<category><![CDATA[internet]]></category>
		<category><![CDATA[localshow]]></category>

		<guid isPermaLink="false">http://iandennismiller.com/blog/2010/06/disable-sharing/</guid>
		<description><![CDATA[Imagine you are a member of a successful mega-band with expensive music videos and everything. You started out small, worked your way up, and now you&#8217;ve sold millions of albums. The band&#8217;s music is owned and distributed by a big Label, and the Label has reluctantly put your music videos online. It is easy to [...]]]></description>
			<content:encoded><![CDATA[<p>Imagine you are a member of a successful mega-band with expensive music videos and everything. You started out small, worked your way up, and now you&#8217;ve sold millions of albums. The band&#8217;s music is owned and distributed by a big Label, and the Label has reluctantly put your music videos online. It is easy to show that Music Labels are wary of video sharing sites (such as youtube) because the Labels often choose to <b>disable sharing</b> when they are given the option. Makes sense, right?</p>
<p>Since you&#8217;re a band member in our hypothetical mega-band, what this means to you in practical terms is that bloggers cannot put your videos in their blogs, among other things. Naturally, the music label wants to disable sharing, because they want fans to be dependent on the label to get band updates. In Internet terms, this is a de facto walled garden of content, which in the music labels&#8217; ideal world would be something completely separate from the Internet.</p>
<p>Ideally, as a band member, you&#8217;ll get a cut of everything the Label sells, so there&#8217;s a lot to say for the walled garden concept. The big problem is this: by definition, <b>sharing is disabled between the Internet and the walled garden</b>. For as long as the Label was the best way to promote your music, there has never been any benefit to sharing content. Ever since broadcast radio music was used to promote albums, and even through the whole music video era, sharing has never played into the promotion scheme.</p>
<p><b>Maybe sharing should be a part of music promotion.</b></p>
<p>I&#8217;m not talking about ripping whole albums or bittorrent filesharing, per se, although there are some people would riff on this. They might go so far as to argue that if you give an artist some money as a result of downloading an entire album worth of mp3s, then that artist got some free promotion via filesharing. It&#8217;s happened before.</p>
<p>But I&#8217;m not even going to touch that. The situation I am talking about is when a music label on youtube clicks that one checkbox to &#8220;disable embedding.&#8221; In the picture below, these are some of the options youtube gives you.</p>
<p><img src="http://iandennismiller.com/blog/wp-content/uploads/2010/06/embedding.jpg" width="412" height="218" alt="embedding.jpg" /></p>
<p>It&#8217;s worth considering why someone would ever decide to disable sharing, but the inescapable observation is that many music labels have made this choice. A practical consequence is that they are missing out on potentially free promotion through the Internet. More on this point later.</p>
]]></content:encoded>
			<wfw:commentRss>http://iandennismiller.com/blog/2010/06/disable-sharing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Passwords, and the Apple Keychain</title>
		<link>http://iandennismiller.com/blog/2010/05/passwords-and-the-apple-keychain/</link>
		<comments>http://iandennismiller.com/blog/2010/05/passwords-and-the-apple-keychain/#comments</comments>
		<pubDate>Wed, 19 May 2010 15:47:18 +0000</pubDate>
		<dc:creator>idm</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[os x]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://iandennismiller.com/blog/2010/05/passwords-and-the-apple-keychain/</guid>
		<description><![CDATA[Some time around 2006, I started thinking about my online passwords in a new way. Until this point, I had used a collection of perhaps a dozen gibberish passwords, which I reused on various sites depending on the sensitivity of the site. For example, my bank account would use a nearly unique password, whereas a [...]]]></description>
			<content:encoded><![CDATA[<p>Some time around 2006, I started thinking about my online passwords in a new way. Until this point, I had used a collection of perhaps a dozen gibberish passwords, which I reused on various sites depending on the sensitivity of the site. For example, my bank account would use a nearly unique password, whereas a random forum would use a very commonly reused password.</p>
<p>This worked acceptably well, but I frequently had to ask myself: &#8220;which password did I use when I signed up for this service?&#8221; In response to having to guess my own passwords, I made two decisions: I would start writing my passwords down, and I would make them all unique and randomly generated.  Four years later, I am using a totally different system, and I&#8217;ll explain all of my reasoning.</p>
<p><span id="more-183"></span></p>
<p>To facilitate my random password approach, I started using 3&#215;5 index cards and a card filer. I added A-Z tabs, and I generally filed cards according to the domain name of the service (e.g. paypal.com is filed under P). I wrote a quick perl script to make 10 random passwords at a time, and I would pick one from the list and write it down on the index card. I really liked the concept of a purely non-digital password storage system, because it would be essentially unhackable without physical access. <i>Essentially unhackable</i> &#8211; more on this later.</p>
<p>There were several drawbacks to the index card system. For brevity, I&#8217;ll just list them:</p>
<ul>
<li>writing some characters by hand is ambiguous. I confused capital I, lowercase L, and numeral 1 all the time. Capital O and numeral 0 are also a trick.</li>
<li>it&#8217;s possible to copy the password incorrectly</li>
<li>it is extremely difficult to create a backup copy, so catastrophic loss is a possibility</li>
<li>if someone has physical access to the index cards, they have access to your accounts</li>
<li>it&#8217;s tedious to type in a random password every time you log in</li>
<li>it doesn&#8217;t scale well after about 400 accounts</li>
</ul>
<p>The scaling problems were the real killer. For example, did I file sandbox.paypal.com under P for paypal or S for sandbox? I don&#8217;t remember, so I need to perform a linear search through both letters.  Or, since a disproportionate number of words start with S, then it became a more tedious task to flip through all the S cards in order to find an S site, whereas a site that started with Y would be pretty quick to look up since there were fewer. Eventually, it got to the point that I knew it was too much of a chore to look up cards, and on that basis, I became too lazy to log in to my accounts! Total failure.</p>
<p><img src="http://iandennismiller.com/blog/wp-content/uploads/2010/05/Keychain-Icon.png" width="64" height="64" alt="Keychain Icon.png" style="float:left;" /> The solution for me is to use <a href="http://en.wikipedia.org/wiki/Apple_Keychain">Apple Keychain</a>. If you&#8217;re a <a href="http://en.wikipedia.org/wiki/Getting_things_done">GTD adherent</a>, then you&#8217;ll understand what I mean when I say this is my trusted system for account information. How did I reconcile a digital password storage with my original goal of keeping my passwords offline in order to make it unhackable? It was when I realized that both offline passwords and the keychain can be successfully attacked with a keystroke logger. If someone went to those lengths to get a password, then it wouldn&#8217;t matter how it was originally stored; the password could be intercepted regardless.</p>
<p>Why use Apple Keychain? Based on my list of drawbacks for the index cards, here&#8217;s a list of pro-Keychain points:</p>
<ul>
<li>built-in random password generator</li>
<li>keyword search</li>
<li>simple cut-and-paste workflow makes it very easy to enter passwords without typing</li>
<li>keychain itself is password protected</li>
<li>passwords are <a href="http://en.wikipedia.org/wiki/Triple_DES">Triple DES</a> encrypted (which should be acceptable until the year 2030)</li>
<li>simple to back up keychain file</li>
<li>slick integration with many applications, including Mail.app, subversion, and Safari/Chrome.</li>
</ul>
<p>I&#8217;m currently at about 900 accounts (yes &#8211; this is deserving of a separate post unto itself) and the system is working great. I think this scales to meet my requirements, and probably beyond. In practical terms, a password that used to take 30 second to retrieve is now instant.  I probably save 5 minutes per day by switching away from index cards, and I am avoiding untold frustrations.  In all, I recommend Apple Keychain highly.  &nbsp;&nbsp;</p>
<p></p>
]]></content:encoded>
			<wfw:commentRss>http://iandennismiller.com/blog/2010/05/passwords-and-the-apple-keychain/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>There&#8217;s a spider in the kitchen</title>
		<link>http://iandennismiller.com/blog/2010/05/theres-a-spider-in-the-kitchen/</link>
		<comments>http://iandennismiller.com/blog/2010/05/theres-a-spider-in-the-kitchen/#comments</comments>
		<pubDate>Tue, 18 May 2010 14:54:27 +0000</pubDate>
		<dc:creator>idm</dc:creator>
				<category><![CDATA[observation]]></category>
		<category><![CDATA[story]]></category>
		<category><![CDATA[living]]></category>
		<category><![CDATA[spider]]></category>

		<guid isPermaLink="false">http://iandennismiller.com/blog/2010/05/theres-a-spider-in-the-kitchen/</guid>
		<description><![CDATA[I noticed a spider in the corner of the kitchen, so I zoomed in for a closer look.

After some analysis, I decided it had to go, even though it was totally harmless. I was going to chase it into my specialty spider-catcher, consisting of a bowl and an old piece of cardstock.

They never see it [...]]]></description>
			<content:encoded><![CDATA[<p>I noticed a spider in the corner of the kitchen, so I zoomed in for a closer look.</p>
<p><img src="http://iandennismiller.com/blog/wp-content/uploads/2010/05/spider.jpg" width="400" height="184" alt="spider.jpg" /></p>
<p>After some analysis, I decided it had to go, even though it was totally harmless. I was going to chase it into my specialty spider-catcher, consisting of a bowl and an old piece of cardstock.</p>
<p><img src="http://iandennismiller.com/blog/wp-content/uploads/2010/05/spider-catcher.jpg" width="400" height="300" alt="spider catcher.JPG" /></p>
<p>They never see it coming.</p>
<p><span id="more-180"></span></p>
<p>First, the bowl comes descending from out of the sky and encloses the target bug. Usually, the bug stays where it is on the wall, but sometimes it runs madly into the bowl itself, which makes the next step even easier. The cardstock slides between the bowl and the wall, and it&#8217;s done. The bug is totally enclosed, and I can just bring it outside.</p>
<p>The key feature is that I don&#8217;t kill the bug in the process, which has a number of practical consequences. First, there&#8217;s no carcass and guts splattered all over the place, which is always an unpleasant thing to clean up. Next, my capturing method has a nearly 100% success rate, whereas it&#8217;s sometimes really hard to squash a bug because they happen to be really good at avoiding being squashed. This means it&#8217;s way less frustrating to simply catch the bug, and it&#8217;s less work in the long run too.</p>
<p>The spider was near the ceiling, so I used a broom-type thing to chase it towards the wall where I could reach it. &#8230;but once the spider was near the door, I thought: I can just send it out the door and skip the catcher. Then, the spider got <b>onto</b> my broom-thing, and I thought: I can just walk outside with the spider clinging to the broom, and then shake it off.</p>
<p><img src="http://iandennismiller.com/blog/wp-content/uploads/2010/05/spider-home.jpg" width="300" height="400" alt="spider home.JPG" /></p>
<p>Here&#8217;s where it went all wrong: I think the spider went <b>into</b> the broom-thing, and I can&#8217;t really tell one way or the other. It&#8217;s some wacky proprietary cleaning device with non-standard, non-maintainable parts. I think the spider lives inside the device now, and I&#8217;m not sure what the next step is.</p>
]]></content:encoded>
			<wfw:commentRss>http://iandennismiller.com/blog/2010/05/theres-a-spider-in-the-kitchen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Reverse Auction</title>
		<link>http://iandennismiller.com/blog/2010/05/the-reverse-auction/</link>
		<comments>http://iandennismiller.com/blog/2010/05/the-reverse-auction/#comments</comments>
		<pubDate>Mon, 17 May 2010 14:29:37 +0000</pubDate>
		<dc:creator>idm</dc:creator>
				<category><![CDATA[cool]]></category>
		<category><![CDATA[story]]></category>
		<category><![CDATA[economy]]></category>

		<guid isPermaLink="false">http://iandennismiller.com/blog/2010/05/the-reverse-auction/</guid>
		<description><![CDATA[Yesterday was eventful: we acquired two chairs that can be pushed together into a sort of bench, and we got rid of a table that didn&#8217;t quite fit. If you&#8217;ve ever read Bruce Sterling&#8217;s Shaping Things, or if you&#8217;ve considered the entire lifecycle of the products you purchase, then like me, you may have grown [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday was eventful: we acquired two chairs that can be pushed together into a sort of bench, and we got rid of a table that didn&#8217;t quite fit. If you&#8217;ve ever read Bruce Sterling&#8217;s <a href="http://mitpress.mit.edu/catalog/item/default.asp?tid=10603&amp;ttype=2">Shaping Things</a>, or if you&#8217;ve considered the entire lifecycle of the products you purchase, then like me, you may have grown to dislike disposing of things &#8211; because it&#8217;s a bit of a chore. I asked myself: what is the easiest way to get rid of this table? The obvious answer &#8211; throwing it away &#8211; is full of problems, not the least of which is that there is a city schedule for throwing away big items. Then the answer struck me: the <a href="http://en.wikipedia.org/wiki/Reverse_auction">Reverse Auction</a>.</p>
<p><span id="more-172"></span></p>
<p>The concept was this: I&#8217;d disassemble the table, move it to the side of a major Toronto street, and angle the table towards oncoming traffic. The price would start at $40, and every 5 minutes, I would lower the price by $5. Now, this type of auction works best with a captive audience, and ideally the person who wins the action will think like this: I must buy the item at this price, because if I wait too long and the price is lowered, then my competitor might be willing to purchase it at the lower price. In the end, a reverse auction has the same consequence as a forward auction: you find the single individual who is willing to pay the most.</p>
<p>I wanted to use a reverse auction because I assumed it would guarantee that we would eventually find a price point that someone would buy at, and I could establish a schedule that would rapidly get us to the right price. In other words, it was a time issue; I felt it wasn&#8217;t worth my time to ask top dollar for the table, so I&#8217;d make price vary by time and accept the tradeoff.</p>
<p>I think a fair price for the table was around $30, so I started it at $40. I printed some price tags on letter-sized paper, using a 400pt font size to make the numbers legible from the street. Armed only with these price sheets and some tape, we set a timer and waited for someone to snap.</p>
<p>My wife was quite the salesperson, and effectively maintained a constant stream of sales points about the table. First, 5 minutes passed and the lowered price still didn&#8217;t make anyone budge. Another 5 minutes, and we lowered it to $30. I caved to pressure and waited 10 minutes before lowering the price to $25, and another 5 minutes later we moved it to $20. This started to get a reaction from people; bikers were commenting, people walking on the sidewalk discussing quietly among themselves&#8230;</p>
<p>And finally, someone bought it, in large part due to my wife&#8217;s sales pitch. I think they saw that we were lowering the price pretty rapidly, and realized that eventually it would be so cheap that someone else was definitely going to buy it. Here&#8217;s the insight, then: the reverse auction worked even without the captive audience, but the price-lowering mechanism is most effective if someone actually witnesses the changing price. They need to see the price drop in order to consider that someone else might compete with them at the lowered price point.</p>
<p>Instead of leaving the table for garbage collectors, earning $0 in the process and adhering to an arbitrary schedule, we sold a $30 table for $20, and we did it in less than half an hour. It was a lot of fun, and it was even educational. I think we ended up executing something related to the Reverse Auction, but which was different enough that it behaved unexpectedly. Nevertheless, it worked, and we bought delicious curry and pad thai with our spoils.</p>
]]></content:encoded>
			<wfw:commentRss>http://iandennismiller.com/blog/2010/05/the-reverse-auction/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The fastest way to download a youtube video</title>
		<link>http://iandennismiller.com/blog/2010/04/the-fastest-way-to-download-a-youtube-video/</link>
		<comments>http://iandennismiller.com/blog/2010/04/the-fastest-way-to-download-a-youtube-video/#comments</comments>
		<pubDate>Sat, 03 Apr 2010 04:05:26 +0000</pubDate>
		<dc:creator>idm</dc:creator>
				<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://iandennismiller.com/blog/2010/04/the-fastest-way-to-download-a-youtube-video/</guid>
		<description><![CDATA[A recent comment on BoingBoing asked if there was a way to download a video from youtube, such that it could be reposted elsewhere. One solution, suggested by Cory Doctorow, is to use pwnyoutube.com, but there exists a general method that works on all flash video (not just youtube), and happens to be faster than [...]]]></description>
			<content:encoded><![CDATA[<p>A <a href="http://www.boingboing.net/2010/04/02/digital-economy-bill.html#comments">recent comment on BoingBoing</a> asked if there was a way to download a video from youtube, such that it could be reposted elsewhere. One solution, suggested by Cory Doctorow, is to use pwnyoutube.com, but there exists a general method that works on <b>all flash video</b> (not just youtube), and happens to be faster than using pwnyoutube.com. Behold! For I shall demonstrate a painless use of <b><a href="http://en.wikipedia.org/wiki/Lsof">lsof</a></b>, the under-appreciated and extra-useful command line tool.</p>
<p><span id="more-145"></span></p>
<p>In the Internet video world, there are two kinds of creatures: streaming video (which is appropriate for live events) and buffered video (which is for recorded things, like youtube). &#8220;Buffering&#8221; means it&#8217;s actually downloading a file in the background, and if it can download a little faster than you can watch it, then everything plays smoothly. If the video pauses suddenly and restarts after a few seconds, that&#8217;s because it&#8217;s rebuffering.</p>
<p><img src="http://iandennismiller.com/blog/wp-content/uploads/2010/04/buffering.png.jpg" width="480" height="284" alt="buffering.png.jpg" /></p>
<p>Have you ever noticed how the youtube progress bar slowly fills in with a pinkish color? It&#8217;s at about 20% in the picture, above. That indicates how much of the file has been buffered, and when it reaches the end, it means the file is fully downloaded. In other words, you don&#8217;t need some special plugin or service to &#8220;download a video from youtube.&#8221; Your browser does it automatically! Even better, this happens for any website that uses flash and .flv files to deliver buffered video.</p>
<p>The key is to use lsof (which is a mnemonic for &#8220;list open files&#8221;). I&#8217;m demonstrating this on OS X, but the process is basically the same with *nixes and Cygwin. If you don&#8217;t have lsof installed by default, just use your package manager to install it. (e.g. apt-get install lsof).</p>
<p>So, the magical incantation is:</p>
<p><code>lsof |grep lash</code></p>
<p>I grep for &#8220;lash&#8221; instead of &#8220;Flash&#8221; since you never know if the F will be capitalized or not, and this is the laziest way to get the desired results. Here is an example of the output:</p>
<p><img src="http://iandennismiller.com/blog/wp-content/uploads/2010/04/lsof.png.jpg" width="750" height="176" alt="lsof.png.jpg" /></p>
<p>Notice the files FlashTmp0 and FlashTmp1? That&#8217;s where the video files are saved, so long as you keep your browser window and video tabs open. There&#8217;s no need to &#8220;download&#8221; a video that you just watched. Instead, simply copy the file straight to your Desktop:</p>
<p><code>cp /private/var/folders/.../TemporaryItems/FlashTmp1 ~/Desktop/rickroll.flv</code></p>
<p>Now, you can open the local file with VLC:</p>
<p><img src="http://iandennismiller.com/blog/wp-content/uploads/2010/04/vlc.png.jpg" width="480" height="394" alt="vlc.png.jpg" /></p>
<p>You might need to try multiple FlashTmp files before you find the one containing the video you want (i.e. is it FlashTmp0 or FlashTmp1) but there usually aren&#8217;t many. <b>On many non-youtube sites, this is the only way you&#8217;re going to get access to a buffered flash video</b> (since there aren&#8217;t handy pwnyoutube.com clones for everything).</p>
<p>Once you have copied the file to your desktop, why not convert it to mp4 and edit it in iMovie?</p>
<p><code>ffmpeg -i rickroll.flv rickroll.mp4</code></p>
<p><img src="http://iandennismiller.com/blog/wp-content/uploads/2010/04/ffmpeg.png.jpg" width="480" height="240" alt="ffmpeg.png.jpg" /></p>
<p>And now you know how to access videos you just watched, as well as convert them into a format you can edit.</p>
]]></content:encoded>
			<wfw:commentRss>http://iandennismiller.com/blog/2010/04/the-fastest-way-to-download-a-youtube-video/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Posting this before it&#8217;s cool: Hipster jokes</title>
		<link>http://iandennismiller.com/blog/2009/12/posting-this-before-its-cool-hipster-jokes/</link>
		<comments>http://iandennismiller.com/blog/2009/12/posting-this-before-its-cool-hipster-jokes/#comments</comments>
		<pubDate>Thu, 03 Dec 2009 18:40:13 +0000</pubDate>
		<dc:creator>idm</dc:creator>
				<category><![CDATA[found]]></category>
		<category><![CDATA[funny]]></category>

		<guid isPermaLink="false">http://iandennismiller.com/blog/?p=127</guid>
		<description><![CDATA[Q: How many hipsters does it take to screw in a lightbulb?
A: You don&#8217;t know?!
posted by shakespeherian at 7:38 AM on November 25 [2 favorites]
Q: How many hipsters does it take to screw in a lightbulb?
A: Lightbulbs? We tape fireflies to our PBR hats with duct tape and can see just as well as YOU.
posted [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>Q: How many hipsters does it take to screw in a lightbulb?</p>
<p>A: You don&#8217;t know?!</p>
<p>posted by shakespeherian at 7:38 AM on November 25 [2 favorites]</p>
<p>Q: How many hipsters does it take to screw in a lightbulb?</p>
<p>A: Lightbulbs? We tape fireflies to our PBR hats with duct tape and can see just as well as YOU.</p>
<p>posted by pyramid termite at 8:29 AM on November 25</p>
<p>Q: How many hipsters does it take to screw in a lightbulb?</p>
<p>A: All of them. One to screw in the lightbulb, while the rest brag to each other about how they were changing lightbulbs before it was cool.</p>
<p>posted by The Great Big Mulp at 10:17 AM on November 25 [3 favorites]</p>
<p>Q: How many hipsters does it take to screw in a lightbulb?</p>
<p>They don&#8217;t need lights. Macbooks have backlit keyboards.</p>
<p>posted by Pogo_Fuzzybutt at 10:44 AM on November 25 [6 favorites]</p>
<p>Q: How many hipsters does it take to screw in a lightbulb?</p>
<p>Oh, are those the new light bulbs? I liked the old ones better.</p>
<p>posted by Parasite Unseen at 1:32 PM on November 25 [3 favorites]</p>
<p>Q: How many hipsters does it take to screw in a lightbulb?</p>
<p>I have the answer on vinyl.</p>
<p>posted by ichthuz at 5:06 PM on November 25 [4 favorites]</p>
<p>Q: How many hipsters does it take to screw in a lightbulb?</p>
<p>A: an obscure number you&#8217;ve never heard of.</p>
<p>posted by meadowlark lime at 7:22 PM on November 25 [8 favorites]</p></blockquote>
<p>via <a href="http://www.metafilter.com/86940/The-Crazy-World-of-andernestborgnineasdominic#2837246">The Crazy World of andernestborgnineasdominic! | MetaFilter</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://iandennismiller.com/blog/2009/12/posting-this-before-its-cool-hipster-jokes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How is it 2009 and we still can&#8217;t write dates in a coherent way?</title>
		<link>http://iandennismiller.com/blog/2009/10/how-is-it-2009-and-we-still-cant-write-dates-in-a-coherent-way/</link>
		<comments>http://iandennismiller.com/blog/2009/10/how-is-it-2009-and-we-still-cant-write-dates-in-a-coherent-way/#comments</comments>
		<pubDate>Sat, 17 Oct 2009 20:25:18 +0000</pubDate>
		<dc:creator>idm</dc:creator>
				<category><![CDATA[observation]]></category>
		<category><![CDATA[rant]]></category>
		<category><![CDATA[calendar]]></category>
		<category><![CDATA[canada]]></category>
		<category><![CDATA[date]]></category>
		<category><![CDATA[gregorian calendar]]></category>

		<guid isPermaLink="false">http://iandennismiller.com/blog/?p=114</guid>
		<description><![CDATA[I have lived in North America my whole life. Most of that time was spent in the United States, but recently I moved to Canada. I really like it in Canada, but I have one gripe to share. Actually, it&#8217;s not so much a problem with Canada as it is a problem with humans, or [...]]]></description>
			<content:encoded><![CDATA[<p>I have lived in North America my whole life. Most of that time was spent in the United States, but recently I moved to Canada. I really like it in Canada, but I have one gripe to share. Actually, it&#8217;s not so much a problem with Canada as it is a problem with humans, or perhaps it relates to the curious relationships between our planet, its moon, and its sun.</p>
<p><span id="more-114"></span>
<p>I have a problem with the way &#8220;we&#8221; write dates, but in particular, I have a problem with the totally inconsistent way people are writing dates in Canada.</p>
<h4>Date templates</h4>
<p>The US has about the dumbest system imaginable. The template goes &#8220;Month / Day / Year&#8221; as in &#8220;1/20/2009&#8243; is &#8220;January 20, 2009.&#8221; Nevertheless, it&#8217;s a template that basically everyone follows. I don&#8217;t know who made up the template or why, but the number form appears to map directly onto the written form.</p>
<p>Personally, I write my dates &#8220;Year / Month / Day.&#8221; First off, it alphabetizes correctly. 2009/01/01 will be listed before 2009/03/17, for example. While it&#8217;s true that the US system also has this property, my system nicely maps onto file/directory hierarchies. A folder called &#8220;2009&#8243; has 12 sub-folders called 01, 02, 03, etc. Each sub-folder has a folder for days. If you want to write the path to a specific day (say, the 3rd day of the 4th month of the 2009th year) you write 2009/04/03. You might notice that this is the format used by this very blog, which is because it&#8217;s awesome. The date is the filesystem path.</p>
<p>I was delighted to discover that some people in Canada use the same date format that I do, but as time went on, it became clear that this wasn&#8217;t a strict rule. To wit, I present two examples, ranging from terrifying to horrifying:</p>
<h4>The grocery receipt</h4>
<p>
First, we have a fine specimen from Metro, which is one of the local supermarket chains. You will notice I have circled two dates in red. Let me be clear about this: these are not separate receipts. They are actually printed on the same, continuous sheet of paper.</p>
<p><img class="aligncenter size-full wp-image-115" title="receipt 1" src="http://iandennismiller.com/blog/wp-content/uploads/2009/10/receipt-1.jpg" alt="receipt 1" width="532" height="600" /></p>
<p>Your eyes do not deceive you: they are different date formats. Which is which? I parse the first one as Month / Day / Year, and I parse the second as Year / Month / Day. In other words, the first is like the US system, and the second is like my ideal system, except they opted to not prefix the century (i.e. 2009 instead of 09). Naturally, I have a problem with leaving the century off (since you don&#8217;t know if they&#8217;re talking about 1909 or 2009) but that&#8217;s not the worst problem with the receipt.</p>
<h4>The parking pass</h4>
<p>In the second example, some enterprising individual completely sidestepped the date format problem, and instead presented us with this gem:</p>
<p><img class="aligncenter size-full wp-image-116" title="receipt 2" src="http://iandennismiller.com/blog/wp-content/uploads/2009/10/receipt-2.jpg" alt="receipt 2" width="587" height="412" /></p>
<p>Again, your eyes are giving you correct information. Of course, it&#8217;s not clear at all which year it is, which will have profound consequences for that pesky &#8220;February 29&#8243; situation.</p>
<h4>Converting days into months</h4>
<p>
Also, it&#8217;s just not that simple to convert days into a date. I present the following two solutions:</p>
<p><a href="http://www.google.ca/search?q=217+days+in+months">http://www.google.ca/search?q=217+days+in+months</a></p>
<p><img class="aligncenter size-full wp-image-117" title="google date" src="http://iandennismiller.com/blog/wp-content/uploads/2009/10/google-date.jpg" alt="google date" width="408" height="201" />That&#8217;s pretty good, insofar as I can tell that we&#8217;re talking about July, but it could be better.</p>
<p><a href="http://www.wolframalpha.com/input/?i=what+is+the+217+day+of+the+year">http://www.wolframalpha.com/input/?i=what+is+the+217+day+of+the+year</a></p>
<p><img class="aligncenter size-full wp-image-118" title="wolfram alpha date" src="http://iandennismiller.com/blog/wp-content/uploads/2009/10/wolfram-alpha-date.jpg" alt="wolfram alpha date" width="590" height="705" />Okay &#8211; that&#8217;s close enough. Assuming it&#8217;s not a leap year, this parking pass refers to July 4th. Right? Well, maybe, which brings us to the next problem: the Gregorian Calendar.</p>
<h4>The Gregorian Calendar</h4>
<p>
Do you know what the product of 28 and 13 is? It&#8217;s 364, as in it&#8217;s just short of the amount of time the Earth takes to go around the sun once. You tack on 1.25 days, and you&#8217;re back with the normal year length we all know and love. That&#8217;s 13 months, not 12. How did something so elegant get so screwed up?</p>
<p>The first culprit is Pope Gregory XIII, who changed the calendar around because the date of Easter was shifting later and later in the year. You see, Easter is calculated according to an esoteric astral scheme including the sun and the moon (how pagan!) The next culprit is Julius Caesar, who can be blamed for the Julian calendar that so strangely distributed the days among the 12 months. Pope Gregory was simply revising the Julian system.</p>
<p>Back to the parking ticket. Knowing that 217 days is 7 months and 4 days doesn&#8217;t actually tell us the date, because it&#8217;s not clear how many days are in a month. I got the shivers simply writing that sentence&#8230; We can&#8217;t say, with any certainty, how many days are in a month; the best we can say is &#8220;it depends.&#8221; Terrible!</p>
<h4>Conclusion</h4>
<p>
We&#8217;re screwed. The calendar is broken, so it&#8217;s not much wonder that we can&#8217;t write dates. We don&#8217;t have a definition of &#8220;month&#8221; so any attempt to convert days into months is hopeless. We can&#8217;t write dates according to any template because &#8230; well, I suspect no one gave it much thought.</p>
<p>Without further ado, I present the only date template that is guaranteed to be useful:</p>
<p>YYYYY/MM/DD</p>
<p>This makes &#8220;October 17, 2009&#8243; look like this: 02009/10/17. Yes, there&#8217;s an extra &#8220;0&#8243; in the year, but this is because we don&#8217;t want to screw up the year 10,000. I am in the habit of leaving the extra 0 off, but just be aware that it&#8217;s good practice. Every day is two digits; if the day is less than 10, you need the leading 0. That means you need to write January 1st as &#8220;2009/01/01&#8243;. This makes alphabetization work properly. The same goes for months &#8211; you need the leading 0.</p>
<p>There&#8217;s simply no other way, people!</p>
]]></content:encoded>
			<wfw:commentRss>http://iandennismiller.com/blog/2009/10/how-is-it-2009-and-we-still-cant-write-dates-in-a-coherent-way/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>curl: HTTP/1.1 100 CONTINUE and multipart/form-data POST</title>
		<link>http://iandennismiller.com/blog/2009/09/curl-http1-1-100-continue-and-multipartform-data-post/</link>
		<comments>http://iandennismiller.com/blog/2009/09/curl-http1-1-100-continue-and-multipartform-data-post/#comments</comments>
		<pubDate>Fri, 18 Sep 2009 15:10:35 +0000</pubDate>
		<dc:creator>idm</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[100-continue]]></category>
		<category><![CDATA[blank form]]></category>
		<category><![CDATA[curl]]></category>
		<category><![CDATA[expect]]></category>
		<category><![CDATA[expect 100]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[http 1.0]]></category>
		<category><![CDATA[http 1.1]]></category>
		<category><![CDATA[http/1.0]]></category>
		<category><![CDATA[http/1/1]]></category>
		<category><![CDATA[missing payload]]></category>
		<category><![CDATA[multipart]]></category>
		<category><![CDATA[multipart form]]></category>
		<category><![CDATA[multipart post]]></category>
		<category><![CDATA[multipart/form-data]]></category>
		<category><![CDATA[payload]]></category>
		<category><![CDATA[post]]></category>
		<category><![CDATA[tcpdump]]></category>

		<guid isPermaLink="false">http://iandennismiller.com/blog/?p=91</guid>
		<description><![CDATA[I&#8217;m working on a REST interface at the moment, and there&#8217;s nothing I need more than a quick utility to test out various functions.  Curl fills this role perfectly, but I have run into a strange problem that interferes with multipart/form-data form POSTing.  Let me explain some of the evidence I&#8217;ve collected, as well as [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m working on a REST interface at the moment, and there&#8217;s nothing I need more than a quick utility to test out various functions.  <a title="Curl" href="http://curl.haxx.se/">Curl</a> fills this role perfectly, but I have run into a strange problem that interferes with <a title="multipart form data" href="http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2">multipart/form-data</a> form POSTing.  Let me explain some of the evidence I&#8217;ve collected, as well as tell you a workaround I learned from an IRC conversation.  In the end, this comes down to the HTTP 1.1 100 CONTINUE response code, which plays a critical role in HTTP 1.1 POST.</p>
<p><span id="more-91"></span></p>
<h4>Configuration</h4>
<p>For starters, I&#8217;m testing this out with OS X 10.5:</p>
<pre>$ uname -a
Darwin osx.example.com 9.7.0 Darwin Kernel Version 9.7.0: Tue Mar 31 22:52:17
PDT 2009; root:xnu-1228.12.14~1/RELEASE_I386 i386 i386</pre>
<p>For all of the output in this post, I used this version of curl:</p>
<pre>$ curl --version
curl 7.19.6 (i386-apple-darwin9.7.0) libcurl/7.19.6 zlib/1.2.3
Protocols: tftp ftp telnet dict http file
Features: Largefile libz</pre>
<p>Next up, we have the web server I was testing with:</p>
<pre>$ curl -I osx.example.com:8000
HTTP/1.0 302 FOUND
Date: Fri, 18 Sep 2009 13:57:22 GMT
Server: WSGIServer/0.1 Python/2.6.2</pre>
<p>I&#8217;ve been using wireshark and tcpdump to watch the traffic.  Here&#8217;s an example invocation of tcpdump that you can work with to replicate the issue:</p>
<pre>sudo tcpdump -X -s 1500 -i lo0 tcp port 8000</pre>
<p>Obviously, you might run a testing webserver on port 80, and you might send your traffic over lo, eth0, or en0.  If you&#8217;re reading this post, you probably know what&#8217;s what, and how to modify the command accordingly.</p>
<h4>Issuing a simple multipart/form-data POST</h4>
<p>It starts when I try to issue a multipart form POST:</p>
<pre>curl -F name=somevalue http://osx.example.com:8000</pre>
<p>This means &#8220;set the field called &#8216;name&#8217; to &#8217;somevalue&#8217; and instead of url encoding it, post it as a multipart MIME message.&#8221;  Your browser does this any time you upload a file to a website.  In my case, my REST API lets me upload PDF files, so curl needs to use multipart instead of url encoding for this purpose.</p>
<p>Curl only generates one TCP packet based on this command (even though it should generate multiple) and this is what that one packet looks like:</p>
<pre>10:07:00.971856 IP osx.57777 &gt; osx.8000: P 1:<strong>260</strong>(259) ack 1 win 65535
&lt;nop,nop,timestamp 1076257225 1076257225&gt;
 0x0000:  4500 0137 03b9 4000 4006 0000 7f00 0001  E..7..@.@.......
 0x0010:  7f00 0001 e1b1 1f40 3f35 c1d8 0bb4 4ba7  .......@?5....K.
 0x0020:  8018 ffff ff2b 0000 0101 080a 4026 61c9  .....+......@&amp;a.
 0x0030:  4026 61c9 504f 5354 202f 2048 5454 502f  @&amp;a.<strong>POST./.HTTP/</strong>
 0x0040:  312e 310d 0a55 7365 722d 4167 656e 743a  <strong>1.1</strong>..User-Agent:
 0x0050:  2063 7572 6c2f 372e 3139 2e36 2028 6933  .curl/7.19.6.(i3
 0x0060:  3836 2d61 7070 6c65 2d64 6172 7769 6e39  86-apple-darwin9
 0x0070:  2e37 2e30 2920 6c69 6263 7572 6c2f 372e  .7.0).libcurl/7.
 0x0080:  3139 2e36 207a 6c69 622f 312e 322e 330d  19.6.zlib/1.2.3.
 0x0090:  0a48 6f73 743a 2031 3237 2e30 2e30 2e31  .Host:.127.0.0.1
 0x00a0:  3a38 3030 300d 0a41 6363 6570 743a 202a  :8000..Accept:.*
 0x00b0:  2f2a 0d0a 436f 6e74 656e 742d 4c65 6e67  /*..<strong>Content-Leng</strong>
 0x00c0:  7468 3a20 3134 380d 0a45 7870 6563 743a  <strong>th:.148</strong>..<strong>Expect:</strong>
 0x00d0:  2031 3030 2d63 6f6e 7469 6e75 650d 0a43  <strong>.100-continue</strong>..<strong>C</strong>
 0x00e0:  6f6e 7465 6e74 2d54 7970 653a 206d 756c  <strong>ontent-Type:.mul</strong>
 0x00f0:  7469 7061 7274 2f66 6f72 6d2d 6461 7461  <strong>tipart/form-data</strong>
 0x0100:  3b20 626f 756e 6461 7279 3d2d 2d2d 2d2d  ;.boundary=-----
 0x0110:  2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d  ----------------
 0x0120:  2d2d 2d2d 2d2d 2d37 3937 3037 6465 6438  -------79707ded8
 0x0130:  6339 640d 0a0d 0a                        c9d....</pre>
<p>We can tell a few things from this.  First, the packet is 260 bytes long, the HTTP Content-Length header indicates a forthcoming payload of 148 bytes, and curl has set the HTTP Expect header to:</p>
<pre>Expect: 100-continue</pre>
<p>Notice that it gets all the way up to the MIME boundary, which is fine.  The server responds with an ACK of the 260 bytes received, then sends back an HTTP reply:</p>
<pre>10:07:00.971880 IP osx.8000 &gt; osx.57777: . <strong>ack 260</strong> win 65535 &lt;nop,nop,
timestamp 1076257225 1076257225&gt;
 0x0000:  4500 0034 cda2 4000 4006 0000 7f00 0001  E..4..@.@.......
 0x0010:  7f00 0001 1f40 e1b1 0bb4 4ba7 3f35 c2db  .....@....K.?5..
 0x0020:  8010 ffff fe28 0000 0101 080a 4026 61c9  .....(......@&amp;a.
 0x0030:  4026 61c9                                @&amp;a.
10:07:00.973365 IP osx.8000 &gt; osx.57777: P 1:21(20) ack 260 win 65535
&lt;nop,nop,timestamp 1076257225 1076257225&gt;
 0x0000:  4500 0048 1bbf 4000 4006 0000 7f00 0001  E..H..@.@.......
 0x0010:  7f00 0001 1f40 e1b1 0bb4 4ba7 3f35 c2db  .....@....K.?5..
 0x0020:  8018 ffff fe3c 0000 0101 080a 4026 61c9  .....&lt;......@&amp;a.
 0x0030:  4026 61c9 4854 5450 2f31 2e30 2033 3032  @&amp;a.<strong>HTTP/1.0.302</strong>
 0x0040:  2046 4f55 4e44 0d0a                      .<strong>FOUND</strong>..</pre>
<p>Ah!  The server didn&#8217;t respond with HTTP/1.1 100 CONTINUE.  Curl will wait until it receives a 100 CONTINUE before it sends its 148 byte payload.  If your server never sends that response, curl will never send the payload.  This can be a problem if your server or your application doesn&#8217;t know about this HTTP 1.1 behavior.</p>
<p>Here is the same communication, as seen from curl&#8217;s perspective with the -v flag (for verbose output):</p>
<pre>$ curl -v -F name=somevalue http://127.0.0.1:8000
* About to connect() to 127.0.0.1 port 8000 (#0)
*   Trying 127.0.0.1... connected
* Connected to 127.0.0.1 (127.0.0.1) port 8000 (#0)
&gt; POST / HTTP/1.1
&gt; User-Agent: curl/7.19.6 (i386-apple-darwin9.7.0) libcurl/7.19.6 zlib/1.2.3
&gt; Host: 127.0.0.1:8000
&gt; Accept: */*
&gt; Content-Length: 148
&gt; Expect: 100-continue
&gt; Content-Type: multipart/form-data; boundary=----------------------------d70cdce71857
&gt;
* HTTP 1.0, assume close after body
&lt; HTTP/1.0 302 FOUND
&lt; Date: Fri, 18 Sep 2009 15:03:20 GMT
&lt; Server: WSGIServer/0.1 Python/2.6.2
&lt; Vary: Cookie
&lt; Content-Type: text/html; charset=utf-8
&lt; Location: http://127.0.0.1:8000/crm/form/login?next=/
&lt;
* Closing connection #0</pre>
<h4>A brief note about HTTP 1.1</h4>
<p>So, the fact that the server responds with a 302 FOUND instead of a 100 CONTINUE is really a feature of HTTP 1.1 because it is at this point that the conversation stops.  The 302 response will redirect the client to another resource on the server, so why not wait until you actually hit the resource that will receive your POST before you POST your payload?  If you&#8217;re POSTing a file to a URL redirect, then you will end up uploading your file at least twice, and that&#8217;s a waste of precious upstream bandwidth.</p>
<p>The HTTP/1.1 100 CONTINUE can potentially save you bandwidth, but read the coda at the end of this post for a cautionary tale.</p>
<h4>Issuing a multipart/form-data POST without Expect</h4>
<p>Let&#8217;s try this again without the Expect header:</p>
<pre>curl -H "Expect:" -F name=somevalue http://osx.example.com:8000</pre>
<p>The command above is identical to the previous one with the exception of the -H flag.  By setting &#8220;Expect:&#8221; to have no value after the colon, curl will interpret this as deleting the Expect header.  Sure enough, when we look at the TCP packet, the Expect header is gone:</p>
<pre>10:11:59.308674 IP osx.57803 &gt; osx.8000: P 1:238(237) ack 1 win 65535
&lt;nop,nop,timestamp 1076260192 1076260192&gt;
 0x0000:  4500 0121 c4b5 4000 4006 0000 7f00 0001  E..!..@.@.......
 0x0010:  7f00 0001 e1cb 1f40 5bb2 5099 2f1c 8bad  .......@[.P./...
 0x0020:  8018 ffff ff15 0000 0101 080a 4026 6d60  ............@&amp;m`
 0x0030:  4026 6d60 504f 5354 202f 2048 5454 502f  @&amp;m`POST./.HTTP/
 0x0040:  312e 310d 0a55 7365 722d 4167 656e 743a  1.1..User-Agent:
 0x0050:  2063 7572 6c2f 372e 3139 2e36 2028 6933  .curl/7.19.6.(i3
 0x0060:  3836 2d61 7070 6c65 2d64 6172 7769 6e39  86-apple-darwin9
 0x0070:  2e37 2e30 2920 6c69 6263 7572 6c2f 372e  .7.0).libcurl/7.
 0x0080:  3139 2e36 207a 6c69 622f 312e 322e 330d  19.6.zlib/1.2.3.
 0x0090:  0a48 6f73 743a 2031 3237 2e30 2e30 2e31  .Host:.127.0.0.1
 0x00a0:  3a38 3030 300d 0a41 6363 6570 743a 202a  :8000..Accept:.*
 0x00b0:  2f2a 0d0a 436f 6e74 656e 742d 4c65 6e67  /*..Content-Leng
 0x00c0:  7468 3a20 3134 380d 0a43 6f6e 7465 6e74  th:.148..Content
 0x00d0:  2d54 7970 653a 206d 756c 7469 7061 7274  -Type:.multipart
 0x00e0:  2f66 6f72 6d2d 6461 7461 3b20 626f 756e  /form-data;.boun
 0x00f0:  6461 7279 3d2d 2d2d 2d2d 2d2d 2d2d 2d2d  dary=-----------
 0x0100:  2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d  ----------------
 0x0110:  2d65 3932 3861 6430 3332 3262 340d 0a0d  -e928ad0322b4...
 0x0120:  0a</pre>
<p>The packet is now 238 bytes long, which is exactly right.  &#8220;Expect: 100-continue&#8221; is 20 bytes long, plus 2 bytes for \r\n (0d0a in hex), which accounts for the packet being 22 bytes shorter than the previous 260 byte packet.   As before, the content length is 148 bytes.  As before, the packet goes all the way up to the MIME boundary.</p>
<p>As before, the server sends back a TCP ACK of the 238 bytes received, but here&#8217;s the difference.  Critically, without the Expect header, curl sends the entire payload before the server responds:</p>
<pre>10:11:59.308693 IP osx.8000 &gt; osx.57803: . ack 238 win 65535 &lt;nop,nop,
timestamp 1076260192 1076260192&gt;
 0x0000:  4500 0034 05cf 4000 4006 0000 7f00 0001  E..4..@.@.......
 0x0010:  7f00 0001 1f40 e1cb 2f1c 8bad 5bb2 5186  .....@../...[.Q.
 0x0020:  8010 ffff fe28 0000 0101 080a 4026 6d60  .....(......@&amp;m`
 0x0030:  4026 6d60                                @&amp;m`
10:11:59.308751 IP osx.57803 &gt; osx.8000 P 238:<strong>386</strong>(<strong>148</strong>) ack 1 win 65535
&lt;nop,nop,timestamp 1076260192 1076260192&gt;
 0x0000:  4500 00c8 45bc 4000 4006 0000 7f00 0001  E...E.@.@.......
 0x0010:  7f00 0001 e1cb 1f40 5bb2 5186 2f1c 8bad  .......@[.Q./...
 0x0020:  8018 ffff febc 0000 0101 080a 4026 6d60  ............@&amp;m`
 0x0030:  4026 6d60 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d  @&amp;m`------------
 0x0040:  2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d  ----------------
 0x0050:  2d2d 6539 3238 6164 3033 3232 6234 0d0a  --e928ad0322b4..
 0x0060:  436f 6e74 656e 742d 4469 7370 6f73 6974  Content-Disposit
 0x0070:  696f 6e3a 2066 6f72 6d2d 6461 7461 3b20  ion:.form-data;.
 0x0080:  6e61 6d65 3d22 6e61 6d65 220d 0a0d 0a73  name=<strong>"name"</strong>....<strong>s</strong>
 0x0090:  6f6d 6576 616c 7565 0d0a 2d2d 2d2d 2d2d  <strong>omevalue</strong>..------
 0x00a0:  2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d  ----------------
 0x00b0:  2d2d 2d2d 2d2d 2d2d 6539 3238 6164 3033  --------e928ad03
 0x00c0:  3232 6234 2d2d 0d0a                      22b4--..</pre>
<p>Whoah!  Did you notice the &#8220;name&#8221; &#8230; somevalue above?  That&#8217;s our payload, and it&#8217;s finally being transmitted.  This all happens before the server respond with an HTTP status code.  When sending the response, the TCP header is now an ACK to the total size of the POST-related packets (238 and 148, which is a total size of 386 bytes).</p>
<pre>10:11:59.308768 IP osx.8000 &gt; osx.57803: . ack <strong>386</strong> win 65535 &lt;nop,nop,
timestamp 1076260192 1076260192&gt;
 0x0000:  4500 0034 d082 4000 4006 0000 7f00 0001  E..4..@.@.......
 0x0010:  7f00 0001 1f40 e1cb 2f1c 8bad 5bb2 521a  .....@../...[.R.
 0x0020:  8010 ffff fe28 0000 0101 080a 4026 6d60  .....(......@&amp;m`
 0x0030:  4026 6d60                                @&amp;m`
10:11:59.316155 IP osx.8000 &gt; osx.57803: P 1:21(20) ack 386 win 65535
&lt;nop,nop,timestamp 1076260192 1076260192&gt;
 0x0000:  4500 0048 e1c5 4000 4006 0000 7f00 0001  E..H..@.@.......
 0x0010:  7f00 0001 1f40 e1cb 2f1c 8bad 5bb2 521a  .....@../...[.R.
 0x0020:  8018 ffff fe3c 0000 0101 080a 4026 6d60  .....&lt;......@&amp;m`
 0x0030:  4026 6d60 4854 5450 2f31 2e30 2033 3032  @&amp;m`HTTP/1.0.302
 0x0040:  2046 4f55 4e44 0d0a                      .FOUND..</pre>
<p>So removing the Expect header allowed curl to send an HTTP 1.1 POST, with its payload, before the server generated HTTP 1.0 302 FOUND.  The fact that the server responded with 302 FOUND means the entire POST data was ignored on the server side, but the client DID send it!  In other words, we just wasted some bandwidth, and we are going to need to POST the data at least one more time.  When curl was expecting an HTTP 1.1 100 CONTINUE instead, it never sends the rest of the payload, and <strong>curl never complains, not even with -v</strong>.</p>
<h4>Issuing a multipart/form-data POST using HTTP 1.0</h4>
<p>I&#8217;ll spare you the complete packet dump, but suffice to say that when curl is invoked with the HTTP 1.0 flag (-0, as in &#8220;dash zero&#8221;), it works just like when the Expect header is absent.  In other words, the following example also sends the payload before waiting for the server to respond.</p>
<pre>curl -0 -F name=somevalue http://osx.example.com:8000</pre>
<p>This results in:</p>
<pre>10:33:25.942611 IP osx.57900 &gt; osx.8000 P 1:238(237) ack 1 win 65535
&lt;nop,nop,timestamp 1076272988 1076272988&gt;
 0x0000:  4500 0121 f225 4000 4006 0000 7f00 0001  E..!.%@.@.......
 0x0010:  7f00 0001 e22c 1f40 0fcb 74fc 46cf 148b  .....,.@..t.F...
 0x0020:  8018 ffff ff15 0000 0101 080a 4026 9f5c  ............@&amp;.\
 0x0030:  4026 9f5c 504f 5354 202f 2048 5454 502f  @&amp;.\<strong>POST./.HTTP/</strong>
 0x0040:  312e 300d 0a55 7365 722d 4167 656e 743a  <strong>1.0</strong>..</pre>
<p>After a little conversation with the server, the payload is transmitted before the HTTP response, just like in the previous example.</p>
<h4>Conclusion</h4>
<p>What is the takeaway message from all of this?  If you&#8217;re using curl to test your REST interface, then make sure you are aware of the behavior HTTP 1.1 100 CONTINUE.  You might notice it because your server receives a blank POST payload.  Your HTML forms will appear to have not been filled in, even though you specified one or more -F arguments on the curl command line.</p>
<p>The solution for the versions of curl I&#8217;ve tested is to either remove the Expect header, or to tell curl to use HTTP 1.0 (since curl will default to 1.1 otherwise).  Once again, here are those examples:</p>
<pre>curl -H "Expect:" -F name=somevalue http://osx.example.com:8000
curl -0 -F name=somevalue http://osx.example.com:8000</pre>
<p>This forces curl to POST the payload without waiting for the 100 CONTINUE response, and it is suitable for servers that don&#8217;t know how to provide a 100 CONTINUE.  I hope this helps someone out there to avoid the trouble I had debugging my REST interface.</p>
<h4>Coda: fix your server!</h4>
<p>The &#8220;right&#8221; way to handle this situation is to make sure your server will send a 100 CONTINUE.  curl is smart enough, but your application might not be.</p>
<p>In a specific instance, my <a href="http://www.djangoproject.com/">Django</a>/<a href="http://bitbucket.org/jespern/django-piston/wiki/Home">Django-Piston</a>/<a href="http://code.google.com/p/modwsgi/">mod_wsgi</a> application having trouble with the 100 CONTINUE when the client sets an Expect: 100-continue header. It turns out this was a problem with mod_wsgi 2.5 and the solution is to update to 3.0 (it&#8217;s RC4 as of this post). Until I realized this was the deeper issue, I was able to get around the problem by preemptively POSTing the entire payload.  This worked, but as I said before, it frequently resulted in duplicate uploads (like in 302 and 401 situations).</p>
<p>Before I started preemptively POSTing the whole payload, my application appeared to be receiving blank POST data, so it was responding with a 400 BAD REQUEST.   In truth, the POST was blank, so it technically was a bad request.  This is not curl&#8217;s fault, though &#8211; it was just being extremely polite, waiting for a proper handshake before sending the payload.</p>
<p>Just watch out, because curl might be <strong>too polite</strong> &#8211; it didn&#8217;t even tell me that my server was refusing the 100 CONTINUE handshake.  This masked a much deeper problem with mod_wsgi, which took several days to sort out.</p>
]]></content:encoded>
			<wfw:commentRss>http://iandennismiller.com/blog/2009/09/curl-http1-1-100-continue-and-multipartform-data-post/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>The Free Beer Speech House: discussing the meaning of the word &#8220;free&#8221;</title>
		<link>http://iandennismiller.com/blog/2009/08/free-speech-beer-house-discussing-the-meaning-of-the-word-free/</link>
		<comments>http://iandennismiller.com/blog/2009/08/free-speech-beer-house-discussing-the-meaning-of-the-word-free/#comments</comments>
		<pubDate>Tue, 04 Aug 2009 19:15:36 +0000</pubDate>
		<dc:creator>idm</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[beer]]></category>
		<category><![CDATA[original]]></category>
		<category><![CDATA[speech]]></category>
		<category><![CDATA[apa]]></category>
		<category><![CDATA[arrogant bastard]]></category>
		<category><![CDATA[free beer]]></category>
		<category><![CDATA[free house]]></category>
		<category><![CDATA[free speech]]></category>
		<category><![CDATA[gnupg]]></category>
		<category><![CDATA[gpl]]></category>
		<category><![CDATA[ipa]]></category>
		<category><![CDATA[jupiter]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[optimator]]></category>
		<category><![CDATA[oss]]></category>
		<category><![CDATA[pgp]]></category>
		<category><![CDATA[pub]]></category>
		<category><![CDATA[stone brewing company]]></category>
		<category><![CDATA[triple rock]]></category>

		<guid isPermaLink="false">http://iandennismiller.com/blog/?p=67</guid>
		<description><![CDATA[Freedom, glorious freedom.
Once upon a time, I took a class based on  a single question: &#8220;what is freedom?&#8221;  We meandered through US history, identifying several distinct stages in the evolution of the definition of &#8220;freedom.&#8221;  I was horrified to learn, during a discussion, that so many of my classmates wanted what I will call &#8220;freedom [...]]]></description>
			<content:encoded><![CDATA[<p>Freedom, glorious freedom.</p>
<p>Once upon a time, I took a class based on  a single question: &#8220;what is freedom?&#8221;  We meandered through US history, identifying several distinct stages in the evolution of the definition of &#8220;freedom.&#8221;  I was horrified to learn, during a discussion, that so many of my classmates wanted what I will call &#8220;freedom from information.&#8221; Ah yes &#8211; Professor Sandage had a way of bringing the ugliest truths to the surface, for all to witness.</p>
<p>On the one hand, I can understand this desire for freedom from information: telemarketing, advertising, spam, the scrolling headlines at the bottom of a newscast&#8230;  well, any unsolicited attempt at selling things you don&#8217;t care about.  On the other hand, I think we need <strong>more</strong> information instead of less, and we need effective tools to filter and manage that information so we only see what we care about.</p>
<p>The term &#8220;freedom&#8221; is muddied by historical contexts, but also through the process of etymological erosion.  With that said, I want to take a moment to discuss the expression, &#8220;free as in speech, not beer.&#8221;</p>
<p><span id="more-67"></span></p>
<h4>Free as in speech, not beer</h4>
<p>&#8220;<a href="http://www.gnu.org/philosophy/free-sw.html">Free as in speech, not beer</a>&#8221; is an expression that comes up in open source discussions all the time.  It&#8217;s a little hard to unpack, unless you really dig into the dual meaning of the word &#8220;free.&#8221;  Thanks to Wikipedia, we&#8217;re part of the way there: the word &#8220;free&#8221; is used to mean two things: <a href="http://en.wikipedia.org/wiki/Gratis_versus_Libre">Gratis versus Libre</a>.  We call both of these terms &#8220;free&#8221; nowadays, but once upon a time, there were different words because they are totally different concepts.  Gratis means &#8220;without charge&#8221; whereas Libre is more like &#8220;liberty&#8221; or &#8220;freedom.&#8221;</p>
<p>So what is free speech?  Of course, that&#8217;s the freedom to say what you want (so long as you accept the consequences for what you&#8217;ve said).  And free beer?  Well, that would mean beer that is provided at no cost.  I think the key is this: although you are free to say what you want, you could well end up in court for it (e.g. slander) and your expression won&#8217;t come free of charge.  On the flipside, you can provide beer free of charge, but not to someone who is 15 years old, so you may not freely provide beer to anyone you wish.</p>
<p>In other words, speech embodies Libre (but not necessarily Gratis) perfectly.  Likewise, beer embodies Gratis very well, at the same time that beer is so closely regulated by many governments that it is hardly &#8220;libre.&#8221;  Nevertheless, everybody likes a good party with some beer pro gratis.</p>
<h4>The Free House, and the Public House</h4>
<p>Speaking of free beer, the <a href="http://en.wikipedia.org/wiki/Free_house_%28pub%29">Free House</a> is definitely not a place to find such a zero-cost beverage.  For starters, the term Free House is mostly British, and always beer-related.  It refers to a Public House (which you may know as a &#8220;pub&#8221;) that will sell any kind of beer they can get people to buy.  Contrast this with a Tied House, which sells beer manufactured by a single brewer, and you find that the Free House will have several brands on tap.  Here, the term &#8220;Free&#8221; is more like Libre, and is used in the context of the &#8220;free market.&#8221;  &#8230;and we all know that the free market isn&#8217;t composed of things that are zero-cost.</p>
<p>When I was living in Berkeley, California there were two particularly good &#8220;Tied House&#8221; pubs that brewed and sold only their own brands of beer: <a href="http://www.jupiterbeer.com/jupiter/">Jupiter</a> and <a href="http://www.triplerock.com/">Triple Rock</a>.  I should also mention <a href="http://www.pyramidbrew.com/alehouses/berkeley">Pyramid</a>, which had a pretty cool restaurant with their own beverages on tap.  This kind of pub is fun because they&#8217;ll often have a sampler option to let you taste a small glass of everything they brew.  It&#8217;s a great way to experience the full spectrum of beers, but a word of advice: start with the lightest stuff and progress towards darker.  The one exception to this rule is for hoppy beverages (e.g. <a href="http://en.wikipedia.org/wiki/India_Pale_Ale">IPA</a> or <a href="http://en.wikipedia.org/wiki/American_Pale_Ale">APA</a>), which might be light but which may have a pronounced bitter taste.  You might want to close it off with an APA, even after drinking the stouts.</p>
<h4>Open Source Software</h4>
<p>There&#8217;s nothing that goes quite so well with open source software as a tasty hoppy beverage.  I like pairing <a href="http://en.wikipedia.org/wiki/Stone_Brewing_Company">Stone Brewing Company&#8217;s</a> <a href="http://www.arrogantbastard.com/">Arrogant Bastard</a> with <a href="http://www.gnupg.org/">GnuPG</a>, the open source implementation of <a href="http://en.wikipedia.org/wiki/Phil_Zimmermann">Phil Zimmerman</a>&#8217;s PGP (<a href="http://en.wikipedia.org/wiki/Pretty_Good_Privacy">pretty good privacy</a>) software.  Another favorite of mine is the <a href="http://en.wikipedia.org/wiki/Spaten-Franziskaner-Br%C3%A4u">Spaten</a> Optimator paired with <a href="http://wordpress.org/">Wordpress</a>.  More recently, I&#8217;ve taken a liking to <a href="http://www.unibroue.com/index_eng.html">Unibroue</a>, the French Canadian brewer, who offers such brews as <a href="http://www.unibroue.com/graphs_our_beers/trois_pistoles.html">Tres Pistoles</a>, which is an excellent complement to <a href="http://www.python.org/">Python</a>.  This last combination is probably the most dangerous of the group, because you might end up with excellent code, and you might end up with <a href="http://en.wikipedia.org/wiki/Monty_python">British comedy</a>.</p>
<div id="attachment_71" class="wp-caption aligncenter" style="width: 310px"><img class="size-full wp-image-71" title="300px-Flyingcircus_2" src="http://iandennismiller.com/blog/wp-content/uploads/2009/08/300px-Flyingcircus_2.jpg" alt="http://en.wikipedia.org/wiki/Monty_Python" width="300" height="225" /><p class="wp-caption-text">http://en.wikipedia.org/wiki/Monty_Python</p></div>
<p>In the end of the day, free speech and free beer have a lot to do with open source software.  You see, licenses such as the <a href="http://en.wikipedia.org/wiki/Gpl">GNU General Public License</a> actually permit developers to charge for their software, while simultaneously requiring all GPL software to be published with its source code.  In this sense, the &#8220;free beer&#8221; part means the software isn&#8217;t necessarily without cost, and the &#8220;free speech&#8221; part means you are required to publish the source code.  In other words, the Libre aspect of the GPL has an important restriction: you are <strong>not</strong> free to <strong>not</strong> publish the source code, which in turn provides the most fundamental tenet of open source software: <strong>you are free to read and distribute the source code</strong>.</p>
<p>I want to hedge my previous statement: the GPL is a famous topic of debate, so there&#8217;s plenty of room to criticize anyone who says anything &#8211; at all &#8211; about the GPL or about open source software, either according to the letter of the license, or according to the spirit of the movement.</p>
<p>Let me sum it up like this: &#8220;free&#8221; means many things to many people throughout many time-periods, but for some reason, it almost always comes down to a matter of speech and beer.</p>
]]></content:encoded>
			<wfw:commentRss>http://iandennismiller.com/blog/2009/08/free-speech-beer-house-discussing-the-meaning-of-the-word-free/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
