<?xml version="1.0" encoding="iso-8859-1" ?>
<rss version="2.0" 
   xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" 
   xmlns:html="http://www.w3.org/1999/html" 
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
   xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
<channel>
   <title>Extra Cheese</title>
   <link>http://blog.extracheese.org</link>
   <description>Gary Bernhardt's blog</description>
   <language>en</language>
   <copyright>Copyright 2007 Gary Bernhardt</copyright>
   <ttl>60</ttl>
   <pubDate>Fri, 30 May 2008 17:56 GMT</pubDate>
   <managingEditor>gary.bernhardt at gmail</managingEditor>
   <generator>PyBlosxom http://pyblosxom.sourceforge.net/ 1.4.2 8/16/2007</generator>
<item>
   <title>Processes spawn faster than threads?</title>
   <guid isPermaLink="false">2008/05/processes-spawn-faster-than-threads</guid>
   <link>http://blog.extracheese.org/2008/05/processes-spawn-faster-than-threads.html</link>
   <description><![CDATA[

<p>In general, processes take longer to start than threads.  This makes sense
if you think about it - a thread lives within the memory space of its parent
process, so it takes less work to set one up.  (This is a gross
oversimplification, but to be honest I find the details of process management
incredibly uninteresting in 2008.)  I assumed that this difference would hold
for the Python processing module.  Apparently it doesn't, at least on Mac OS
X.  Surprise!</p>

<pre><code>Spawning 100 children with Thread took 1.04s
Spawning 100 children with Process took 0.60s</code></pre>

<p>The above result is for starting and joining the children serially.  I get
the same results in all of these variations:</p>

<ul>
    <li>Starting them all at once, then joining them all at once.</li>
    <li>Using 10 children or 1,000 children.</li>
    <li>Having each child sleep for one second (to ensure that they're all
    actually alive at the same time).</li>
</ul>

<p>I don't know whether this is due to goodness in OS X, or processing, or
fork(), or just Unix in general.  In any case, it's very good news.  I'd
dismissed processing for use on the client side of <a
    href="http://bitbacker.com">BitBacker</a> because "process management is
hard and they're too heavyweight."  Clearly at least one of those complaints
is invalid; maybe the other is as well.  It would be a wonderful relief if I
could use processes.  I'm going to need parallelization of one form or another
soon, and I'm definitely not going to start sprinkling threads around.  Only
madness lies down that path.</p>

<p>Here's the code that generated those results, in case you're
interested:</p>

<pre><code>import time, threading, processing
for cls in [threading.Thread, processing.Process]:
    start = time.time()
    for _ in range(100):
        child = cls(target=lambda: None)
        child.start()
        child.join()
    print 'Spawning 100 children with %s took %.2fs' % (
        cls.__name__, time.time() - start)</code></pre>


]]></description>
   <category domain="http://blog.extracheese.org">/2008/05</category>
   <pubDate>Fri, 30 May 2008 17:56 GMT</pubDate>
