<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
	<title>Richard Crowley’s blog</title>
	
	<link href="http://rcrowley.org/" rel="alternate" />
	<id>http://rcrowley.org/feed</id>
	<updated>2009-06-27T17:18:55-07:00</updated>
	<author><name>Richard Crowley</name></author>
<link rel="self" href="http://feeds.feedburner.com/rcrowley" type="application/atom+xml" /><entry><title>BashReduce</title><link href="http://feedproxy.google.com/~r/rcrowley/~3/hntzvX-svF0/bashreduce" rel="alternate" /><id>http://rcrowley.org/2009/06/27/bashreduce</id><published>2009-06-27T17:18:55-07:00</published><updated>2009-06-27T17:18:55-07:00</updated><author><name>Richard Crowley</name></author><content type="html">&lt;p&gt;I might be crazy but I&amp;#8217;m loving Last.fm&amp;#8217;s BashReduce tool
&lt;a id="f-27-1-src" href="#f-27-1" class="footnote"&gt;[1]&lt;/a&gt;.&amp;nbsp; So much
so that I&amp;#8217;ve taken time at work to make some improvements so we
can use it for some internal data analysis (unrelated to the public DNS
Stats I spoke about at Velocity
&lt;a id="f-27-2-src" href="#f-27-2" class="footnote"&gt;[2]&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;Changes&lt;/h2&gt;

&lt;p&gt;I had to change the argument structure a bit from Erik Frey&amp;#8217;s
original version to accommodate some of the bigger changes I made:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;-h&lt;/code&gt; is now how you specify a list of hosts.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;-?&lt;/code&gt; is now how you get the detailed help message.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; is now how you specify the map program.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;-M&lt;/code&gt; allows you to specify the merge program.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; now accepts a file or a directory.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; does some DFS-like things I&amp;#8217;ll discuss
	in more detail later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I think specifying your own merge step can be pretty useful, especially
in cases where you want to create a re-reduce step on the end.  A user
still has to be careful to do as little work as possible in the merge
step since it is serializing the output of map and reduce.&lt;/p&gt;

&lt;p&gt;The new &lt;code&gt;-f&lt;/code&gt; option causes &lt;code&gt;br&lt;/code&gt; to distribute
filenames instead of lines of data over the network (via
&lt;code&gt;nc&lt;/code&gt;).&amp;nbsp; The implication here is that each node has a
mirror of the directory specified with &lt;code&gt;-i&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Because &lt;code&gt;br&lt;/code&gt; can now act on a directory instead of a single
file, it&amp;#8217;s possible that you as a user would want to keep some or
all of this data gzipped.&amp;nbsp; &lt;code&gt;br&lt;/code&gt; will transparently handle
gzipped content when &lt;code&gt;-i&lt;/code&gt; is specified (gzipped
&lt;code&gt;stdin&lt;/code&gt; is not supported, use &lt;code&gt;zcat&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;One last thing: &lt;code&gt;stderr&lt;/code&gt; from most parts of &lt;code&gt;br&lt;/code&gt;
is saved to &lt;code&gt;$tmp/br_stderr&lt;/code&gt; where &lt;code&gt;$tmp&lt;/code&gt; is the
&lt;code&gt;-t&lt;/code&gt; option (which defaults to &lt;code&gt;/tmp&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;Performance&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;ve found performance to pretty well follow with the number of
cores made available with one caveat: if your dataset is small and your
merge step is significant, it will dominate and performance gains will
be reduced.&lt;/p&gt;

&lt;h2&gt;Distributed Filesystem&lt;/h2&gt;

&lt;p&gt;I want to spend some time talking about what a distributed filesystem
for &lt;code&gt;br&lt;/code&gt; will look like.&amp;nbsp; For OpenDNS&amp;#8217; immediate
purposes, a filesystem mirrored using &lt;code&gt;rsync&lt;/code&gt; is desirable from
both a performance and durability point-of-view.&amp;nbsp; For more general
use, being limited by the size of your smallest node is not acceptable.&lt;/p&gt;

&lt;p&gt;Growing the dataset beyond the size of the smallest node introduces two
challenges.&amp;nbsp; First, how to partition and replicate the data and second,
how to find these partitions later.&amp;nbsp; Ultimately, I realize the answer
is probably to stop hating and use Hadoop.&amp;nbsp; Humor me.&lt;/p&gt;

&lt;p&gt;The simplest solution is probably the RedHat GFS
&lt;a id="f-27-3-src" href="#f-27-3" class="footnote"&gt;[3]&lt;/a&gt; since it&amp;#8217;s POSIX-compliant and
designed to scale beyond one node&amp;#8217;s capacity.&amp;nbsp; The downside is
that it isn&amp;#8217;t able to take any of the locality considerations
of HDFS into account.&lt;/p&gt;

&lt;p&gt;The other interesting possibility is wiring
MogileFS &lt;a id="f-27-4-src" href="#f-27-4" class="footnote"&gt;[4]&lt;/a&gt; or
HDFS &lt;a id="f-27-5-src" href="#f-27-5" class="footnote"&gt;[5]&lt;/a&gt;
itself underneath &lt;code&gt;br&lt;/code&gt; as a frontend.&amp;nbsp; With Hadoop Streaming,
this isn&amp;#8217;t too far fetched and may represent the best route for
a &lt;code&gt;br&lt;/code&gt; user who outgrows a single-node&amp;#8217;s storage
capacity.&lt;/p&gt;

&lt;h2&gt;Licensed by the goodwill of Erik Frey&lt;/h2&gt;

&lt;p&gt;Here&amp;#8217;s my version: &lt;big&gt;&lt;a href="http://github.com/rcrowley/bashreduce"&gt;http://github.com/rcrowley/bashreduce&lt;/a&gt;&lt;/big&gt;&lt;/p&gt;


&lt;ol class="footnote"&gt;
	&lt;li id="f-27-1"&gt;&lt;a href="http://blog.last.fm/2009/04/06/mapreduce-bash-script"&gt;http://blog.last.fm/2009/04/06/mapreduce-bash-script&lt;/a&gt; &lt;a href="#f-27-1-src" class="footnote-src"&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
	&lt;li id="f-27-2"&gt;&lt;a href="http://rcrowley.org/2009/06/23/building-opendns-stats-at-velocity"&gt;http://rcrowley.org/2009/06/23/building-opendns-stats-at-velocity&lt;/a&gt; &lt;a href="#f-27-2-src" class="footnote-src"&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
	&lt;li id="f-27-3"&gt;&lt;a href="http://www.redhat.com/gfs/"&gt;http://www.redhat.com/gfs/&lt;/a&gt; &lt;a href="#f-27-3-src" class="footnote-src"&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
	&lt;li id="f-27-4"&gt;&lt;a href="http://www.danga.com/mogilefs/"&gt;http://www.danga.com/mogilefs/&lt;/a&gt; &lt;a href="#f-27-4-src" class="footnote-src"&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
	&lt;li id="f-27-5"&gt;&lt;a href="http://hadoop.apache.org/core/docs/current/hdfs_user_guide.html"&gt;http://hadoop.apache.org/core/docs/current/hdfs_user_guide.html&lt;/a&gt; &lt;a href="#f-27-5-src" class="footnote-src"&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/rcrowley?a=hntzvX-svF0:aVC8bfQk5hI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/rcrowley?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/rcrowley?a=hntzvX-svF0:aVC8bfQk5hI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/rcrowley?i=hntzvX-svF0:aVC8bfQk5hI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rcrowley/~4/hntzvX-svF0" height="1" width="1"/&gt;</content><feedburner:origLink>http://rcrowley.org/2009/06/27/bashreduce</feedburner:origLink></entry><entry><title>&amp;#8220;Building OpenDNS Stats&amp;#8221; at Velocity</title><link href="http://feedproxy.google.com/~r/rcrowley/~3/3EHOgF-Ucro/building-opendns-stats-at-velocity" rel="alternate" /><id>http://rcrowley.org/2009/06/23/building-opendns-stats-at-velocity</id><published>2009-06-23T17:45:56-07:00</published><updated>2009-06-26T09:48:49-07:00</updated><author><name>Richard Crowley</name></author><content type="html">&lt;p&gt;I just finished talking about OpenDNS&amp;#8217;s stats system at Velocity
and I think it went rather well.&amp;nbsp; I got the official Allspaw and
Hammond seals of approval so my life is pretty much complete.&lt;/p&gt;

&lt;p&gt;Here are the slides: &lt;a href="http://rcrowley.org/talks/opendns_stats.pdf"&gt;http://rcrowley.org/talks/opendns_stats.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Questions I expected and wasn&amp;#8217;t asked because I only left
8 seconds for questions:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;&lt;em&gt;When you catch std::bad_alloc, why do you shutdown the process
	instead of just freeing some memory?&lt;/em&gt;&amp;nbsp; I chose to exit and let
	&lt;a href="http://cr.yp.to/daemontools/supervise.html"&gt;&lt;code&gt;supervise&lt;/code&gt;&lt;/a&gt;
	restart the process because I might have run out of memory due to a
	slow memory leak.&amp;nbsp; Starting fresh is safer and doesn&amp;#8217;t
	have any downsides.&amp;nbsp; In production, each node tends to restart
	every day shortly after midnight, UTC as rows for the new day start
	being allocated.&lt;/li&gt;
	&lt;li&gt;&lt;em&gt;What&amp;#8217;s up with the waffle at the end?&lt;/em&gt;&amp;nbsp;
	Wednesdays are Waffle Wednesdays at OpenDNS.&amp;nbsp;
	&lt;a href="http://www.opendns.com/about/careers/"&gt;We&amp;#8217;re
	hiring&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;del&gt;I&amp;#8217;ll update later with the video link when O&amp;#8217;Reilly
posts.&lt;/del&gt;&amp;nbsp; Moving pictures with sound!&amp;nbsp; &lt;a href="http://blip.tv/file/2286154/"&gt;http://blip.tv/file/2286154/&lt;/a&gt; and embedded below.&lt;/p&gt;

&lt;embed src="http://blip.tv/play/AYGMsDIA" type="application/x-shockwave-flash" width="640" height="390" allowscriptaccess="always" allowfullscreen="true"&gt;&lt;/embed&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/rcrowley?a=3EHOgF-Ucro:kYLlYYcFaNI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/rcrowley?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/rcrowley?a=3EHOgF-Ucro:kYLlYYcFaNI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/rcrowley?i=3EHOgF-Ucro:kYLlYYcFaNI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rcrowley/~4/3EHOgF-Ucro" height="1" width="1"/&gt;</content><feedburner:origLink>http://rcrowley.org/2009/06/23/building-opendns-stats-at-velocity</feedburner:origLink></entry><entry><title>(spacetimeshift)</title><link href="http://feedproxy.google.com/~r/rcrowley/~3/vB3om_KWQDs/spacetimeshift" rel="alternate" /><id>http://rcrowley.org/2009/05/01/spacetimeshift</id><published>2009-05-01T16:37:44-07:00</published><updated>2009-05-01T16:37:44-07:00</updated><author><name>Richard Crowley</name></author><content type="html">&lt;p&gt;It&amp;#8217;s almost the first Saturday in May, which means it&amp;#8217;s
almost time to &lt;del&gt;drink and gamble&lt;/del&gt; celebrate my Kentucky
heritage.&amp;nbsp; Here&amp;#8217;s the setup I will be using to observe the
race at 6:24pm as Eastern Daylight Savings Time intends.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.flickr.com/photos/rcrowley/3491974643/"
title="(spacetimeshift) by rcrowley, on Flickr"&gt;&lt;img
src="http://farm4.static.flickr.com/3410/3491974643_6160b0c235.jpg"
width="500" height="386" alt="(spacetimeshift)" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s good, ol&amp;#8217; fashioned Kentucky cable TV, split and sent
to both the TV there and an old TiVo.&amp;nbsp; The TiVo outputs to and is
controlled by Mike Malone&amp;#8217;s Slingbox, which is being displayed on my
TV in San Francisco via Malone&amp;#8217;s DVI-to-HDMI cable.&amp;nbsp; Thanks,
Mike!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/rcrowley?a=vB3om_KWQDs:OdI-0t8WbcU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/rcrowley?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/rcrowley?a=vB3om_KWQDs:OdI-0t8WbcU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/rcrowley?i=vB3om_KWQDs:OdI-0t8WbcU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rcrowley/~4/vB3om_KWQDs" height="1" width="1"/&gt;</content><feedburner:origLink>http://rcrowley.org/2009/05/01/spacetimeshift</feedburner:origLink></entry><entry><title>Haystack and Whoosh notes</title><link href="http://feedproxy.google.com/~r/rcrowley/~3/pVbiZe3psGI/haystack-and-whoosh-notes" rel="alternate" /><id>http://rcrowley.org/2009/04/26/haystack-and-whoosh-notes</id><published>2009-04-26T20:52:02-07:00</published><updated>2009-04-28T15:15:53-07:00</updated><author><name>Richard Crowley</name></author><content type="html">&lt;p&gt;Real search is always better than running &lt;code&gt;LIKE&lt;/code&gt; queries
from MySQL so today I picked up Haystack &lt;a id="f-26-1-src" href="#f-26-1" class="footnote"&gt;[1]&lt;/a&gt;
and Whoosh &lt;a id="f-26-2-src" href="#f-26-2" class="footnote"&gt;[2]&lt;/a&gt;.&amp;nbsp; I chose this combination for
the low barrier to entry and the easy upgrade path should that be
required.&amp;nbsp; Both are pure Python and speak &lt;code&gt;setup.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The first problem I ran into has actually been fixed but not
committed.&amp;nbsp; The Gist embedded below patches Whoosh as recommended
in the bug report &lt;a id="f-26-3-src" href="#f-26-3" class="footnote"&gt;[3]&lt;/a&gt;.&amp;nbsp; The bug
manifests itself as &amp;#8220;IOError: [Errno 24] Too many open files&amp;#8221;
when you try to load even modestly sized datasets all at once.&amp;nbsp;
I can&amp;#8217;t make my laptop give me more than 8192 file descriptors
and my Slice will only give me 1024 so I could never see just how bad
things got on a 1.5 million row sample.&amp;nbsp; With the patch, though,
everything is golden.&lt;/p&gt;

&lt;p&gt;The second and last problem I encountered was more of a documentation
problem.&amp;nbsp; Some of the official tutorial is a bit overkill, so
here&amp;#8217;s the fastest get-up-and-go tutorial I can distill:&lt;/p&gt;

&lt;ol&gt;

&lt;li&gt;&lt;p&gt;Add &lt;code&gt;'haystack',&lt;/code&gt; to &lt;code&gt;INSTALLED_APPS&lt;/code&gt; in your
&lt;code&gt;settings.py&lt;/code&gt;.&amp;nbsp; Also add these two lines to let Haystack
know where to keep your Whoosh index files:&lt;/p&gt;
&lt;pre&gt;HAYSTACK_SEARCH_ENGINE = 'whoosh'
HAYSTACK_WHOOSH_PATH = '/path/to/server/writable/directory'&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Add two lines to your global &lt;code&gt;urls.py&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;import haystack
haystack.autodiscover()&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Create a file called &lt;code&gt;search_indexes.py&lt;/code&gt; next to
&lt;code&gt;models.py&lt;/code&gt;.&amp;nbsp; This file will contain model-like classes
defining your search schema.&amp;nbsp; It is important to list every field you
will want in your search results (the primary key, for example) in the
search schema.&amp;nbsp; The field defined with &lt;code&gt;document=True&lt;/code&gt; and
the &lt;code&gt;prepare&lt;/code&gt; method determine the searchable data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update: &lt;a href="http://github.com/toastdriven"&gt;Daniel Lindsley&lt;/a&gt;
pointed out that Haystack reserves &lt;code&gt;id&lt;/code&gt; for itself so I&amp;#8217;ve
changed my example to use a &lt;code&gt;slug&lt;/code&gt; field.&amp;nbsp; Same point
applies, just don&amp;#8217;t use an &lt;code&gt;id&lt;/code&gt; field in your subclasses
of &lt;code&gt;SearchIndex&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;from haystack import indexes
from haystack.sites import site
from models import Foo
class FooIndex(indexes.SearchIndex):
	&lt;strong&gt;text = indexes.CharField(document=True)&lt;/strong&gt;
	slug = indexes.CharField(model_attr='slug')
	name = indexes.CharField(model_attr='name')
	city = indexes.CharField(model_attr='city')
	state = indexes.CharField(model_attr='state')
	def prepare(self, obj):
		self.prepared_data = super(FooIndex, self).prepare(obj)
		&lt;strong&gt;self.prepared_data['text'] = obj.name&lt;/strong&gt;
		return self.prepared_data
site.register(Foo, FooIndex)&lt;/pre&gt;
&lt;p&gt;I&amp;#8217;ve called the indexable data &amp;#8220;text&amp;#8221; and use the
&lt;code&gt;prepare&lt;/code&gt; method to explicitly allow searching by name
only.&amp;nbsp; The official documentation ask for a template file to use
during preparation but I think this is overkill.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Replace your old ORM-based search view with something like this:&lt;/p&gt;
&lt;pre&gt;from haystack.views import SearchView
def search(req):
	return SearchView(template='search.html')(req)&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Replace your search page&amp;#8217;s template with something like this:&lt;/p&gt;
&lt;pre&gt;{% extends 'layout.html' %}
{% url core.views.search as base %}
{% block content %}
&amp;lt;form action="{{ base }}" method="get"&amp;gt;
&amp;lt;h1&amp;gt;&amp;lt;label for="query"&amp;gt;{% block title %}Search{% endblock %}&amp;lt;/label&amp;gt;
for &amp;lt;input id="query" name="query" type="text" value="{{ query }}" /&amp;gt;
&amp;lt;input type="submit" value="Search" class="button" /&amp;gt;&amp;lt;/h1&amp;gt;
&amp;lt;/form&amp;gt;
{% if page.object_list %}
	&amp;lt;ol start="{{ page.start_index }}"&amp;gt;
	{% for o in page.object_list %}
		&amp;lt;li&amp;gt;&amp;lt;a href="{{ base }}/{{ o.slug }}"&amp;gt;{{ o.name }}&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
	{% endfor %}
	&amp;lt;/ol&amp;gt;
	&amp;lt;p&amp;gt;Page {{ page.number }} of {{ page.paginator.num_pages }}&amp;lt;/p&amp;gt;
	&amp;lt;ul&amp;gt;
	{% if page.has_previous %}
		&amp;lt;li&amp;gt;&amp;lt;a href="{{ base }}?query={{ query|urlencode }}&amp;amp;amp;page={{ page.previous_page_number }}"&amp;gt;&amp;amp;larr; Previous&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
	{% endif %}
	{% if page.has_next %}
		&amp;lt;li&amp;gt;&amp;lt;a href="{{ base }}?query={{ query|urlencode }}&amp;amp;amp;page={{ page.next_page_number }}"&amp;gt;Next &amp;amp;rarr;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
	{% endif %}
	&amp;lt;/ul&amp;gt;
{% else %}
	{% if query %}
		&amp;lt;p&amp;gt;We couldn&amp;rsquo;t find anything named &amp;lt;strong&amp;gt;{{ query }}&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
	{% endif %}
{% endif %}
{% endblock %}&lt;/pre&gt;
&lt;p&gt;The view gets the &lt;code&gt;query&lt;/code&gt;, a &lt;code&gt;page&lt;/code&gt; from a regular
Django Paginator and the &lt;code&gt;paginator&lt;/code&gt; itself.&amp;nbsp; A
&lt;code&gt;form&lt;/code&gt; comes along too but I prefer to ignore this.&amp;nbsp; If
you defined your own User model that lives at &lt;code&gt;req.user&lt;/code&gt;, it
must implement &lt;code&gt;get_and_delete_messages&lt;/code&gt; &lt;a id="f-26-4-src" href="#f-26-4" class="footnote"&gt;[4]&lt;/a&gt;
because &lt;code&gt;django.contrib.auth.models.User&lt;/code&gt; leaks into
&lt;code&gt;django.core.context_preprocessors a bit.&lt;/p&gt;&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;Here&amp;#8217;s the previously mentioned &lt;del&gt;patch-and-&lt;/del&gt;install script
&lt;strong&gt;(Updated to reflect bugfixes merged into the trunk of
Whoosh!)&lt;/strong&gt;:&lt;/p&gt;

&lt;script src="http://gist.github.com/102284.js"&gt;&lt;/script&gt;


&lt;ol class="footnote"&gt;
	&lt;li id="f-26-1"&gt;&lt;a href="http://haystacksearch.org/"&gt;http://haystacksearch.org/&lt;/a&gt; &lt;a href="#f-26-1-src" class="footnote-src"&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
	&lt;li id="f-26-2"&gt;&lt;a href="http://whoosh.ca/"&gt;http://whoosh.ca/&lt;/a&gt; &lt;a href="#f-26-2-src" class="footnote-src"&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
	&lt;li id="f-26-3"&gt;&lt;a href="http://trac.whoosh.ca/ticket/25"&gt;http://trac.whoosh.ca/ticket/25&lt;/a&gt; &lt;a href="#f-26-3-src" class="footnote-src"&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
	&lt;li id="f-26-4"&gt;&lt;a href="http://github.com/rcrowley/django-twitterauth/commit/83ba6a07df3e97455abd4ab2b3ffaba7096407bc"&gt;http://github.com/rcrowley/django-twitterauth/commit/83ba6a07df3e97455abd4ab2b3ffaba7096407bc&lt;/a&gt; &lt;a href="#f-26-4-src" class="footnote-src"&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/rcrowley?a=pVbiZe3psGI:8svAJR9SSe0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/rcrowley?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/rcrowley?a=pVbiZe3psGI:8svAJR9SSe0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/rcrowley?i=pVbiZe3psGI:8svAJR9SSe0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rcrowley/~4/pVbiZe3psGI" height="1" width="1"/&gt;</content><feedburner:origLink>http://rcrowley.org/2009/04/26/haystack-and-whoosh-notes</feedburner:origLink></entry><entry><title>College courses I should have taken</title><link href="http://feedproxy.google.com/~r/rcrowley/~3/YUOjlqkccGw/college-courses-i-should-have-taken" rel="alternate" /><id>http://rcrowley.org/2009/04/09/college-courses-i-should-have-taken</id><published>2009-04-09T17:15:56-07:00</published><updated>2009-04-09T17:15:56-07:00</updated><author><name>Richard Crowley</name></author><content type="html">&lt;p&gt;Yesterday, I read through A List Apart&amp;#8217;s 2008 Survey and the
Relevance of Education &lt;a id="f-09-1-src" href="#f-09-1" class="footnote"&gt;[1]&lt;/a&gt;
section tricked me into reflecting on my time at Wash U.&amp;nbsp; My professors
taught me all about performance and time complexity, data structures,
operating systems, circuits and hardware architecture (I am a hardware
designer by education).&amp;nbsp; All of this, save the direct design of new
hardware, has been immensely helpful in my first two years as a Real
Boy&amp;trade;.&lt;/p&gt;

&lt;p&gt;Since yes-or-no questions are kind of boring, I reflected further on
what my college education lacked&amp;nbsp;&amp;mdash; courses I wish I&amp;#8217;d
taken.&amp;nbsp; While I was working for Flickr and recruiting for Yahoo!, I
spent a part of each visit to Wash U encouraging the Computer Science
department to get serious about web programming.&amp;nbsp; The result was an
ostensibly senior-level course that guided students through LAMP, Rails,
databases and JavaScript plus the protocols/standards they build upon:
HTTP, HTML and CSS.&amp;nbsp; It was a great addition to the program and
I hope it&amp;#8217;s still around.&amp;nbsp; Though I&amp;#8217;ve not kept up
my course-list evangelism, I now have several more courses I wish I&amp;#8217;d
taken.&lt;/p&gt;

&lt;h2&gt;Network algorithms&lt;/h2&gt;
&lt;p&gt;The algorithms course that I took focused on efficient computation on
a single node.&amp;nbsp; Wash U offered an Advanced Algorithms course that, in
retrospect, I should have taken.&amp;nbsp; I hope such a course covers
network-aware algorithms like map/reduce, gossip and P2P protocols,
queuing and distributed hash tables (Chord
&lt;a id="f-09-2-src" href="#f-09-2" class="footnote"&gt;[2]&lt;/a&gt;, etc.).&amp;nbsp; These topics
become required knowledge when you start talking about &amp;#8220;Internet
scale&amp;#8221; anything.&lt;/p&gt;

&lt;h2&gt;Managing disk I/O&lt;/h2&gt;
&lt;p&gt;This course definitely doesn&amp;#8217;t exist.&amp;nbsp; Academics are big fans
of pretending they have infinite I/O capacity but they do students a
disservice by hand-waving one of the largest time-sinks in all of
computing.&amp;nbsp; I have learned a lot by reading papers and blog posts
produced by my more experienced peers and even more by
trial-and-error.&amp;nbsp; Topics for such a course include write-ahead logs
(and all of the other things InnoDB does), &lt;code&gt;aio&lt;/code&gt; and its effect
on performance plus some time to address concurrency as it pertains to
disk performance.&amp;nbsp; Engineering school should prepare people for reality
and I can&amp;#8217;t thing of anything more real than &lt;code&gt;iowait&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;Lock-less data structures&lt;/h2&gt;
&lt;p&gt;I&amp;#8217;m not certain this doesn&amp;#8217;t exist at Wash U.&amp;nbsp; The
Drizzle mailing list &lt;a id="f-09-3-src" href="#f-09-3" class="footnote"&gt;[3]&lt;/a&gt;
made mention of lock-free data structures, a topic I haven&amp;#8217;t given
much thought to beyond using &lt;code&gt;concurrent_hash_map&lt;/code&gt; from the
Intel TBB &lt;a id="f-09-4-src" href="#f-09-4" class="footnote"&gt;[4]&lt;/a&gt;.&amp;nbsp; Not
surprisingly, the design of these libraries is difficult and
theoretical&amp;nbsp;&amp;mdash; you have to &lt;em&gt;prove&lt;/em&gt; correctness since so
much is left to chance.&amp;nbsp; Academics love proofs, right?&lt;/p&gt;

&lt;h2&gt;OS kernels&lt;/h2&gt;
&lt;p&gt;I took Wash U&amp;#8217;s senior-level Operating Systems course but never
got around to taking the graduate-level version.&amp;nbsp; The former focused
on &lt;code&gt;libc&lt;/code&gt;, system calls, threading and writing programs that
behave like UNIX programs.&amp;nbsp; The latter dives into the Linux kernel
itself.&amp;nbsp; I don&amp;#8217;t anticipate becoming a kernel hacker anytime
soon but having deep knowledge on the design of the Linux kernel would
definitely make me a better software architect.&lt;/p&gt;

&lt;h2&gt;More econ&lt;/h2&gt;
&lt;p&gt;I took up through intermediate microeconomics and wish I had learned
more.&amp;nbsp; I don&amp;#8217;t have the solutions to the world&amp;#8217;s problems
and I still wouldn&amp;#8217;t even if I knew more but I would understand
the expert&amp;#8217;s opinions more thoroughly.&lt;/p&gt;

&lt;p&gt;Anything I&amp;#8217;m missing?&amp;nbsp; I&amp;#8217;m curious what others wish
they&amp;#8217;d taken in college, especially those who have been at it
professionally for more than two years.&lt;/p&gt;


&lt;ol class="footnote"&gt;
	&lt;li id="f-09-1"&gt;&lt;a href="http://aneventapart.com/alasurvey2008/02.html"&gt;http://aneventapart.com/alasurvey2008/02.html&lt;/a&gt; &lt;a href="#f-09-1-src" class="footnote-src"&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
	&lt;li id="f-09-2"&gt;&lt;a href="http://en.wikipedia.org/wiki/Chord_(DHT)"&gt;http://en.wikipedia.org/wiki/Chord_(DHT)&lt;/a&gt; &lt;a href="#f-09-2-src" class="footnote-src"&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
	&lt;li id="f-09-3"&gt;&lt;a href="https://lists.launchpad.net/drizzle-discuss/msg03337.html"&gt;https://lists.launchpad.net/drizzle-discuss/msg03337.html&lt;/a&gt; &lt;a href="#f-09-3-src" class="footnote-src"&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
	&lt;li id="f-09-4"&gt;&lt;a href="http://software.intel.com/en-us/intel-tbb/"&gt;http://software.intel.com/en-us/intel-tbb/&lt;/a&gt; &lt;a href="#f-09-4-src" class="footnote-src"&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/rcrowley?a=YUOjlqkccGw:vp-_sjtrXjQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/rcrowley?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/rcrowley?a=YUOjlqkccGw:vp-_sjtrXjQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/rcrowley?i=YUOjlqkccGw:vp-_sjtrXjQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rcrowley/~4/YUOjlqkccGw" height="1" width="1"/&gt;</content><feedburner:origLink>http://rcrowley.org/2009/04/09/college-courses-i-should-have-taken</feedburner:origLink></entry><entry><title>How-to</title><link href="http://feedproxy.google.com/~r/rcrowley/~3/MugKOu83ueE/how-to" rel="alternate" /><id>http://rcrowley.org/2009/04/02/how-to</id><published>2009-04-02T09:17:12-07:00</published><updated>2009-04-02T09:17:12-07:00</updated><author><name>Richard Crowley</name></author><content type="html">&lt;p&gt;My absolute favorite kind of how-to post involves me downloading,
&lt;em&gt;reading&lt;/em&gt; and running a shell script that automates an otherwise
tedious and non-obvious process.&amp;nbsp; If it were straightforward, I
wouldn&amp;#8217;t be googling for it in the first place.&amp;nbsp; The Gist
tool on GitHub is perfect for how-to scripts, so here we go.&lt;/p&gt;

&lt;p&gt;So, since I&amp;#8217;ve already chugged the promises of the Drizzle
Kool-Aid, it is time I started using it in hopes I can soon contribute
code myself.&amp;nbsp; Step one is getting the bugger to install.&amp;nbsp; Step
two is writing a little program using the &lt;em&gt;very&lt;/em&gt; Brian Aker-ified
&lt;code&gt;libdrizzle&lt;/code&gt; C library.&amp;nbsp; Today is a step one kind of
day.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m on Ubuntu Intrepid myself but from the package lists, this
looks like it'll work almost out-of-the-box for all Ubuntu flavors.&amp;nbsp;
The hands-on part will be the Bazaar PPA but a visit to
&lt;a href="https://launchpad.net/~bzr/+archive/ppa"&gt;Launchpad&lt;/a&gt; will get
you the right &lt;code&gt;/etc/apt/sources.list&lt;/code&gt; lines and the appropriate
key.&lt;/p&gt;

&lt;p&gt;I started from a system that was already full of compilers and libraries
so, for completeness, I&amp;#8217;ve included a modification to the
&lt;a href="http://drizzle.org/wiki/Compiling#Ubuntu_2"&gt;official Ubuntu
dependency list&lt;/a&gt;.&amp;nbsp; The modifications get you newer Bazaar, newer
&lt;code&gt;libevent&lt;/code&gt; and what I believe to be a more generally build-ready
environment.&lt;/p&gt;

&lt;p&gt;This installs &lt;code&gt;libprotobuf&lt;/code&gt; and &lt;code&gt;libevent&lt;/code&gt;
manually so make sure to comment those sections if you already have a
version you like.&lt;/p&gt;

&lt;script src="http://gist.github.com/88478.js"&gt;&lt;/script&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/rcrowley?a=MugKOu83ueE:fOYYmepwCAU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/rcrowley?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/rcrowley?a=MugKOu83ueE:fOYYmepwCAU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/rcrowley?i=MugKOu83ueE:fOYYmepwCAU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rcrowley/~4/MugKOu83ueE" height="1" width="1"/&gt;</content><feedburner:origLink>http://rcrowley.org/2009/04/02/how-to</feedburner:origLink></entry><entry><title>Distributed version control</title><link href="http://feedproxy.google.com/~r/rcrowley/~3/huwY9iwOwOo/distributed-version-control" rel="alternate" /><id>http://rcrowley.org/2009/03/16/distributed-version-control</id><published>2009-03-16T21:32:17-07:00</published><updated>2009-03-16T21:43:10-07:00</updated><author><name>Richard Crowley</name></author><content type="html">&lt;p&gt;First Wistow &lt;a id="f-16-1-src" href="#f-16-1" class="footnote"&gt;[1]&lt;/a&gt; and
now Malcolm &lt;a id="f-16-2-src" href="#f-16-2" class="footnote"&gt;[2]&lt;/a&gt;!&amp;nbsp;
Wistow wrote a couple of weeks back about Git being awesome but
encouraging the kind of patch hide-and-seek he had to endure when
building NCSA httpd.&amp;nbsp; In the comments we discussed whether the
tools offered enough benefits to outweigh the inherent encouragement
to fork your forks of your mother&amp;#8217;s fork.&amp;nbsp; I still maintain
the tools offer significant benefits even in the face of Malcolm&amp;#8217;s
concern that rampant forking can splinter communities before they really
form.&amp;nbsp; Being a Django juggernaut, his word carries a lot of weight
but I feel obligated to point out that the pile of forks that every
open-source project must endure is not a new problem.&lt;/p&gt;

&lt;p&gt;I bet every open-source program ever released has been tweaked by
savvy users to do something extra, something different or something more
correct.&amp;nbsp; Distributed version control and sites like GitHub have
brought the forks front-and-center, which I think is a much nicer place
to keep them.&amp;nbsp; Malcolm&amp;#8217;s got a point &amp;mdash; it shouldn&amp;#8217;t
be up to the user to decide which fork or set of forks is best; a successful
project needs a release to serve as the official starting point.&amp;nbsp;
Merging patches or branches is a job for the fearless leader and one which
should not be taken lightly.&lt;/p&gt;

&lt;p&gt;Distributed version control gives the fearless leader a fighting chance
to make sense of the parallel thought processes of any project&amp;#8217;s
multiple developers.&amp;nbsp; An open-source project living in Subversion is
stuck with patch files, emails and tickets; a project using Git gets branches,
history, false starts and good ideas in as much or as little detail as the
fearless leader needs to decide the fate of the patch.&lt;/p&gt;

&lt;p&gt;Version control is a tool, not a form of government.&amp;nbsp; It is the
fearless leader&amp;#8217;s responsibility to merge the best patches into the
master copy, get second opinions and rewrites of iffy changes or flat-out
reject feature creep and poor implementation.&lt;/p&gt;

&lt;p&gt;There will always be both selfish users and philanthropic users.&amp;nbsp;
In this awesome new world that has so many people coding in public
(thanks GitHub, Launchpad and Bitbucket!), it is actually becoming easier
to be philanthropic than selfish.&amp;nbsp; It is easier to fork
&lt;code&gt;$PROJECT&lt;/code&gt; on GitHub than to sequester changes behind your
Virtual Paranoid Network and GitHub keeps the fearless leader
informed.&amp;nbsp; The loop is closed.&amp;nbsp; We&amp;#8217;ve emerged from patch
hell.&amp;nbsp; We have the commit messages to prove it.&lt;/p&gt;


&lt;ol class="footnote"&gt;
	&lt;li id="f-16-1"&gt;&lt;a href="http://deflatermouse.livejournal.com/148975.html"&gt;http://deflatermouse.livejournal.com/148975.html&lt;/a&gt; &lt;a href="#f-16-1-src" class="footnote-src"&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
	&lt;li id="f-16-2"&gt;&lt;a href="http://www.pointy-stick.com/blog/2009/03/16/dark-side-distributed-version-control/"&gt;http://www.pointy-stick.com/blog/2009/03/16/dark-side-distributed-version-control/&lt;/a&gt; &lt;a href="#f-16-2-src" class="footnote-src"&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/rcrowley?a=huwY9iwOwOo:L4ePF4CAHU8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/rcrowley?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/rcrowley?a=huwY9iwOwOo:L4ePF4CAHU8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/rcrowley?i=huwY9iwOwOo:L4ePF4CAHU8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rcrowley/~4/huwY9iwOwOo" height="1" width="1"/&gt;</content><feedburner:origLink>http://rcrowley.org/2009/03/16/distributed-version-control</feedburner:origLink></entry><entry><title>Drizzle</title><link href="http://feedproxy.google.com/~r/rcrowley/~3/aZPrtRK-T5A/drizzle" rel="alternate" /><id>http://rcrowley.org/2009/03/03/drizzle</id><published>2009-03-03T08:09:49-08:00</published><updated>2009-03-03T08:09:49-08:00</updated><author><name>Richard Crowley</name></author><content type="html">&lt;p&gt;The SF MySQL meetup last night &lt;a id="foot-1-src" href="#foot-1"
class="foot"&gt;[1]&lt;/a&gt; about Drizzle &lt;a id="foot-2-src" href="#foot-2"
class="foot"&gt;[2]&lt;/a&gt; was a home run by my limited research &lt;a
id="foot-3-src" href="#foot-3" class="foot"&gt;[3]&lt;/a&gt;.&amp;nbsp; It
won&amp;#8217;t be a get-out-of-jail-free card for very write-heavy
applications but I bet it will do wonders for heavily replicated, heavily
federated, read-heavy architectures (you know, normal stuff).&lt;/p&gt;

&lt;p&gt;The common conception of Drizzle is a bit off center so I&amp;#8217;d
like to offer my 2-sentence version.&amp;nbsp; First and foremost, Drizzle
is a refactor of MySQL for today&amp;#8217;s hardware and today&amp;#8217;s
architectures.&amp;nbsp; Second, Drizzle is pluggable &amp;mdash; everything
from the storage engines (which default to InnoDB) to the pluggable
PAM authentication and replication &amp;mdash; is replaceable or removable.&lt;/p&gt;

&lt;p&gt;I intimately understand the pros and cons of global mutexes.&amp;nbsp;
Much of my performance testing at OpenDNS has to do with how long our
stats pipeline spends waiting for mutex locks.&amp;nbsp; I have to commend
Brian Aker and Drizzle&amp;#8217;s commitment to their removal.&amp;nbsp; I
suspect read-heavy loads will see a major performance increase from
this alone (Brian was quoting something like 11-13% of time was spent
in the heavily-mutexed authentication code &lt;strong&gt;Update: that time
is spent in parsing, not in auth, still, the mutexes are
bad&lt;/strong&gt;).&amp;nbsp; The last big mutex
is the one that enables MyISAM and it sounded like (it could have been
a convincing planned monologue) Brian decided during his talk to remove
it, meaning you&amp;#8217;d not be able to use MyISAM in Drizzle.&amp;nbsp;
That&amp;#8217;s fine by me &amp;mdash; I only use MyISAM in places where
table-level locks are okay.&lt;/p&gt;

&lt;p&gt;That time spent in authentication is usually a complete waste.&amp;nbsp;
Motivated by the countless MySQL instances running as &amp;#8220;root&amp;#8221;
with no password, authentication is now a removable plugin that can
also use PAM auth like your OS can.&amp;nbsp; I hope my operator will let
me just take it out.&lt;/p&gt;

&lt;p&gt;Most folks in the room didn&amp;#8217;t seem to pick up on this one but
there was a hand-wavey mention of a &amp;#8220;shard bit&amp;#8221; in the wire
protocol which would open the doors to software (or even hardware!)
load-balancers that could understand how you federate your data.&lt;/p&gt;

&lt;p&gt;The last thing I found compelling enough to write down is that Drizzle
is making heavy use of Google&amp;#8217;s Protocol Buffers &lt;a id="foot-4-src"
href="#foot-4" class="foot"&gt;[4]&lt;/a&gt; as part of their query planning.&amp;nbsp;
Serialized, they&amp;#8217;re used as an alternative wire format and as the
replication protocol.&amp;nbsp; Crazy things like replicating some Drizzle
tables through a Protocol Buffer proxy into a different database engine
become downright easy.&amp;nbsp; For example, keeping your main table in a
very indexed Drizzle database while replicating a distilled version into
MemcacheDB for fast primary-key lookups of the essential data.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(This reads like a press release, I&amp;#8217;m sorry.&amp;nbsp; I wrote
all of this down as a cheatsheet for talking to the rest of OpenDNS about
when and if this will make sense for parts of our architecture.)&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
	&lt;li id="foot-1"&gt;&lt;a href="http://mysql.meetup.com/30/calendar/9471261/"&gt;SF MySQL Meetup &amp;mdash; Why Drizzle&lt;/a&gt; &lt;a href="#foot-1-src" class="foot"&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
	&lt;li id="foot-2"&gt;&lt;a href="https://launchpad.net/drizzle"&gt;Drizzle&lt;/a&gt; &lt;a href="#foot-2-src" class="foot"&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
	&lt;li id="foot-3"&gt;&lt;a href="http://twitter.com/mjmalone/status/1272455967"&gt;mjmalone&lt;/a&gt;, &lt;a href="http://twitter.com/mihasya/status/1272845884"&gt;mihasya&lt;/a&gt; &amp;amp; &lt;a href="http://twitter.com/ericflo/status/1272837912"&gt;ericflo&lt;/a&gt; &lt;a href="#foot-3-src" class="foot"&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
	&lt;li id="foot-4"&gt;&lt;a href="http://code.google.com/p/protobuf/"&gt;Google Protocol Buffers&lt;/a&gt; &lt;a href="#foot-4-src" class="foot"&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/rcrowley?a=aZPrtRK-T5A:_jEtE_2mhug:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/rcrowley?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/rcrowley?a=aZPrtRK-T5A:_jEtE_2mhug:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/rcrowley?i=aZPrtRK-T5A:_jEtE_2mhug:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rcrowley/~4/aZPrtRK-T5A" height="1" width="1"/&gt;</content><feedburner:origLink>http://rcrowley.org/2009/03/03/drizzle</feedburner:origLink></entry><entry><title>Diversion</title><link href="http://feedproxy.google.com/~r/rcrowley/~3/ymh1Nm5fMkw/diversion" rel="alternate" /><id>http://rcrowley.org/2009/02/27/diversion</id><published>2009-02-27T07:56:32-08:00</published><updated>2009-02-27T07:56:32-08:00</updated><author><name>Richard Crowley</name></author><content type="html">&lt;p&gt;All I think about at work is disk I/O.&amp;nbsp; That&amp;rsquo;s an
overstatement but the point is to motivate my late night and early
morning batch of small changes to &lt;a
href="http://github.com/rcrowley/bashpress"&gt;Bashpress&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First up, I made the homepage a 302 redirect to the most recent
month&amp;rsquo;s posts.&amp;nbsp; It has long bothered me that blogs are
singluarly obsessed with permalinks and yet will place rotating
content on the homepage without a second thought.&lt;/p&gt;

&lt;p&gt;Second and equally inconsequential is that I added a flag to
Bashpress to globally enable or disable comments, which I&amp;rsquo;ve
disabled.&amp;nbsp; &lt;a
href="http://al3x.net/2009/02/24/why-no-comments-more-everything-buckets.html"
&gt;Al3x&amp;rsquo;s reasoning&lt;/a&gt; sits well with me but for someone without
his noteriety, I need a crutch.&amp;nbsp; &lt;a
href="http://rcrowley.org/js/delicious.js"&gt;delicious.js&lt;/a&gt; pulls
in every save and note from del.icio.us for the post, at least
giving folks willing to dive deeper a map of sorts.&amp;nbsp; It
isn&amp;rsquo;t perfect but hopefully I can work out trackbacks or
something to complete the puzzle.&lt;/p&gt;

&lt;p&gt;Small pieces loosely joined, etc.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/rcrowley?a=ymh1Nm5fMkw:fB53ExqOhao:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/rcrowley?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/rcrowley?a=ymh1Nm5fMkw:fB53ExqOhao:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/rcrowley?i=ymh1Nm5fMkw:fB53ExqOhao:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rcrowley/~4/ymh1Nm5fMkw" height="1" width="1"/&gt;</content><feedburner:origLink>http://rcrowley.org/2009/02/27/diversion</feedburner:origLink></entry><entry><title>django-twitterauth</title><link href="http://feedproxy.google.com/~r/rcrowley/~3/brzYBqBLXPg/django-twitterauth" rel="alternate" /><id>http://rcrowley.org/2009/01/24/django-twitterauth</id><published>2009-01-24T19:30:36-08:00</published><updated>2009-01-24T19:30:36-08:00</updated><author><name>Richard Crowley</name></author><content type="html">&lt;p&gt;For a new little side project I&amp;rsquo;m working on, I need a way to
interact with Twitter on a user&amp;rsquo;s behalf.&amp;nbsp; You know, like
what OAuth is for.&amp;nbsp; Until that blessed day, I&amp;rsquo;ve got &lt;a
href="http://github.com/rcrowley/django-twitterauth"&gt;django-twitterauth&lt;/a&gt;
to keep from stealing Twitter passwords.&lt;/p&gt;

&lt;p&gt;Your app&amp;rsquo;s Twitter user first follows the user that is trying
to authenticate.&amp;nbsp; The user is then directed, by way of a hidden
&lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;, to send a direct message to the app&amp;rsquo;s
Twitter user containing a SHA1 hex digest.&amp;nbsp; Once the app verifies that
it received the direct message, the user is authenticated.&lt;/p&gt;

&lt;p&gt;It isn&amp;rsquo;t the &lt;em&gt;best&lt;/em&gt; flow in the world but it isn&amp;rsquo;t
the worst, either.&amp;nbsp; I hope my Django n00b-iness isn&amp;rsquo;t shining
too bright.&lt;/p&gt;

&lt;p&gt;Once again, &lt;a href="http://github.com/rcrowley/django-twitterauth"
&gt;&lt;big&gt;django-twitterauth on GitHub&lt;/big&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/rcrowley?a=pXHV18Fe"&gt;&lt;img src="http://feeds.feedburner.com/~f/rcrowley?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/rcrowley?a=6RpHfqwg"&gt;&lt;img src="http://feeds.feedburner.com/~f/rcrowley?i=6RpHfqwg" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rcrowley/~4/brzYBqBLXPg" height="1" width="1"/&gt;</content><feedburner:origLink>http://rcrowley.org/2009/01/24/django-twitterauth</feedburner:origLink></entry><entry><title>Out of paper</title><link href="http://feedproxy.google.com/~r/rcrowley/~3/6hIQ_RitFjM/out-of-paper" rel="alternate" /><id>http://rcrowley.org/2009/01/13/out-of-paper</id><published>2009-01-13T11:04:45-08:00</published><updated>2009-01-13T11:04:45-08:00</updated><author><name>Richard Crowley</name></author><content type="html">&lt;p&gt;Last night at the laundromat it took me three attempts to add money to
my stored-value card because I, like everyone else, don't read the messages
in modal dialogs.&amp;nbsp; I know that ATMs, gas pumps, laundromats and other
credit card readers ask if you&amp;rsquo;d like a receipt before they complete
the transaction.&amp;nbsp; Sometimes, though, they tell you they can&amp;rsquo;t
print a receipt and ask for your permission to continue.&amp;nbsp; The problem
is that the options available are the same in both cases: &amp;ldquo;yes&amp;rdquo;
or &amp;ldquo;no.&amp;rdquo;&amp;nbsp; It looks like this:&lt;/p&gt;

&lt;pre&gt;Would you like a receipt?
    YES             NO&lt;/pre&gt;

&lt;pre&gt;Unable to print receipt.&amp;nbsp; Continue?
    YES             NO&lt;/pre&gt;

&lt;p&gt;Because no one reads the actual prompt, the options need to indicate
that something unexpected is going on.&amp;nbsp; This is doubly true when the
machine is so low that I can&amp;rsquo;t even see the top line of the
display.&amp;nbsp; The special case of the printer being out of paper should
read:&lt;/p&gt;

&lt;pre&gt;Unable to print receipt.
    OK              CANCEL&lt;/pre&gt;

&lt;p&gt;By breaking the expected pattern of put in my card, press &amp;ldquo;no&amp;rdquo;,
select $20 and wait, I can do the right thing the first time and avoid being
turned away by the washing machine.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/rcrowley?a=cIpAyN66"&gt;&lt;img src="http://feeds.feedburner.com/~f/rcrowley?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/rcrowley?a=6Fy0UlqA"&gt;&lt;img src="http://feeds.feedburner.com/~f/rcrowley?i=6Fy0UlqA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rcrowley/~4/6hIQ_RitFjM" height="1" width="1"/&gt;</content><feedburner:origLink>http://rcrowley.org/2009/01/13/out-of-paper</feedburner:origLink></entry><entry><title>Django</title><link href="http://feedproxy.google.com/~r/rcrowley/~3/dRs_FuiloYg/django" rel="alternate" /><id>http://rcrowley.org/2008/12/15/django</id><published>2008-12-15T11:56:19-08:00</published><updated>2008-12-15T11:56:19-08:00</updated><author><name>Richard Crowley</name></author><content type="html">&lt;p&gt;I asked &lt;a href="http://immike.net/"&gt;Malone&lt;/a&gt; the other week why
Django made me go all &lt;code&gt;return render_to_response('foo.html')&lt;/code&gt;
in my view named &lt;code&gt;foo&lt;/code&gt; instead of assuming some defaults.
To be explicit, candidates for those defaults might go something along
the lines of:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;If a view function returns &lt;code&gt;None&lt;/code&gt; (which is,
	it seems what happens when you don't return anything), render the
	template that shares its name with the view.&lt;/li&gt;
	&lt;li&gt;If a view function returns a &lt;code&gt;dict&lt;/code&gt;, render the
	template that shares its name with the view, passing this
	&lt;code&gt;dict&lt;/code&gt; wrapped up in a &lt;code&gt;Context&lt;/code&gt;.&lt;/li&gt;
	&lt;li&gt;If the view function returns a string, take the string as the
	template name.&lt;/li&gt;
	&lt;li&gt;If the view function returns a 2-&lt;code&gt;tuple&lt;/code&gt; containing
	a string and a &lt;code&gt;dict&lt;/code&gt;, take the string as the template
	name and make the &lt;code&gt;dict&lt;/code&gt; into a &lt;code&gt;Context&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On top of that, I asked him why Django didn't figure out what response
format makes sense, given the URL and headers in the request and the
formats available for the template chosen.  His response was basically
that Django hates magic.  If it did all of these things, it'd favor
convention over configuration and be called Rails.  Or &lt;em&gt;P&lt;/em&gt;ails.&lt;/p&gt;

&lt;p&gt;After playing around with Django for a few days and now starting to
use it for a real project, I'm seeing the wisdom in Django's (and indeed,
Python's) choice to avoid magic.  I've already used the word "explicit"
once in this post and that's what this is really all about.&lt;/p&gt;

&lt;blockquote&gt;Additionally, Ruby seems to skew towards implicitness in
the language, while Python skews toward explicitness. I like explicitness.
&amp;mdash; &lt;a href="http://www.joestump.net/2008/11/a-discussion-on-languages-and-frameworks.html"&gt;Joe
Stump&lt;/a&gt;&lt;/blockquote&gt;

&lt;p&gt;I'm not here to start a Ruby-versus-Python or Rails-versus-Django fight.
I'm here to talk about being explicit with code.&lt;/p&gt;

&lt;p&gt;My efforts a while back &lt;a
href="http://rcrowley.org/2008/10/26/hacking-the-ruby-interpreter"&gt;hacking
the Ruby interpreter&lt;/a&gt; were a bit misguided.  I was heavily and
prematurely optimizing my desired use case at the expense of code clarity
and at least seven other traits generally considered to be positive.  In
the resulting Frankenruby interpreter, &lt;code&gt;@foo&lt;/code&gt; could show
up in a file outside of a class with no warning, meaning that file could
only ever be used by my very streamlined URL-to-code routing script.  In
retrospect, it's a good thing I never got it to work just right.&lt;/p&gt;

&lt;p&gt;The desire to remove as many declarative, housekeeping-esque lines of
code is seemingly noble but it is at odds with another principle of mine,
learned from years in the trenches writing C(++): always
&lt;code&gt;#include&lt;/code&gt; everything a file uses.  This makes files instantly
more portable and less magical.  Despite Django's mascot being a magical
pony, I gather that it, too, avoids magic in most scenarios.&lt;/p&gt;

&lt;p&gt;Being explicit allows Django to be loosely-coupled.  Imagine trying to
remove the Django ORM or templating system if they were omnipresent in
every Django app from start to finish.  Tedious.  As it is, a single
"&lt;code&gt;#&lt;/code&gt;" sets you free.  Even the concept of having many apps
within a project enables further explicit use or disuse of each package.&lt;/p&gt;

&lt;p&gt;Being explicit also lowers the barriers-to-entry for would-be framework
hackers like myself.  My first serious afternoon saw me trying to create
a fairly involved template tag.  It would have made page titles work just
about like the excellent Headliner plugin for Rails.  I discovered along
the way that the &lt;code&gt;{% block foo %}&lt;/code&gt; template tag, if placed within
another block, would both override the named block and output its contents
in place.  Observe, here's how I decided to do page titles in Django:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In &lt;code&gt;templates/layout.html&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&amp;lt;title&amp;gt;Foo &amp;mdash; {% block title %}{% endblock %}&amp;lt;/title&amp;gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;In other templates:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;{% extends 'layout.html' %}
{% block title %}Only shows up in the title tag{% endblock %}
{% block content %}
&amp;lt;p&amp;gt;foo&amp;lt;/p&amp;gt;
{% endblock %}&lt;/pre&gt;
&lt;pre&gt;{% extends 'layout.html' %}
{% block content %}
&amp;lt;h1&amp;gt;{% block title %}Shows up here and in the title tag{% endblock %}&amp;lt;/h1&amp;gt;
{% endblock %}&lt;/pre&gt;

&lt;p&gt;The ORM looks similarly easy to figure out though I haven't taken the
plunge yet.  I already know what I'm going to build to learn it, though:
a command-line SQL tool that works through a combination of Python and
hard links.  The python script will find the closest Django settings module
and use the database connection info there.  The command will be invoked by
typing out a SQL statement on the command line.  The SQL statement will be
&lt;code&gt;' '.join(sys.argv)&lt;/code&gt; and the commands &lt;code&gt;SELECT&lt;/code&gt;,
&lt;code&gt;INSERT&lt;/code&gt;, etc. will be routed to the Python script using hard
links.  I don't know if this is a good idea but I know it'll be relatively
easy to do thanks to how easy it seems to be to dive into the Django
internals.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/rcrowley?a=l0NtXq06"&gt;&lt;img src="http://feeds.feedburner.com/~f/rcrowley?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/rcrowley?a=WKUeiK5K"&gt;&lt;img src="http://feeds.feedburner.com/~f/rcrowley?i=WKUeiK5K" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rcrowley/~4/dRs_FuiloYg" height="1" width="1"/&gt;</content><feedburner:origLink>http://rcrowley.org/2008/12/15/django</feedburner:origLink></entry><entry><title>Hacking the Ruby interpreter</title><link href="http://feedproxy.google.com/~r/rcrowley/~3/h8yd4GpriaE/hacking-the-ruby-interpreter" rel="alternate" /><id>http://rcrowley.org/2008/10/26/hacking-the-ruby-interpreter</id><published>2008-10-26T18:11:16-07:00</published><updated>2008-10-26T18:11:16-07:00</updated><author><name>Richard Crowley</name></author><content type="html">&lt;p&gt;I like Ruby.  Ruby the language anyway.  I have started to have violent
reactions to PHP's lack of closures.  However, Ruby has one deficiency that
makes me almost as mad as PHP's lack of closures.  Assume for this example
that the file foo.rb looks like this:&lt;/p&gt;

&lt;pre&gt;@foo = "I'm getting ready to abuse the instance variable syntax."&lt;/pre&gt;

&lt;p&gt;As is, Ruby lets me do the following, which is functionally desirable
but makes the good programmer part of me twitch:&lt;/p&gt;

&lt;pre&gt;class Foo
    def initialize(path)
        &lt;strong&gt;self.instance_eval(File.read(path))&lt;/strong&gt;
    end
end
f = Foo.new('load_me.rb')
f.instance_variables # =&gt; ['@foo']&lt;/pre&gt;

&lt;p&gt;Replacing the bold line with the following is what I'm after:&lt;/p&gt;

&lt;pre&gt;        &lt;strong&gt;load_in_scope path&lt;/strong&gt;&lt;/pre&gt;

&lt;p&gt;In my dream, &lt;code&gt;load_in_scope&lt;/code&gt; is a function defined in the C
code that compiles a file using the Bison parser to read through the file.
This saves a whole round trip to and from memory, making the program more
efficient and me less twitchy.&lt;/p&gt;

&lt;p&gt;I'm having major trouble getting the Ruby interpreter to do this.
Starting with a trunk checkout and working backwards from the
&lt;code&gt;Kernel#load&lt;/code&gt; method, I've been able to segfault at least
two-dozen different ways.  I think there are only two changes that are
necessary.  First, after &lt;code&gt;rb_load_file&lt;/code&gt; returns a &lt;code&gt;NODE
*&lt;/code&gt;, &lt;code&gt;rb_iseq_new&lt;/code&gt; must turn that into an instruction
sequence with a type other than &lt;code&gt;ISEQ_TYPE_TOP&lt;/code&gt; (perhaps
&lt;code&gt;ISEQ_TYPE_CLASS&lt;/code&gt; or &lt;code&gt;ISEQ_TYPE_EVAL&lt;/code&gt;?).  Second,
the instruction sequence can't be passed to &lt;code&gt;rb_iseq_eval&lt;/code&gt;
because that calls &lt;code&gt;vm_set_top_stack&lt;/code&gt;, so
&lt;code&gt;load_in_scope&lt;/code&gt; must call &lt;code&gt;vm_set_eval_stack&lt;/code&gt; and
&lt;code&gt;vm_exec&lt;/code&gt; itself.&lt;/p&gt;

&lt;p&gt;Am I insane?&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/rcrowley?a=Db1kczIE"&gt;&lt;img src="http://feeds.feedburner.com/~f/rcrowley?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/rcrowley?a=1PdVHyNZ"&gt;&lt;img src="http://feeds.feedburner.com/~f/rcrowley?i=1PdVHyNZ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rcrowley/~4/h8yd4GpriaE" height="1" width="1"/&gt;</content><feedburner:origLink>http://rcrowley.org/2008/10/26/hacking-the-ruby-interpreter</feedburner:origLink></entry><entry><title>Allspaw's playbook</title><link href="http://feedproxy.google.com/~r/rcrowley/~3/oXt7IxP0r_Y/allspaws-playbook" rel="alternate" /><id>http://rcrowley.org/2008/10/23/allspaws-playbook</id><published>2008-10-23T20:07:46-07:00</published><updated>2008-10-23T20:07:46-07:00</updated><author><name>Richard Crowley</name></author><content type="html">&lt;p&gt;I just finished the proper book part (appendices tomorrow) of Allspaw's &lt;a
href="http://www.kitchensoap.com/2008/10/06/wrote-a-book/"&gt;The Art of
Capacity Planning&lt;/a&gt;.  His playbook is now my playbook.  I've got more
than my fair share of charts and graphs (as all good engineers do) but
am to some degree at a loss in using them.  On one hand, the book presents
nothing but common sense and on the other, it has saved me endless
trial-and-error.  I've been reading it on the morning bus and have put
something into practice each day.&lt;/p&gt;

&lt;p&gt;Most of his advice on growing a service applies equally to launching a
service, albeit with a nasty chicken-and-egg problem that needs solving
before your boss will let you buy hardware.  By piping production traffic
into my dev environment I've been able, in stages at least, to put every
bit of my architecture under real production load (&lt;em&gt;empirical&lt;/em&gt;, as
per the Allspaw doctrine), piling on more and more until my work queues
go hockey stick.  (That'd be the &lt;em&gt;bad&lt;/em&gt; kind of hockey stick.)  &lt;a
href="http://flickr.com/photos/straup/2247714432/"&gt;The result speaks for
itself.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you, John Allspaw, for giving me a script to follow for the past
week and a half.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/rcrowley?a=wuoRl81a"&gt;&lt;img src="http://feeds.feedburner.com/~f/rcrowley?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/rcrowley?a=UjvJ41dn"&gt;&lt;img src="http://feeds.feedburner.com/~f/rcrowley?i=UjvJ41dn" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rcrowley/~4/oXt7IxP0r_Y" height="1" width="1"/&gt;</content><feedburner:origLink>http://rcrowley.org/2008/10/23/allspaws-playbook</feedburner:origLink></entry><entry><title>Updates to my street sweeping app</title><link href="http://feedproxy.google.com/~r/rcrowley/~3/0z6iFpmy2Q8/updates-to-my-street-sweeping-app" rel="alternate" /><id>http://rcrowley.org/2008/09/21/updates-to-my-street-sweeping-app</id><published>2008-09-21T19:51:56-07:00</published><updated>2008-09-21T19:51:56-07:00</updated><author><name>Richard Crowley</name></author><content type="html">&lt;p&gt;It's been a long time coming but I've finally updated &lt;a
href="http://car.rcrowley.org/"&gt;Where's my car?&lt;/a&gt; to take recent updates
over at &lt;a href="http://gispubweb.sfgov.org/website/sfviewer/INDEX.htm"&gt;SF
GIS&lt;/a&gt; into account.  They've augmented the street sweeping schedule in
most places to include something to the effect of "Effective 8/25/2008,
1st &amp; 3rd Tuesday only" which will reduce the "false positive" problem with
the site.  Now the site will be very explicit about the date and time you
should move your car instead of relying on "Mon 9AM" to get the point
across.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/rcrowley?a=rmBhbeDq"&gt;&lt;img src="http://feeds.feedburner.com/~f/rcrowley?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/rcrowley?a=Yn5FI4PZ"&gt;&lt;img src="http://feeds.feedburner.com/~f/rcrowley?i=Yn5FI4PZ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rcrowley/~4/0z6iFpmy2Q8" height="1" width="1"/&gt;</content><feedburner:origLink>http://rcrowley.org/2008/09/21/updates-to-my-street-sweeping-app</feedburner:origLink></entry></feed>
