<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-5664072085694046073</id><updated>2010-01-03T22:30:10.294-08:00</updated><title type='text'>Personal Web Page</title><subtitle type='html'></subtitle><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/posts/default'/><link rel='alternate' type='text/html' href='http://logn.org/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://logn.org/atom.xml'/><author><name>Jared Brothers</name><uri>http://www.blogger.com/profile/04481914185463551406</uri><email>brothers@logn.org</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>8</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5664072085694046073.post-5382001461532894831</id><published>2009-07-30T08:06:00.000-07:00</published><updated>2009-08-04T18:44:08.753-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='lazy'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='papers'/><title type='text'>Lazy Primes Sieve in Python</title><content type='html'>I read this interesting paper, &lt;a href="http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf"&gt;The Genuine Sieve of Eratosthenes&lt;/a&gt; (PDF) by Melissa O'Neill, when it was discussed on &lt;a href="http://lambda-the-ultimate.org/node/3127"&gt;Lambda the Ultimate&lt;/a&gt;.  I came back to look at it again today because I wanted to improve my Haskell fluency, which I only seem to exercise when I read papers like this.  I decided to try to correctly construe the Haskell code in the paper by implementing the algorithms in Python.  I focused on reproducing the laziness but not the functional style because I could substitute iterators for lazy lists but had to use conventional control structures for all the pattern matching and tail calls.&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;# Author: Jared Brothers&lt;br /&gt;# &lt;br /&gt;# A Python version of the Haskell code from&lt;br /&gt;# "The Genuine Sieve of Eratosthenes"&lt;br /&gt;# www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf&lt;br /&gt;#&lt;br /&gt;import heapq, itertools, operator&lt;br /&gt;&lt;br /&gt;def sieve(xs):&lt;br /&gt;    """Generate the prime numbers, given an iterable of candidate numbers.&lt;br /&gt;    Cross off multiples of prime numbers incrementally using iterators."""&lt;br /&gt;    table = []&lt;br /&gt;    while 1:&lt;br /&gt;        x = xs.next()&lt;br /&gt;        if table == [] or x &lt; table[0][0]:&lt;br /&gt;            yield x&lt;br /&gt;            xs, ys = itertools.tee(xs)&lt;br /&gt;            timesx = (lambda x: lambda y: x*y)(x)&lt;br /&gt;            heapq.heappush(table, (x**2, itertools.imap(timesx, ys)))&lt;br /&gt;        else:&lt;br /&gt;            while table[0][0] &lt;= x:&lt;br /&gt;                heapq.heapreplace(table, (table[0][1].next(), table[0][1]))&lt;br /&gt;&lt;br /&gt;def wheel(factors=[2, 3, 5, 7], next=11):&lt;br /&gt;    """Generate the distances between numbers not divisible by a list of small&lt;br /&gt;    primes, from the next prime up to the product of the list."""&lt;br /&gt;    circumference = reduce(operator.mul, factors)&lt;br /&gt;    prev = next&lt;br /&gt;    next += 1&lt;br /&gt;    end = next + circumference &lt;br /&gt;    while next &lt; end:&lt;br /&gt;        if not any(next % factor == 0 for factor in factors):&lt;br /&gt;            yield next - prev&lt;br /&gt;            prev = next&lt;br /&gt;        next += 1&lt;br /&gt;&lt;br /&gt;def spin(factors=[2, 3, 5, 7], next=11):&lt;br /&gt;    """Generate candidates by making a wheel and cycling through it."""&lt;br /&gt;    for gap in itertools.cycle(wheel(factors, next)):&lt;br /&gt;        yield next&lt;br /&gt;        next += gap&lt;br /&gt;&lt;br /&gt;def primes(k=5):&lt;br /&gt;    """Generate primes with the sieve and wheel factorization, which filters&lt;br /&gt;    multiples of the first k primes."""&lt;br /&gt;    smallprimes = list(itertools.islice(sieve(itertools.count(2)), k + 1))&lt;br /&gt;    factors = smallprimes[:-1]&lt;br /&gt;    next = smallprimes[-1]&lt;br /&gt;    return itertools.chain(factors, sieve(spin(factors, next)))&lt;br /&gt;&lt;/pre&gt;&lt;/tt&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5664072085694046073-5382001461532894831?l=logn.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/5382001461532894831/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://logn.org/2009/07/lazy-primes-sieve-in-python.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/posts/default/5382001461532894831'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/posts/default/5382001461532894831'/><link rel='alternate' type='text/html' href='http://logn.org/2009/07/lazy-primes-sieve-in-python.html' title='Lazy Primes Sieve in Python'/><author><name>Jared Brothers</name><uri>http://www.blogger.com/profile/04481914185463551406</uri><email>brothers@logn.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10411452212119309262'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5664072085694046073.post-1065777317697717808</id><published>2009-06-24T09:21:00.000-07:00</published><updated>2009-06-26T20:17:59.892-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='deployment'/><category scheme='http://www.blogger.com/atom/ns#' term='puppet'/><category scheme='http://www.blogger.com/atom/ns#' term='subversion'/><title type='text'>Code deployment with Puppet</title><content type='html'>I fielded a question from Matt on the &lt;a href="http://lists.nycbug.org/mailman/listinfo/talk"&gt;NYC*BSD&lt;/a&gt; discussion list about using Puppet to do code deployment from a subversion repository to his web servers.  Some time ago I came up with a nice way to do this but hadn't published the code for it anywhere.  This works for me, but tmtowtdi and ymmv.&lt;br /&gt;&lt;br /&gt;I have developers create a tag for the version they want deployed, then I define in the web server manifest (which is in subversion itself) an instance of a custom resource that manages subversion working copies given the url of the repository,  which branch to use, and the path of the copy directory.&lt;br /&gt;&lt;br /&gt;Using a working copy rather than an export makes upgrading code fast but leaves &lt;tt&gt;.svn&lt;/tt&gt; directories lying around, so I have Apache configured to hide them with 404s.  The code is short and simple, since it just abuses &lt;tt&gt;exec&lt;/tt&gt; to run the &lt;tt&gt;svn&lt;/tt&gt; binary to do a check out, check which version is in place, and switch to a newer branch if necessary.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;tt&gt;&lt;br /&gt;# web-foo.pp&lt;br /&gt;class web-foo {&lt;br /&gt;   if $branch {&lt;br /&gt;       subversion::workingcopy { foo:&lt;br /&gt;           repourl =&gt; 'http://svn.example.com/foo/tags',&lt;br /&gt;           branch =&gt; "$branch",&lt;br /&gt;           copydir =&gt; '/www/foo',&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# modules/subversion/manifests/init.pp&lt;br /&gt;class subversion {&lt;br /&gt;   package { subversion:&lt;br /&gt;       ensure =&gt; installed,&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;define subversion::workingcopy ($repourl, $branch, $copydir) {&lt;br /&gt;   include subversion&lt;br /&gt;   file { "$copydir":&lt;br /&gt;       owner =&gt; apache, group =&gt; apache, mode =&gt; 755,&lt;br /&gt;       ensure =&gt; directory,&lt;br /&gt;   }&lt;br /&gt;   # initial check out&lt;br /&gt;   exec { "svnco-$name":&lt;br /&gt;       command =&gt; "/usr/bin/svn co --non-interactive $repourl/$branch $copydir/$name",&lt;br /&gt;       creates =&gt; "$copydir/$name/.svn",&lt;br /&gt;       require =&gt; [Package[subversion], File["$copydir"]],&lt;br /&gt;   }&lt;br /&gt;   # switch branches&lt;br /&gt;   exec { "svnswitch-$name":&lt;br /&gt;       command =&gt; "/usr/bin/svn switch --non-interactive $repourl/$branch $copydir/$name",&lt;br /&gt;       unless =&gt; "/usr/bin/svn info $copydir/$name|/bin/grep -q 'URL:.*$branch\$'",&lt;br /&gt;       require =&gt; [Package[subversion], File["$copydir"], Exec["svnco-$name"]],&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/tt&gt;&lt;br /&gt;&lt;br /&gt;When the developers want me to deploy a new tagged version, I just change the value of the &lt;tt&gt;$branch&lt;/tt&gt; variable to the name of the new tag.  I use an external classifier, &lt;a href="http://github.com/adamhjk/iclassify/tree/master"&gt;iClassify&lt;/a&gt;, which is a Ruby on Rails application that serves as a nice tagging interface for mapping nodes to classes and setting the values of variables.  On its next run, Puppet sees that the working copy is the wrong version and switches to the new one.  So, basically this provides declarative configuration of what code is on which servers with point and click deployment of new versions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5664072085694046073-1065777317697717808?l=logn.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/1065777317697717808/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://logn.org/2009/06/code-deployment-with-puppet.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/posts/default/1065777317697717808'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/posts/default/1065777317697717808'/><link rel='alternate' type='text/html' href='http://logn.org/2009/06/code-deployment-with-puppet.html' title='Code deployment with Puppet'/><author><name>Jared Brothers</name><uri>http://www.blogger.com/profile/04481914185463551406</uri><email>brothers@logn.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10411452212119309262'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5664072085694046073.post-542726299595639227</id><published>2009-01-04T10:05:00.000-08:00</published><updated>2009-03-22T16:58:17.453-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='combinatorics'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Domino counting problem</title><content type='html'>My brother is writing a combinatorics paper about playing with dominoes.  Pure mathematics is a lot of fun that way, but with more Hamiltonian paths of graphs embedded on a torus.  Here is a Python script I wrote for him last night to solve a counting problem.&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;# Author: Jared Brothers &lt;brothers@logn.org&gt;&lt;br /&gt;# Find the orderings of a set of dominoes such that&lt;br /&gt;# adjacent dominoes share a number and the other two&lt;br /&gt;# numbers differ by one.&lt;br /&gt;&lt;br /&gt;def search(start):&lt;br /&gt;    """ Depth first search, generating all solutions. """&lt;br /&gt;    fringe = [start]&lt;br /&gt;    while fringe:&lt;br /&gt;        s = fringe.pop()&lt;br /&gt;        if s.check():&lt;br /&gt;            yield s&lt;br /&gt;        fringe.extend(s.successors())&lt;br /&gt;&lt;br /&gt;class state():&lt;br /&gt;    """ A state in the search space.  """&lt;br /&gt;    def __init__(self, d, r):&lt;br /&gt;        """ The ordered dominoes are in done (list),&lt;br /&gt;        and the unordered dominoes are in rest (set). """&lt;br /&gt;        self.done = d&lt;br /&gt;        self.rest = r&lt;br /&gt;&lt;br /&gt;    def __str__(self):&lt;br /&gt;        return str(self.done)&lt;br /&gt;&lt;br /&gt;    def check(self):&lt;br /&gt;        """ Is this a solution? """&lt;br /&gt;        return not self.rest&lt;br /&gt;&lt;br /&gt;    def successors(self):&lt;br /&gt;        """ The states you can get to by moving a domino from rest to done. """&lt;br /&gt;        if self.done:&lt;br /&gt;            # Try only dominoes adjacent to the previous one,&lt;br /&gt;            a,b = self.done[-1]&lt;br /&gt;            a1 = (a + 1) % n&lt;br /&gt;            a2 = (a - 1) % n&lt;br /&gt;            b1 = (b + 1) % n&lt;br /&gt;            b2 = (b - 1) % n&lt;br /&gt;            adjs = set([(a,b1), (b1,a), (a,b2), (b2,a), (b,a1), (a1,b), (b,a2), (a2,b)])&lt;br /&gt;            for x in self.rest.intersection(adjs):&lt;br /&gt;                d = self.done[:]&lt;br /&gt;                d.append(x)&lt;br /&gt;                r = self.rest.copy()&lt;br /&gt;                r.discard(x)&lt;br /&gt;                yield state(d, r)&lt;br /&gt;        else:&lt;br /&gt;            # or all the rest if nothing has been done yet.&lt;br /&gt;            for x in sorted(self.rest):&lt;br /&gt;                d = [x]&lt;br /&gt;                r = self.rest.copy()&lt;br /&gt;                r.discard(x)&lt;br /&gt;                yield state(d, r)&lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;    n = 7 # The number of numbers. The number of dominoes is sum(range(n + 1)).&lt;br /&gt;    start = state([], set((a, b) for a in range(n) for b in range(a + 1)))&lt;br /&gt;    for s in search(start):&lt;br /&gt;        print(s)&lt;br /&gt;&lt;/pre&gt;&lt;/tt&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5664072085694046073-542726299595639227?l=logn.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/542726299595639227/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://logn.org/2009/01/domino-counting-problem.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/posts/default/542726299595639227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/posts/default/542726299595639227'/><link rel='alternate' type='text/html' href='http://logn.org/2009/01/domino-counting-problem.html' title='Domino counting problem'/><author><name>Jared Brothers</name><uri>http://www.blogger.com/profile/04481914185463551406</uri><email>brothers@logn.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10411452212119309262'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5664072085694046073.post-1706532636416202402</id><published>2008-12-17T12:06:00.000-08:00</published><updated>2009-01-02T08:21:12.513-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bukowski'/><category scheme='http://www.blogger.com/atom/ns#' term='puppet'/><title type='text'>Pull A String, A Puppet Moves</title><content type='html'>each man must realize&lt;br /&gt;that it can all disappear very&lt;br /&gt;quickly:&lt;br /&gt;the cat, the woman, the job,&lt;br /&gt;the front tire,&lt;br /&gt;the bed, the walls, the&lt;br /&gt;room; all our necessities&lt;br /&gt;including love,&lt;br /&gt;rest on foundations of sand -&lt;br /&gt;and any given cause,&lt;br /&gt;no matter how unrelated:&lt;br /&gt;the death of a boy in Hong Kong&lt;br /&gt;or a blizzard in Omaha …&lt;br /&gt;can serve as your undoing.&lt;br /&gt;all your chinaware crashing to the&lt;br /&gt;kitchen floor, your girl will enter&lt;br /&gt;and you’ll be standing, drunk,&lt;br /&gt;in the center of it and she’ll ask:&lt;br /&gt;my god, what’s the matter?&lt;br /&gt;and you’ll answer: I don’t know,&lt;br /&gt;I don’t know …&lt;br /&gt;&lt;br /&gt;-Charles Bukowski&lt;br /&gt;&lt;br /&gt;from &lt;a href="http://www.amazon.com/Burning-Water-Drowning-Charles-Bukowski/dp/087685191X"&gt;Burning in Water Drowning in Flame&lt;/a&gt;.  Not to be confused with: &lt;br /&gt;&lt;a href="http://www.amazon.com/Pulling-Strings-Puppet-Configuration-Management/dp/1590599780"&gt;Pulling Strings With Puppet: Configuration Management Made Easy&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5664072085694046073-1706532636416202402?l=logn.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/1706532636416202402/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://logn.org/2008/12/pull-string-puppet-moves.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/posts/default/1706532636416202402'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/posts/default/1706532636416202402'/><link rel='alternate' type='text/html' href='http://logn.org/2008/12/pull-string-puppet-moves.html' title='Pull A String, A Puppet Moves'/><author><name>Jared Brothers</name><uri>http://www.blogger.com/profile/04481914185463551406</uri><email>brothers@logn.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10411452212119309262'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5664072085694046073.post-1686912984711798500</id><published>2008-12-09T08:42:00.000-08:00</published><updated>2009-09-08T11:52:27.096-07:00</updated><title type='text'>This superblock wants to tell you something</title><content type='html'>The problem is, when you reboot a Linux server, it will probably be back up quickly, but it may want to check all the filesystems, which takes substantially longer.  How do you know what to expect?  The conditions that can trigger a fsck (the time and number of mounts since the last one) are stored in the superblock, which is annoying to inspect before planning an outage.&lt;br /&gt;&lt;br /&gt;It doesn't seem worth doing the checks myself every time, but it would be nice to know.  I didn't follow up on this until someone else complained about it, convincing me there was enough demand to justify a better user interface.  Now I install the following script as a daily cron job with standard output redirected to the message of the day file.  I decided to use a few older idioms to support Python 1.5.2 installed on Red Hat 7.3 (Valhalla).  I would have just used awk if it had a decent date parsing library.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;# Author: Jared Brothers &lt;brothers@logn.org&gt;&lt;br /&gt;#&lt;br /&gt;# Which ext2/3 filesystems will require a fsck, delaying the next reboot?&lt;br /&gt;#&lt;br /&gt;# Inspect the superblock of mounted filesystems with debugfs(8)&lt;br /&gt;# to check whether the max mount count or time interval have been&lt;br /&gt;# exceeded.  List the overdue filesystems' mount points.&lt;br /&gt;#&lt;br /&gt;&lt;br /&gt;import os, sys, re, time, popen2, string&lt;br /&gt;fsck = []&lt;br /&gt;debug = 0&lt;br /&gt;name = os.path.basename(sys.argv[0])&lt;br /&gt;&lt;br /&gt;if os.geteuid() != 0:&lt;br /&gt;    sys.exit(name + ": not run as root")&lt;br /&gt;&lt;br /&gt;fd1, fd0, fd2 = popen2.popen3("/bin/mount")&lt;br /&gt;for line in fd1.readlines():&lt;br /&gt;&lt;br /&gt;    if re.search("type (ext2|ext3)", line):&lt;br /&gt;        fields = string.split(line)&lt;br /&gt;        dev = fields[0]&lt;br /&gt;        if debug: print("dev: " + dev)&lt;br /&gt;&lt;br /&gt;        fs = fields[2]&lt;br /&gt;        if debug: print("fs: " + fs)&lt;br /&gt;&lt;br /&gt;        fd1, fd0, fd2 = popen2.popen3("/sbin/debugfs -R show_super_stats " + dev)&lt;br /&gt;        for line in fd1.readlines():&lt;br /&gt;            fields = string.split(line)&lt;br /&gt;&lt;br /&gt;            if re.search("^Mount count:", line):&lt;br /&gt;                count = int(fields[2])&lt;br /&gt;&lt;br /&gt;            if re.search("^Maximum mount count:", line):&lt;br /&gt;                max = int(fields[3])&lt;br /&gt;&lt;br /&gt;            if re.search("^Last checked:", line):&lt;br /&gt;                last = string.strip(string.join(fields[2:], " "))&lt;br /&gt;&lt;br /&gt;            if re.search("^Check interval:", line):&lt;br /&gt;                check = int(fields[2])&lt;br /&gt;&lt;br /&gt;        if max != -1:&lt;br /&gt;            left = max - count&lt;br /&gt;            if debug: print("left: " + str(left))&lt;br /&gt;&lt;br /&gt;        if check != 0:&lt;br /&gt;            next = time.mktime(time.strptime(last)) + check&lt;br /&gt;            if debug: print("next: " + time.asctime(time.localtime(next)))&lt;br /&gt;&lt;br /&gt;        if max != -1 and left &lt;= 0 or check != 0 and next &lt;= time.time():&lt;br /&gt;            fsck.append(fs)&lt;br /&gt;&lt;br /&gt;if len(fsck):&lt;br /&gt;    print("These ext2/3 filesystems are due for a fsck: "&lt;br /&gt;        + string.join(fsck, ", "))&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5664072085694046073-1686912984711798500?l=logn.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/1686912984711798500/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://logn.org/2008/12/this-superblock-wants-to-tell-you.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/posts/default/1686912984711798500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/posts/default/1686912984711798500'/><link rel='alternate' type='text/html' href='http://logn.org/2008/12/this-superblock-wants-to-tell-you.html' title='This superblock wants to tell you something'/><author><name>Jared Brothers</name><uri>http://www.blogger.com/profile/04481914185463551406</uri><email>brothers@logn.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10411452212119309262'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5664072085694046073.post-3727945107946207047</id><published>2008-11-24T19:30:00.001-08:00</published><updated>2009-08-18T21:08:36.718-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='halloween'/><category scheme='http://www.blogger.com/atom/ns#' term='old school'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><title type='text'>Assuming you have a terrycloth robe</title><content type='html'>On Halloween, I heard, "That guy is awesome," as someone passed me in the train station on my way to the office in the morning.  Arthur Dent is an effortless costume, so I'm surprised anyone was impressed.  You just wear your pyjamas all day and set the background of your phone to say "Don't Panic" in large friendly letters.  Maybe he thought I was dressed as &lt;a href="http://answers.yahoo.com/question/index?qid=20090204202321AAWtMkO"&gt;the Dude&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://logn.org/uploaded_images/Don't-Panic-795930.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 213px; height: 320px;" src="http://logn.org/uploaded_images/Don't-Panic-795925.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Just two things differentiate an iPhone from a canonical copy of The Hitchhiker's Guide to the Galaxy: our species' parochial travel habits and the all too limited lifespan of our cell phone batteries.  If we were to make the advances in physics and engineering necessary to produce cell phone batteries that last more than a day and interstellar travel that took less than a day, there would be huge demand for Lonely Exoplanet guides in the App Store.  &lt;br /&gt;&lt;br /&gt;But in the meantime, I recommend getting the free Z-machine interpreter iPhone application, &lt;a href="http://code.google.com/p/iphonefrotz/"&gt;Frotz&lt;/a&gt;, and trying to puzzle out Douglas Adam's brilliant Infocom game, also called &lt;a href="http://ifdb.tads.org/viewgame?id=ouv80gvsl32xlion"&gt;Hitchhiker's Guide to the Galaxy&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5664072085694046073-3727945107946207047?l=logn.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/3727945107946207047/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://logn.org/2008/11/assuming-you-have-terrycloth-robe.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/posts/default/3727945107946207047'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/posts/default/3727945107946207047'/><link rel='alternate' type='text/html' href='http://logn.org/2008/11/assuming-you-have-terrycloth-robe.html' title='Assuming you have a terrycloth robe'/><author><name>Jared Brothers</name><uri>http://www.blogger.com/profile/04481914185463551406</uri><email>brothers@logn.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10411452212119309262'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5664072085694046073.post-6751895177343143234</id><published>2008-11-20T16:30:00.001-08:00</published><updated>2008-11-20T17:22:37.436-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vista'/><category scheme='http://www.blogger.com/atom/ns#' term='google'/><category scheme='http://www.blogger.com/atom/ns#' term='anecdote'/><category scheme='http://www.blogger.com/atom/ns#' term='microsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>A Mac running Vista is a Sad Mac</title><content type='html'>My dad asked me recently what kind of small form-factor PC he should buy. My response was highly biased by my interest in his switching to a platform I have more experience with.  I'm not enthusiastic about offering desktop support, even for my family, but they could at least notice that I haven't used Windows much lately.&lt;br /&gt;&lt;br /&gt;  He's too set in his ways to switch to Linux, so I volunteered to buy him a Mac Mini and set it up to dual-boot Vista, in the hope he would eventually try out Leopard.  I had a copy of Vista that I won at a Microsoft recruiting event, which I subsequently failed to sell on eBay.  I had also won a redundant iPod Nano from Google in their &lt;a href="http://googleblog.blogspot.com/2008/10/google-treasure-hunt-winners-abound.html"&gt;Treasure Hunt&lt;/a&gt; contest.  Every Mac should come with a free iPod, so I pitched that in the deal too.&lt;br /&gt;&lt;br /&gt;  Next to all these software companies wasting perfectly good schwag on me, the saddest part of the story is that, from the resigned tone of his complaints about Vista, it sounds like he's going to keep running Windows.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5664072085694046073-6751895177343143234?l=logn.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/6751895177343143234/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://logn.org/2008/11/mac-running-vista-is-sad-mac.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/posts/default/6751895177343143234'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/posts/default/6751895177343143234'/><link rel='alternate' type='text/html' href='http://logn.org/2008/11/mac-running-vista-is-sad-mac.html' title='A Mac running Vista is a Sad Mac'/><author><name>Jared Brothers</name><uri>http://www.blogger.com/profile/04481914185463551406</uri><email>brothers@logn.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10411452212119309262'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5664072085694046073.post-1919730733184847704</id><published>2008-11-07T21:40:00.000-08:00</published><updated>2008-11-20T17:23:21.175-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unix'/><title type='text'>Something new every day, most days</title><content type='html'>I just found out less(1) does "tail -f".  And I thought it just went up more than more(1), but down too?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5664072085694046073-1919730733184847704?l=logn.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/1919730733184847704/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://logn.org/2008/11/something-new-every-day-most-days.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/posts/default/1919730733184847704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5664072085694046073/posts/default/1919730733184847704'/><link rel='alternate' type='text/html' href='http://logn.org/2008/11/something-new-every-day-most-days.html' title='Something new every day, most days'/><author><name>Jared Brothers</name><uri>http://www.blogger.com/profile/04481914185463551406</uri><email>brothers@logn.org</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='10411452212119309262'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry></feed>