</item>
<item>
   <title>Add me on twitter!</title>
   <guid isPermaLink="false">2008/05/add-me-on-twitter</guid>
   <link>http://blog.extracheese.org/2008/05/add-me-on-twitter.html</link>
   <description><![CDATA[
<p>I've been twittering for a while, so I guess it's safe to link to my
Twitter from here.  And since I'm doing that, I may as well do a few
others:</p>

<ul>
    <li><a href="http://twitter.com/garybernhardt">At Twitter</a></li>
    <li><a href="http://www.last.fm/user/keil">At last.fm</a></li>
    <li><a href="http://del.icio.us/gary.bernhardt">At del.icio.us</a></li>
    <li><a
        href="http://www.librarything.com/catalog/garybernhardt">At LibraryThing</a>
    (I'm still slowly adding my books.)</li>
</ul>

<p>These are the only social sites I use regularly.  You should friend me on
them!</p>


]]></description>
   <category domain="http://blog.extracheese.org">/2008/05</category>
   <pubDate>Wed, 28 May 2008 22:22 GMT</pubDate>
</item>
<item>
   <title>Shell Meme Wins</title>
   <guid isPermaLink="false">2008/04/shell-meme-wins</guid>
   <link>http://blog.extracheese.org/2008/04/shell-meme-wins.html</link>
   <description><![CDATA[
<p>My most common shell commands:</p>
<pre><code>171 hg
144 fg
77 rm
71 ls
38 cd
28 vi
24 nosetests
17 killall
15 tissue
15 python
</code></pre>

<p>I tend to keep Vim open for a long
time, running many commands from within it.  That's why I don't have lots of
task switching like <a
href="http://exilejedi.livejournal.com/198371.html">Mike</a>.  I learned Emacs
before Vim, so blame it on that.  I also usually run tests from within Vim;
otherwise nosetests would definitely be #1.</p>

<p>Tissue is a ticketing system I've been working on.  It's super simple - the
whole ticket database is stored in a single plaintext file.  The idea is to
fit in with DVCSes like Mercurial better.  Having a single monolithic Trac
instance breaks down when you have dozens of repositories, each of which may
have certain tickets fixed or not.  By storing the ticket database in a
plaintext file within the repository, you get (1) explicit ties between code
fixes and ticket changes, and (2) free merging of modified tickets when the
corresponding code merge happens.  I'm about to switch <a
href="http://bitbacker.com">BitBacker</a> from Trac to this, so it will
hopefully get released some time.</p>


]]></description>
   <category domain="http://blog.extracheese.org">/2008/04</category>
   <pubDate>Fri, 11 Apr 2008 21:42 GMT</pubDate>
</item>
<item>
   <title>Human-Readable Encryption Keys</title>
   <guid isPermaLink="false">2007/12/human-readable-encryption-keys</guid>
   <link>http://blog.extracheese.org/2007/12/human-readable-encryption-keys.html</link>
   <description><![CDATA[
<p>For <a href="http://bitbacker.com">BitBacker</a>, we use 128-bit AES
encryption, which means our keys are really long and annoying - 32 characters
long when printed in hex.  And not only do the users sometimes have to type
them in, but they have to write them down on paper.  (We can't store the key on
our servers because then we'd be able to read the user's files; and we
obviously can't trust it to their hard drive because that's what we're backing
up.)</p>

<p>Somehow, we have to present these random 128-bit keys to the user, and I
think I've found a pretty good way.  We use RFC 1751, which defines a
"Convention for Human-Readable 128-bit Keys" -  basically just a mapping of
blocks of bits to strings of English words.  Here's an example in Python using
the RFC 1751 module in <a
href="http://www.amk.ca/python/code/crypto">PyCrypto</a>:</p>

<pre><code>>>> key = os.urandom(16) # Generate 16 random bytes (128 bits)
>>> bin_to_hex(key) # Show the key in hex (32 characters)
'61aa60e43a5e7fdb4b86a4897b52a0dc'
>>> y = RFC1751.key_to_english(key)
>>> y # Show the pass phrase version of the key
'BUSY BARN RUB DOLE TAUT TOOK ALTO PRY KIT WALL MUG CURT'
>>> # The transformation is always reversible
>>> bin_to_hex(RFC1751.english_to_key(y))
'61aa60e43a5e7fdb4b86a4897b52a0dc'
</code></pre>

<p>The keys are still *very* long, of course, and this is unavoidable for our
application.  But when translated to words, I think it's easier to write them
down or type them in without making a mistake.  The image below shows
BitBacker giving me a pass phrase.  (This feature hasn't even gone into beta
yet - it's little more than a mockup.  So please don't judge it too
harshly!)</p>

<a href="/2007/12/BitBacker-pass-phrase.png"><img
src="/2007/12/BitBacker-pass-phrase.png"
alt="Screen shot of BitBacker's pass phrase handling"/></a>

<p>When the user clicks "Continue" here, BitBacker actually makes him re-enter
the generated pass phrase he wrote down.  To be honest, BitBacker's pass
phrase handling is quite annoying.  But that's a heck of a lot better than
losing your pass phrase, which would make your backups inaccessible!  This is
the one place in all of BitBacker that isn't optimized for "least user
annoyance".  Encryption keys are just <i>way</i> too important to mess around
with, and I think that most existing software is far too lax with them
(including BitBacker's competitors).</p>

<p>(This was derived from a comment I left on Jeff Atwood's "<a
href="http://www.codinghorror.com/blog/archives/001021.html?r=19656">Software
Registration Keys</a>" post.)</p>


]]></description>
   <category domain="http://blog.extracheese.org">/2007/12</category>
   <pubDate>Sat, 29 Dec 2007 00:12 GMT</pubDate>
</item>
<item>
   <title>My blog woes have been soothed</title>
   <guid isPermaLink="false">2007/12/my-blog-woes-have-been-soothed</guid>
   <link>http://blog.extracheese.org/2007/12/my-blog-woes-have-been-soothed.html</link>
   <description><![CDATA[
<p>It seems I've mostly solved my <a
    href="http://blog.extracheese.org/2007/12/blog-woes.html">"blog woes"</a>.
I got some quite helpful replies (still visible on <a
    href="https://www.blogger.com/comment.g?blogID=6753084968628985846&amp;postID=908827919673100974">Blogger</a>,
although the comments didn't come over to my new blog).  I also got emails
from <a href="http://www.bluesock.org/~willg/">Will Guaraldi</a> about <a
    href="http://pyblosxom.sourceforge.net/">PyBlosxom</a>, and from <a
    href="http://www.daltonlp.com/">Lloyd Dalton</a> about <a
    href="http://www.daltonlp.com/blog_my">blog_my</a>.</p>

<p>I took at least a brief look at each system mentioned in the comments and
emails, but I decided on PyBlosxom.  If you're reading this in a web browser,
what you're seeing is PyBlosxom rendering a theme I ported from Tumblr, with
all of my old Blogger blog's content imported.  Quite frankensteinian indeed,
as far as blogs go.</p>

<p>It turns out that my impression of PyBlosxom's size when I wrote my "blog
woes" post was a bit off - I didn't realize just how little functionality
resides in the core.  It's pretty slim, but with a decent selection of
plugins.  I only needed <a
    href="http://pyblosxom.sourceforge.net/blog/registry/meta/tags">tags</a>,
<a
    href="http://pyblosxom.sourceforge.net/blog/registry/archives/wbgarchives">wbgarchives</a>,
and <a
    href="http://pyblosxom.sourceforge.net/blog/registry/date/metadate">metadate</a>,
but there are plenty more for those who want more features.  With the tag and
metadate plugins, I managed to keep my blog posts in almost exactly the format
I've always used, so that was nice.</p>

<p>PyBlosxom nicely solves my biggest concern, which I didn't explicitly state
in my original post: I want to keep all of the files related to my blog in a
<a href="http://www.selenic.com/mercurial">Mercurial</a> repository.  I've
succeeded in that - my entire blog is in Mercurial now.  That includes
configuration files, the .htaccess file, the template, the entries, and even
the queue of unfinished entries.  If I ever need to, I should be able to move
the blog to another host in a matter of minutes.  Not that I ever intend to
leave <a href="http://www.webfaction.com/?affiliate=grb">WebFaction</a>
(note: that's an affiliate link), which is where it's happily hosted
now.</p>

<p>With that all out of the way, hopefully I can quit the detestable practice
of metablogging, which I'd managed to avoid for my entire first year.  Thanks
to everyone who made a suggestion, and special thanks to the PyBlosxom
developers.</p>


]]></description>
   <category domain="http://blog.extracheese.org">/2007/12</category>
   <pubDate>Sun, 23 Dec 2007 00:05 GMT</pubDate>
</item>
</channel>
</rss>
