<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link rel="hub" href="http://tumblr.superfeedr.com/" xmlns:atom="http://www.w3.org/2005/Atom"/><description>www: brianbeck.com
email: brian.beck@gmail.com
twitter: @ua6oxa
employer: BigDoor</description><title>Brian Beck’s Text Adventure</title><generator>Tumblr (3.0; @exogen)</generator><link>http://blog.brianbeck.com/</link><item><title>The Point and Those Who Miss It</title><description>&lt;p&gt;A lot has been said about &lt;a href="http://teddziuba.com/2011/10/node-js-is-cancer.html"&gt;Ted&amp;#8217;s successful troll&lt;/a&gt; and the &lt;a href="http://joshuakehn.com/2011/10/3/Diagnosis-No-Cancer.html"&gt;several&lt;/a&gt; &lt;a href="http://mathias-biilmann.net/posts/2011/10/is-haskell-the-cure"&gt;responses&lt;/a&gt; that seem to miss the point—including mine.&lt;/p&gt;

&lt;p&gt;To that I say: if a point is never properly made, can one truly miss it?&lt;/p&gt;

&lt;p&gt;There are two reasons people are benchmarking Fibonacci in response to Ted&amp;#8217;s post:&lt;/p&gt;

&lt;ol&gt;&lt;li&gt;Ted himself benchmarked it and concluded it was slow. This is wrong—it&amp;#8217;s comparatively fast. But nobody thinks this was his entire point. It wasn&amp;#8217;t. Let&amp;#8217;s move on.&lt;/li&gt;
&lt;li&gt;Because it&amp;#8217;s an order of magnitude faster, &lt;em&gt;every single one of Ted&amp;#8217;s clients&lt;/em&gt; in the &lt;code&gt;ab&lt;/code&gt; benchmark would receive a response before even a &lt;em&gt;single&lt;/em&gt; client of an equivalent Python or Ruby service, regardless of their level of concurrency. Even though each request blocked the next, it still would have far better throughput than your &lt;em&gt;typical&lt;/em&gt; Python or Ruby deployment. (This of course depends on which language runtime the deployment uses, that&amp;#8217;s why I&amp;#8217;m stressing &amp;#8220;typical.&amp;#8221;) This has everything to do with the speed of V8, and not Node&amp;#8217;s event-based I/O.&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;So even the demonstration of a blocked request pipeline was rather poor. Still want to blame anyone for missing the point?&lt;/p&gt;

&lt;p&gt;People are excited about Node because you can handle a large number of requests before even beginning to think about parallelization. If you start with a blazing fast runtime and request handler, you can put off parallelization until it matters. And it may never matter, because most web services are I/O-bound. Node also makes asynchronous programming very approachable.&lt;/p&gt;

&lt;p&gt;Taken out of context, Node&amp;#8217;s claim that &amp;#8220;nothing blocks&amp;#8221; can indeed be confusing. And I&amp;#8217;m not defending the claim that &amp;#8220;less-than-expert programmers are able to develop fast systems.&amp;#8221; But Ted deliberately took &amp;#8220;nothing blocks&amp;#8221; out of context. Node&amp;#8217;s site is very clear that it&amp;#8217;s talking about blocking I/O. For CPU-intensive tasks, &lt;a href="http://news.ycombinator.com/item?id=3065074"&gt;the Unix way is alive and well&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Running multiple Node processes to improve concurrency is not anti-Unix. It is in fact a widely-accepted approach, albeit one users are left to discover themselves with Node. Some people dismissed projects that serve this purpose, claiming that the introduction of third-party add-ons somehow invalidates the entire approach. Maybe we should stop using mod_python and mod_wsgi then, eh?&lt;/p&gt;

&lt;p&gt;Perhaps there are some less-than-expert programmers out there shooting themselves in the foot with Node and failing spectacularly to scale. But so far they seem to be mythical.&lt;/p&gt;

&lt;p&gt;If you want to read an article that &lt;em&gt;does&lt;/em&gt; make a great point about Node&amp;#8217;s concurrency—and concurrency in general—&lt;a href="http://functional-orbitz.blogspot.com/2011/10/your-favorite-language-is-probably.html"&gt;Anthony Fejes got it right&lt;/a&gt;.&lt;/p&gt;</description><link>http://blog.brianbeck.com/post/10997599091</link><guid>http://blog.brianbeck.com/post/10997599091</guid><pubDate>Mon, 03 Oct 2011 16:25:00 -0700</pubDate><category>node.js</category><category>javascript</category></item><item><title>Node.js Cures Cancer</title><description>&lt;p&gt;I apologize for the title. But it&amp;#8217;s no less accurate than this &lt;a href="http://teddziuba.com/"&gt;embarassing, poorly-reasoned article&lt;/a&gt; by Ted Dziuba. It&amp;#8217;s flamebait, but I couldn&amp;#8217;t resist. Sigh&amp;#8230;here we go.&lt;/p&gt;

&lt;p&gt;First, Ted takes issue with this claim on Node&amp;#8217;s homepage:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Almost no function in Node directly performs I/O, so the process never blocks. Because nothing blocks, less-than-expert programmers are able to develop fast systems.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;He then gives an example of a blocking function as some kind of weird disproof.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Here&amp;#8217;s a fun fact: every function call that does CPU work also blocks. This function, which calculates the n&amp;#8217;th Fibonacci number, will block the current thread of execution because it&amp;#8217;s using the CPU.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function fibonacci(n) {
  if (n &amp;lt; 2)
    return 1;
  else
    return fibonacci(n-2) + fibonacci(n-1);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;I think Ted might be confused about what exactly Node is. Node is not a language or a framework. &lt;strong&gt;Node is a small set of JavaScript modules bundled with a JavaScript runtime.&lt;/strong&gt; &amp;#8220;Almost no function in Node directly performs I/O&amp;#8221; means that most functions included in Node&amp;#8217;s built-in modules are asynchronous—they return as soon as possible and a callback handles the result. It doesn&amp;#8217;t mean that any JavaScript function you write won&amp;#8217;t block. It&amp;#8217;s still JavaScript with normal semantics.&lt;/p&gt;

&lt;p&gt;The first thing Ted does to disprove this claim is fire up Node&amp;#8217;s single-threaded HTTP server in a single process and calculate &lt;code&gt;fibonacci(40)&lt;/code&gt; on every request. Here&amp;#8217;s his conclusion when the request takes 5.6 seconds to complete:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;5 second response time. Cool. So we all know JavaScript isn&amp;#8217;t a terribly fast language, but why is this such an indictment?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I don&amp;#8217;t know Ted, why is it? Maybe let&amp;#8217;s try the same thing in Python and Ruby so we can see just how terribly fast other languages are by comparison. For reference, Ted&amp;#8217;s example takes 8 seconds on my machine.&lt;/p&gt;

&lt;p&gt;Python:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from wsgiref.util import setup_testing_defaults
from wsgiref.simple_server import make_server

def fibonacci(n):
    if n &amp;lt; 2:
        return 1
    else:
        return fibonacci(n-2) + fibonacci(n-1)

def fibonacci_app(environ, start_response):
    status = '200 OK'
    headers = [('Content-Type', 'text/plain')]
    start_response(status, headers)
    return [str(fibonacci(40))]

make_server('', 1337, fibonacci_app).serve_forever()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Result:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ time curl http://localhost:1337/
165580141
real    1m48.732s
user    0m0.009s
sys     0m0.007s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;1 minute 48 second response time. Cool. This is the fastest it got after multiple runs, by the way. The results are the same for any Python web server because, surprise, it&amp;#8217;s measuring the speed of Python. Just like Ted&amp;#8217;s example is measuring the speed of V8.&lt;/p&gt;

&lt;p&gt;Ruby:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;require 'rubygems'
require 'mongrel'

def fibonnaci(n)
    if n &amp;lt; 2
        1
    else
        fibonnaci(n - 2) + fibonnaci(n - 1)
    end
end

class FibonacciHandler &amp;lt; Mongrel::HttpHandler
   def process(request, response)
     response.start(200) do |head,out|
       head["Content-Type"] = "text/plain"
       out.write(fibonnaci(40))
     end
   end
end

h = Mongrel::HttpServer.new("127.0.0.1", "1337")
h.register("/", FibonacciHandler.new)
h.run.join
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Result:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ time curl http://localhost:1337/
165580141
real    3m18.429s
user    0m0.011s
sys     0m0.009s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;3 minute 18 second response time. Cool.&lt;/p&gt;

&lt;p&gt;What exactly did he expect to happen in this case? We wrote a function that &lt;em&gt;does&lt;/em&gt; block, and told Node to call it on every request. How could Node&amp;#8217;s claim that &amp;#8220;almost no function in Node directly performs I/O, so the process never blocks&amp;#8221; possibly have any bearing at all on this result?&lt;/p&gt;

&lt;p&gt;Maybe the claim that &amp;#8220;less-than-expert programmers are able to develop fast systems&amp;#8221; is misleading, but so far it&amp;#8217;s actually sounding almost reasonable. Getting the response time down to 5 seconds was effortless, after all&amp;#8230;&lt;/p&gt;

&lt;p&gt;Ted then discredits Node for disobeying &amp;#8220;the Unix way.&amp;#8221; This indeed sounds pretty lamentable until you realize he just means that Node doesn&amp;#8217;t ship with a CGI module, which is true.&lt;/p&gt;

&lt;p&gt;How odd, then, that Node&amp;#8217;s lack of built-in CGI support hasn&amp;#8217;t caused an exodus en masse. People still seem to be getting along just fine without it. And even if they weren&amp;#8217;t, nothing is stopping anybody from developing a CGI module for Node. So why haven&amp;#8217;t they?&lt;/p&gt;

&lt;p&gt;One reason could be that &lt;a href="http://zgadzaj.com/benchmarking-nodejs-basic-performance-tests-against-apache-php"&gt;Node&amp;#8217;s built-in web server can easily outperform Apache—even in high-concurrency tests&lt;/a&gt;. This is apparently dismissible since it violates &amp;#8220;the Unix way&amp;#8221; of separation of responsibility. All the people who are getting stuff done with Node should just drop what they&amp;#8217;re doing, because according to Ted they&amp;#8217;re conceptually impure.&lt;/p&gt;

&lt;p&gt;Never mind that most developers will never need the scale that loosely coupled services would provide.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Conceptually, this is how any web application architecture that&amp;#8217;s not cancer still works today: you have a web server program that&amp;#8217;s job is to accept incoming requests, parse them, and figure out the appropriate action to take. That can be either serving a static file, running a CGI script, proxying the connection somewhere else, whatever. The point is that the HTTP server isn&amp;#8217;t the same entity doing the application work.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Look, I totally agree with this. From an architectural standpoint, it&amp;#8217;s the way to go. I&amp;#8217;m sure someday, Node will get its own equivalent of WSGI for Python and Rack for Ruby. That will be an exciting time. But nobody seems to be in a hurry to get there. [Update: Except for &lt;a href="http://senchalabs.github.com/connect/"&gt;Connect&lt;/a&gt; and &lt;a href="http://stratajs.org/"&gt;Strata&lt;/a&gt;.]&lt;/p&gt;

&lt;p&gt;Finally, Ted concludes that Node was just doomed from the start, since it&amp;#8217;s written in JavaScript:&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;&lt;code&gt;if (typeof my_var !== "undefined" &amp;amp;&amp;amp; my_var !== null) {
  // you idiots put Rasmus Lerdorf to shame
}
&lt;/code&gt;&lt;/pre&gt;
  
  &lt;p&gt;What is this I don&amp;#8217;t even&amp;#8230;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Never mind that this code would be even uglier in, say, Python—presumably a non-cancerous language:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;try:
    my_var
except NameError:
    pass
else:
    if my_var is not None:
        # Ted needs better examples
        ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Some people &lt;em&gt;like&lt;/em&gt; JavaScript now, Ted. We even have &lt;a href="http://jashkenas.github.com/coffee-script/"&gt;options for people who don&amp;#8217;t&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Look, I&amp;#8217;m not that invested in Node, and I don&amp;#8217;t have any interest in using its web server for anything. That&amp;#8217;s just not what I use it for. But even I could spot the flaws in Ted&amp;#8217;s childish article. Please don&amp;#8217;t support his inflammatory trash just because you don&amp;#8217;t like JavaScript.&lt;/p&gt;

&lt;p&gt;For a much more reasonable take on Node and its performance claims, I recommend &lt;a href="http://al3x.net/2010/07/27/node.html"&gt;this post by Alex Payne of Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://news.ycombinator.com/item?id=3064952"&gt;Discuss this post on Hacker News.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[Update: I&amp;#8217;ve posted &lt;a href="http://blog.brianbeck.com/post/10997599091"&gt;a brief followup&lt;/a&gt;.]&lt;/p&gt;</description><link>http://blog.brianbeck.com/post/10967024222</link><guid>http://blog.brianbeck.com/post/10967024222</guid><pubDate>Sun, 02 Oct 2011 19:57:00 -0700</pubDate><category>node.js</category><category>javascript</category></item><item><title>So, you want to use require() in the browser...</title><description>&lt;p&gt;You&amp;#8217;ve written a bunch of JavaScript or CoffeeScript running on &lt;a href="http://nodejs.org/"&gt;Node&lt;/a&gt;, which has helped you organize your code into modules, develop a test suite in any of numerous styles, experiment in a decent REPL, and take advantage of useful libraries.&lt;/p&gt;

&lt;p&gt;Now you want to deploy that code to the final frontier—the web browser.&lt;/p&gt;

&lt;p&gt;You have a couple options. A couple dozen, actually. Here are just the libraries that were easy to find, in order of GitHub popularity. The bars represent their number of watchers:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&lt;a href="http://ender.no.de/"&gt;Ender&lt;/a&gt; &lt;span class="barline" style="width: 200px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://requirejs.org/"&gt;RequireJS&lt;/a&gt; &lt;span class="barline" style="width: 183px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/substack/node-browserify"&gt;browserify&lt;/a&gt; &lt;span class="barline" style="width: 123px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sstephenson/stitch"&gt;Stitch&lt;/a&gt; / &lt;a href="https://github.com/secoif/StitchUp"&gt;StitchUp&lt;/a&gt; &lt;span class="barline" style="width: 75px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jbrantly/yabble"&gt;Yabble&lt;/a&gt; &lt;span class="barline" style="width: 16px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/weepy/brequire"&gt;brequire&lt;/a&gt; &lt;span class="barline" style="width: 15px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mozilla/dryice"&gt;DryIce&lt;/a&gt; &lt;span class="barline" style="width: 12px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/marcuswestin/require"&gt;require&lt;/a&gt; &lt;span class="barline" style="width: 10px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Gozala/teleport"&gt;teleport&lt;/a&gt; &lt;span class="barline" style="width: 7px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tobie/modulr"&gt;modulr&lt;/a&gt; / &lt;a href="https://github.com/tobie/modulr-node"&gt;modulr-node&lt;/a&gt; &lt;span class="barline" style="width: 5px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pmuellr/modjewel"&gt;modjewel&lt;/a&gt; &lt;span class="barline" style="width: 4px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kriskowal/q-require"&gt;q-require&lt;/a&gt; &lt;span class="barline" style="width: 2px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/medikoo/modules-webmake"&gt;webmake&lt;/a&gt; &lt;span class="barline" style="width: 2px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bnoguchi/browser-require"&gt;browser-require&lt;/a&gt; &lt;span class="barline" style="width: 1px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dominictarr/amd"&gt;AMD&lt;/a&gt; &lt;span class="barline" style="width: 1px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/joehewitt/app.js"&gt;app.js&lt;/a&gt; &lt;span class="barline" style="width: 1px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dimituri/beans"&gt;Beans&lt;/a&gt; &lt;span class="barline" style="width: 1px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rincewind/roast"&gt;Roast&lt;/a&gt; &lt;span class="barline" style="width: 1px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/brentlintner/gaseous"&gt;gaseous&lt;/a&gt; &lt;span class="barline" style="width: 1px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/azer/onejs"&gt;OneJS&lt;/a&gt; &lt;span class="barline" style="width: 0px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ryanwilliams/jah"&gt;jah&lt;/a&gt; &lt;span class="barline" style="width: 0px"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;As you can see, quite a few developers have approached this problem. There are several ways to interpret this:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Maybe it&amp;#8217;s an easy problem to solve, since so many people have opted to roll their own.&lt;/li&gt;
&lt;li&gt;Maybe it&amp;#8217;s hard to solve, since so many people evidently decided that the others got it wrong.&lt;/li&gt;
&lt;li&gt;Maybe each person has legitimately different requirements.&lt;/li&gt;
&lt;li&gt;Maybe it&amp;#8217;s just &amp;#8220;opinionated&amp;#8221;, like web frameworks.&lt;/li&gt;
&lt;/ul&gt;&lt;h2&gt;Downloading code on-demand: related, but different.&lt;/h2&gt;

&lt;p&gt;Admittedly, several of these libraries are trying to solve a related, but different problem: downloading the required modules on-demand (usually asynchronously via AJAX).&lt;/p&gt;

&lt;p&gt;While an interesting problem to tackle, I think using this scheme in production is a bit misguided. Compiling your entire application into a single JavaScript file shouldn&amp;#8217;t be a problem for anyone. Whose minified and compressed code is bigger than the size of a few JPEGs? (Hint: not Facebook&amp;#8217;s, Grooveshark&amp;#8217;s, or Pandora&amp;#8217;s.) At most you should need a tiny loader script that grabs a couple of large, self-contained blobs of code when the page loads.&lt;/p&gt;

&lt;p&gt;Loading dozens of small modules on demand is just going to result in more HTTP requests and worse compression. The simpler alternative is to already have the modules available, and just run them and return their exports on-demand. Thus, you have one file and no asynchrony.&lt;/p&gt;

&lt;h2&gt;Deploying the same code to production that you run in development: the actual problem.&lt;/h2&gt;

&lt;p&gt;The larger and more compelling use-case that many of these libraries tackle is running the same code in the browser that you wrote for Node. The foremost obstacle here just happens to be the organization of code into &lt;a href="http://www.commonjs.org/specs/modules/1.0/"&gt;CommonJS&lt;/a&gt;-like &lt;a href="http://nodejs.org/docs/v0.4.12/api/modules.html"&gt;modules&lt;/a&gt;. Even if you avoid using Node&amp;#8217;s core modules and globals like &lt;code&gt;process&lt;/code&gt; and &lt;code&gt;__filename&lt;/code&gt;, the use of &lt;code&gt;require&lt;/code&gt; for your own modules still must be addressed.&lt;/p&gt;

&lt;p&gt;That&amp;#8217;s where these libraries come in.&lt;/p&gt;

&lt;p&gt;I happen to have implemented yet another one of these libraries for my own purposes, so I&amp;#8217;m familiar with the problem. In my next blog post, I&amp;#8217;ll explain what requirements the most popular libraries satisfy, describe where they fall short, and demonstrate some improvements we could make to truly call them production-ready.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://news.ycombinator.com/item?id=3037275"&gt;Discuss this post on Hacker News.&lt;/a&gt;&lt;/p&gt;</description><link>http://blog.brianbeck.com/post/10667967423</link><guid>http://blog.brianbeck.com/post/10667967423</guid><pubDate>Sun, 25 Sep 2011 17:43:00 -0700</pubDate><category>javascript</category><category>coffeescript</category><category>node.js</category><category>require</category></item><item><title>adminbrowse: Fancier changelist columns in Django's admin site</title><description>&lt;p&gt;I just released a new reusable Django app called &lt;a href="https://github.com/exogen/django-adminbrowse"&gt;django-adminbrowse on GitHub&lt;/a&gt;. This was factored out of a Django project I&amp;#8217;ve been working on for a while.&lt;/p&gt;

&lt;p&gt;Ever wish it was easier to get around in the Django admin? Maybe you&amp;#8217;ve deployed the admin site as a management tool for some less technical users? This project lets you easily spiff up changelist pages to include better text and markup. I&amp;#8217;ve been using it in production for a while and it&amp;#8217;s been a welcome improvement.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://assets1.github.com/img/0c5348a67a0180a6187c8b93746d0627c0803300?repo=&amp;amp;url=http%3A%2F%2Fexogen.github.com%2Fdjango-adminbrowse%2Fimages%2Fadminbrowse.png&amp;amp;path="&gt;&lt;img src="http://media.tumblr.com/tumblr_lctxp5SWZc1qz7sas.png" alt=""/&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the screenshot (click to zoom), you&amp;#8217;ll notice:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;URL fields become clickable links.&lt;/li&gt;
&lt;li&gt;Foreign key fields link to the change form for the corresponding object.&lt;/li&gt;
&lt;li&gt;Related objects get a link to their changelist page, filtered appropriately.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;There are a few more features, but the most powerful is that the code is very easily extensible. If you ever wanted to include a custom markup in your changelist columns, this makes it really easy.&lt;/p&gt;

&lt;p&gt;See the &lt;a href="https://github.com/exogen/django-adminbrowse#readme"&gt;README&lt;/a&gt; or use Python&amp;#8217;s &lt;code&gt;help()&lt;/code&gt; for starters. More advanced documentation is in progress.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;</description><link>http://blog.brianbeck.com/post/2077098609</link><guid>http://blog.brianbeck.com/post/2077098609</guid><pubDate>Thu, 02 Dec 2010 18:12:00 -0800</pubDate><category>django</category><category>python</category><category>adminbrowse</category></item><item><title>The Numbers: Day 70</title><description>&lt;p&gt;More updates are coming! Erin and I will be taking a break from our trip next week in order to celebrate our birthday&amp;#8212;October 30 for the both of us&amp;#8212;back in Cleveland with friends and family. We&amp;#8217;ll be in town from Wednesday, October 27 until Tuesday, November 2, when we&amp;#8217;ll most likely continue our journey from Eugene, Oregon.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Miles since Cleveland: ~2,000&lt;/li&gt;
&lt;li&gt;Cycling days: 44&lt;/li&gt;
&lt;li&gt;Leisure days: 26&lt;/li&gt;
&lt;li&gt;Rainy days: 4&lt;/li&gt;
&lt;li&gt;Nights camped: 11&lt;/li&gt;
&lt;li&gt;Nights in motels: 22½&lt;/li&gt;
&lt;li&gt;Nights couchsurfed: 36½&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;[We half-camped on two occasions&amp;#8212;the night in Oberlin, which accounts for half a motel, and in someone&amp;#8217;s yard, which I&amp;#8217;ll call &amp;#8220;campsurfing&amp;#8221; and accounts for half a couchsurf.]&lt;/p&gt;</description><link>http://blog.brianbeck.com/post/1384376935</link><guid>http://blog.brianbeck.com/post/1384376935</guid><pubDate>Sat, 23 Oct 2010 15:44:00 -0700</pubDate></item><item><title>Days 12-14: Milwaukee</title><description>&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l9fjteIn4z1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;The ferry arrived in Milwaukee just as the sun was setting. As we hadn&amp;#8217;t yet arranged for a place to spend the night, we debated skipping the city altogether and riding 20 miles south to find a camping spot. A light rain started to fall, so after sending some futile last-minute &lt;a href="http://www.couchsurfing.org"&gt;CouchSurfing&lt;/a&gt; requests, we booked a room at the Ramada Inn downtown.&lt;/p&gt;

&lt;p&gt;We showered at the hotel, and, having just spent several hours on a ferry instead of on bikes, were feeling energetic and ready to experience some Milwaukee nightlife. I found a great thread on &lt;a href="http://www.reddit.com/r/milwaukee"&gt;the Milwaukee sub-reddit&lt;/a&gt; and made a list of everything we should check out during our stay. One bar on the list, The Safe House, was just around the corner.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l9fju3wOlI1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.safe-house.com/"&gt;The Safe House&lt;/a&gt; is a spy-themed bar. There&amp;#8217;s a doorman to whom you whisper the password; a bookcase then opens to grant access to the bar. If you don&amp;#8217;t know the password, you must suffer a hazing ritual; to your further embarassment, a live video feed of the entranceway is broadcast on every TV in the bar.&lt;/p&gt;

&lt;p&gt;Inside is essentially a playground for adults. All the drinks are spy-themed, and many come with souvenir pint glasses (Erin took home the Spy&amp;#8217;s Demise glass). There are secret rooms, crazy mirrors, and telephone booths into which you can enter codes to play recordings. One of several bars is tended by a magician, who we watched perform card tricks, swallow a balloon, and generally entertain the audience.&lt;/p&gt;

&lt;p&gt;Upstairs was a couple enjoying some drinks by themselves. They overheard us talking about our trip and we made introductions and small talk. They were Milwaukee natives, yet were also first-timers at The Safe House. We decided to all go out for dinner (and more drinks), having just arrived at the bar after the kitchen closed for the night. Unfortunately, we were in too much of a hurry to find the secret exit.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l9fjzpuE5l1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;We walked over a small bridge to Rock Bottom Brewery with our new friends, Tony and Allyssa. The food and conversation were both great. Apparently, they didn&amp;#8217;t get many opportunities to hang out with other couples, so they greatly enjoyed our company. We checked out a few more downtown bars until I showed my hand by ordering a gin &amp;amp; tonic. This usually means I&amp;#8217;ve had enough to drink for the night, so Tony dropped us off at the hotel.&lt;/p&gt;

&lt;p&gt;Judging by the list we made of things to do in Milwaukee, it was clear we&amp;#8217;d be staying at least another day. So while Tony and Allyssa were at work, we checked off the items on our list.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l9fjus53Hd1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;We relaxed in the grass along the coast, near the science center and other attractions. Then we made our way south, checking out the Pabst mansion, touring the Lakefront brewery, and grabbing a bite to eat at Alterra Coffee on the way.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l9fjwiZ5fW1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l9fjxhFD5S1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;As the sun went down, we hopped from bar to bar on Kinnikinnic Avenue, where some of the more hip establishments are located. Eventually, Tony got home from work and invited us to stay for the night. When Allyssa joined us, we enjoyed more drinks and some dinner at Cafe Centraal, which was supposedly named the most bike-friendly restaurant/bar in Milwaukee.&lt;/p&gt;

&lt;p&gt;To conclude the night, we drove to a more residential area where Tony remembered finding a speakeasy called At Random. We eventually arrived, and were the only patrons there to keep the older couple running the place busy. The drink list was similar to that of the &lt;a href="http://velvettangoroom.com/"&gt;Velvet Tango Room&lt;/a&gt;, but the atmosphere was terribly dated (and obviously, the Velvet Tango Room wouldn&amp;#8217;t have been empty). I took it easy (due in part to the $10 cocktails) and ordered a large drink that included ice cream.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l9fjvgDEHt1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;On the way out of town in the morning, we rode over to an Einstein Bros. Bagels for breakfast. Conveniently, Allyssa was working there at the time, and Tony also stopped in for a visit. We enjoyed a good breakfast, said our goodbyes, and hopped on the highway heading south&amp;#8230;&lt;/p&gt;</description><link>http://blog.brianbeck.com/post/1212851195</link><guid>http://blog.brianbeck.com/post/1212851195</guid><pubDate>Wed, 29 Sep 2010 16:20:00 -0700</pubDate></item><item><title>The Numbers: Day 34</title><description>&lt;p&gt;Some quick data while I work on writing the backlog of our trip&amp;#8230;&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Miles since Cleveland: ~1,000&lt;/li&gt;
&lt;li&gt;Cycling days: 22&lt;/li&gt;
&lt;li&gt;Leisure days: 12&lt;/li&gt;
&lt;li&gt;Rainy days: 1&lt;/li&gt;
&lt;li&gt;Nights camped: 6½&lt;/li&gt;
&lt;li&gt;Nights in motels: 8½&lt;/li&gt;
&lt;li&gt;Nights couchsurfed: 19&lt;/li&gt;
&lt;/ul&gt;</description><link>http://blog.brianbeck.com/post/1139912050</link><guid>http://blog.brianbeck.com/post/1139912050</guid><pubDate>Fri, 17 Sep 2010 16:51:33 -0700</pubDate></item><item><title>Days 5-12: Ann Arbor to Milwaukee</title><description>&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l8555dW6Ty1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;We made some changes to our route in Ann Arbor. Our plan was to pass through Kalamazoo, Michigan and Gary, Indiana on our way to Chicago. But we looked into taking a ferry across Lake Michigan when we heard that Gary might be a bit hazardous to our health and morale. So after enjoying the &lt;a href="http://www.lakefolkband.com/home.html"&gt;Lake Folk&lt;/a&gt; show and spending the night in Ann Arbor, we headed out for Lansing and Grand Rapids.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l8555vPiDP1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;We set up camp in the wilderness of the Pinckney State Recreation Area. The isolated areas were all overgrown, so our only option was to clear a spot in a covered circle of trees and bushes.&lt;/p&gt;

&lt;p&gt;We didn&amp;#8217;t get much sleep that night. It was hot, the road was very close, and we encountered our first critter. In the middle of the night, Erin spotted the silhouette of something big passing by. It started sniffing and snorting when it detected us, but luckily didn&amp;#8217;t feel the need to further challenge these terrified campers or browse our food selection.&lt;/p&gt;

&lt;p&gt;The next day, we sent out some &lt;a href="http://couchsurfing.org"&gt;CouchSurfing&lt;/a&gt; requests to various folks living northwest of Lansing. We saw some nice parts of the city as we passed through, but our only stop was for some groceries at a Meijer, where we learned that our new CouchSurfing hosts were just a few miles down the road.&lt;/p&gt;

&lt;p&gt;Trever and Natalee were excited to host us&amp;#8212;their first CouchSurfers&amp;#8212;at their apartment in Grand Ledge. We went out to dinner at Cancun Mexican Grill, where I ordered what turned out to be the most impressive looking Mexican dish I&amp;#8217;ve ever seen (and very tasty, too). We talked about our new route and the ferry, and our hosts recommended we check out Grand Haven&amp;#8212;apparently, the place where everyone in Michigan wants to be. After dinner, Trever and Natalee took us to the rock ledges that gave Grand Ledge its name. It was a long and tricky walk in the dark, so the many bike headlights we brought came in handy.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l8566lfeTt1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;We said our goodbyes in the morning and began the 55-mile ride to Grand Rapids. Erin was experiencing pain in her Achilles tendon by lunch time, so we applied some ointment and bandages and tried to take it easy. The sun was just going down as we rolled into Grand Rapids, so we started calling motels and contacting CouchSurfers from a park downtown, with no immediate success. Across the street was a restaurant with great reviews called &lt;a href="http://www.onetrick.biz/home.html"&gt;One Trick Pony&lt;/a&gt;. We decided to mull over our lodging situation over dinner.&lt;/p&gt;

&lt;p&gt;I ordered the pecan-crusted salmon at One Trick Pony, which was the best meal I&amp;#8217;d had on the trip so far. When it came time for dessert, the waitress gave it to us on the house, on account of the exciting adventure we were on! To make the evening even better, I got a call from a CouchSurfer less than an hour after contacting her. Ama said she&amp;#8217;d be happy to host us at her duplex a few minutes from downtown, despite being tired and overworked during our visit.&lt;/p&gt;

&lt;p&gt;Before leaving the restaurant, I noticed that a lot of people were checking into a place called the Lyon Street Water Slide on &lt;a href="http://foursquare.com"&gt;foursquare&lt;/a&gt;. This struck me as a bit strange, since it was getting pretty late. So I asked around, and learned that there was indeed a water slide set up on a nearby street. In fact, the entire downhill portion of the road was closed off just for this special two-day event, and people were waiting for up to five hours for a free ride! Interesting&amp;#8230;&lt;/p&gt;

&lt;p&gt;When it came time to leave in the morning, it became apparent that Erin&amp;#8217;s tendons needed a day of rest. So, while we were visiting the water slide just to take a peek, we made the decision to take the day off and get in line!&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l8579jGGut1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;As expected, the slide—rather, the line for it—took up most of our day. We ended up waiting about four hours for a ride, but it was worth the wait. Others seemed to agree, since it appeared that nearly everyone in Grand Rapids was there. It was a slow day followed by a relaxing evening.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l8578957A81qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;In the morning we left for Grand Haven, figuring we&amp;#8217;d kill some time before the ferry left from Muskegon. When we rolled across the bridge into town, it became apparent why Trever and Natalee had spoken highly of it. There were beautiful beaches and boardwalks, and clean, bike-friendly streets. A sign informed us that Grand Haven is known as &amp;#8220;Coast Guard City, USA.&amp;#8221; It felt a lot like Newport, Rhode Island, where I grew up.&lt;/p&gt;

&lt;p&gt;Figuring it would be appropriate to order some seafood for lunch, we sat down outdoors at The Grand, a nice downtown restaurant. Our waiter, &lt;a href="http://twitter.com/salomonskier720/status/22012553070"&gt;Gavin&lt;/a&gt;, was incredibly friendly and talkative. He was very interested in our trip and excited to tell us all about Grand Haven—he even recommended staying overnight, so we&amp;#8217;d have time to absorb more of the city.&lt;/p&gt;

&lt;p&gt;Still planning to catch the ferry that night, we spent the afternoon at the beach swimming and building sand castles. Lake Michigan is so big that it was nearly indistinguishable from a beach on the ocean.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l85bfksXwt1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;While walking back to our bikes, we noticed that the beach had camping spots for tents and trailers, and it appeared to be quite a popular activity that night. For the low price of $29, we couldn&amp;#8217;t pass it up. So we took Gavin&amp;#8217;s advice and spent the night, setting up our tent right on the beach. We showered and then rode our bikes to the closest movie theater to catch Piranha 3D, which is just what you&amp;#8217;d expect. The theater employees let us in for free with no reason given.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l857b75tgT1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;In the morning we got the best breakfast Grand Haven has to offer at the Morning Star Cafe. A quick stop at the bike shop around the corner and we were ready for our last ride in Michigan.&lt;/p&gt;

&lt;p&gt;It didn&amp;#8217;t take us long to reach Muskegon, but it did take a little too much effort to find the &lt;a href="http://www.lake-express.com/"&gt;Lake Express&lt;/a&gt; ferry. The tickets were also far too expensive, but at this point we had no choice. As the only cyclists, we got to board first, followed by the cars. We settled in next to a power outlet so we could charge our phones, then explored the deck as the ferry left the harbor.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l857dvvLaf1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;Upon departing the harbor at an average pace, it soon became apparent why the Lake Express is called a high-speed ferry. That thing really moves! Standing on the deck is only reasonable for a few minutes before the wind becomes so strong that it&amp;#8217;s hard to move. We took some pictures and returned to our seats until our arrival in Milwaukee&amp;#8230;&lt;/p&gt;</description><link>http://blog.brianbeck.com/post/1139518508</link><guid>http://blog.brianbeck.com/post/1139518508</guid><pubDate>Fri, 17 Sep 2010 15:26:00 -0700</pubDate><category>adventure</category><category>bikes</category><category>cycling</category><category>seattle</category><category>ann arbor</category><category>milwaukee</category></item><item><title>Days 1-4: Cleveland to Ann Arbor</title><description>&lt;p&gt;Friends and family met us at Lakewood Park on Sunday to send us off—two days later than we originally planned.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l7d7yu3Vw41qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;We finally hit the road a little after 3pm, but stopped at &lt;a href="http://centurycycles.com/about/rocky-river-pg286.htm"&gt;Century Cycles&lt;/a&gt; in Rocky River for some last minute supplies.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l7d80kE6j41qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;The ride to Oberlin was slow, but we made it. It took us quite a few miles to get used to the weight of the bikes—each carrying about 50 pounds.&lt;/p&gt;

&lt;p&gt;There weren&amp;#8217;t many people on campus at the time, so we just picked up some Chinese food and started scouting out a good spot to set up for the night. We settled on a hidden clearing next to a chapel and unloaded our gear.&lt;/p&gt;

&lt;p&gt;That turned out to be a terrible idea. For one thing, the bells tolled every hour—even at 2am. And the benches around the corner turned out to be a popular late-night hangout for students looking to drink on the down-low. After the second rowdy group left, I gave in and looked up the closest motel. At 3am, we quickly packed it up and rode to the motel in the dark of the night. This turned out to be my favorite few miles of riding so far. The air was cool, there was absolutely nobody on the road, and we could only see as far as the reach of our headlights.&lt;/p&gt;

&lt;p&gt;After showers and breakfast at the motel on Monday, we left for Fremont, Ohio.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l7dka8i4KN1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, we didn&amp;#8217;t discover the &lt;a href="http://www.metroparks.cc/reservation-north-coast-inland-trail.php"&gt;North Coast Inland Trail&lt;/a&gt; until we arrived in Fremont, so the ride could have been faster and easier than it was. While looking for a place to camp, we found the trail and met a new friend: John, a 26-year-old mechanical engineer contracting on a project in Fremont. After sending us off with suggested camping locations, he caught up to us and offered his place for the night. We gladly accepted and ended up having a great time.&lt;/p&gt;

&lt;p&gt;The next morning we hopped on the trail and enjoyed another day of perfect weather. We ran into &lt;a href="http://fremontcycleandfitness.com/storelocator/elmore-cycle-fitness-2.htm"&gt;Elmore Cycle &amp;amp; Fitness&lt;/a&gt; along the trail and stopped in for some tune-ups on Erin&amp;#8217;s bike. The head mechanic, Mike, was interested in the gear we chose to pack and eagerly offered some helpful advice (such as picking up 12oz of heat antifreeze at a gas station to replace the 32oz of denatured alcohol we&amp;#8217;re carrying for cooking). Mike posts photos of passing tourers and his ultralight setups &lt;a href="http://www.flickr.com/photos/mmeiser2"&gt;on his Flickr stream&lt;/a&gt; (photos of us coming soon).&lt;/p&gt;

&lt;p&gt;We eventually reached and promptly exited Toledo, which had terrible roads for cycling and &lt;em&gt;the worst&lt;/em&gt; drivers. Everyone had some stupid comment for us—none of them demonstrating any knowledge of the actual rules of the road, of course. So we rode until we reached Temperance, Michigan, and found the perfect stealth camping spot behind some trees.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l7d7i48mbc1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;This morning was the earliest we&amp;#8217;ve started yet, waking up at 7:00 to make breakfast and pack up, and hitting the road by 9:00. After 15 miles, we took a short break in Dundee, which was home to every imaginable fast-food chain on just a half-mile stretch, but also a cute and clean downtown area.&lt;/p&gt;

&lt;p&gt;The remainder of the trip was spent riding directly north on some very sparsely populated roads, singing songs and taking pictures along the way to cure our boredom.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l7dkj1DSEk1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;We rolled into Ann Arbor a little after 1pm and met up with our friends, Erin and Bryan (funny, right?) at their apartment. We&amp;#8217;re about to leave for the bar to see their band &lt;a href="http://www.lakefolkband.com/home.html"&gt;Lake Folk&lt;/a&gt; perform. We&amp;#8217;ll be taking advantage of these comfy couches tonight and leaving for Kalamazoo after lunch tomorrow!&lt;/p&gt;</description><link>http://blog.brianbeck.com/post/974724333</link><guid>http://blog.brianbeck.com/post/974724333</guid><pubDate>Wed, 18 Aug 2010 18:24:00 -0700</pubDate></item><item><title>Bike Adventure Gear, Part 1: Camping</title><description>&lt;p&gt;Over the next few days, I&amp;#8217;ll be posting all the gear Erin and I are bringing on our bike trip to Seattle. I&amp;#8217;m a determined comparison shopper and bargain hunter, so every last item here was meticulously researched, and we got great deals on almost everything. Maybe these posts will save you some time if you&amp;#8217;re planning a similar adventure!&lt;/p&gt;

&lt;p&gt;Today&amp;#8217;s post: our camping gear.&lt;/p&gt;

&lt;p&gt;We&amp;#8217;ll be spending our nights in &lt;a href="http://www.rei.com/product/779039"&gt;The North Face&amp;#8217;s Big Fat Frog 2-person tent&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l6ptd0b69J1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;One of the highest rated tents on &lt;a href="http://www.rei.com"&gt;REI&lt;/a&gt;, I bought it there during their big sale earlier this summer, and saved some money by purchasing the footprint from &lt;a href="http://www.rockcreek.com"&gt;Rock/Creek&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since our bodies will likely be aching after riding for hours every day, we each have our own &lt;a href="http://www.rei.com/product/778147"&gt;REI Trekker 1.75 self-inflating sleeping pad&lt;/a&gt;. To save on weight and space, we&amp;#8217;re only bringing one sleeping bag, replacing the other with a &lt;a href="http://www.rei.com/product/735819"&gt;Cocooon ripstop silk liner&lt;/a&gt;. We can always share the sleeping bag if necessary, so I&amp;#8217;m betting that this tradeoff is going to be worthwhile.&lt;/p&gt;

&lt;p&gt;We&amp;#8217;ll be cooking our meals on the road with the &lt;a href="http://www.rei.com/product/657906"&gt;Mini Trianga 28-T backpacking stove&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l6pu3zJwOR1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;This tiny stove burns denatured alcohol and comes with a pot and pan. While we&amp;#8217;ll mostly be using this just to boil water, I&amp;#8217;m looking forward to learning how to cook meals as quickly and efficiently as possible with this limited equipment. &lt;a href="http://www.campsaver.com"&gt;CampSaver.com&lt;/a&gt; had the best deal on this stove.&lt;/p&gt;

&lt;p&gt;And why bring along some normal household utensils when we can use the &lt;a href="http://www.rei.com/product/765204"&gt;Guyot Designs MicroBites&lt;/a&gt; and the &lt;a href="http://www.rei.com/product/660002"&gt;Snow Peak titanium spork&lt;/a&gt;? If there&amp;#8217;s an everyday item that has a fancy backpacking equivalent, I had to have it. :)&lt;/p&gt;

&lt;p&gt;For campsite lighting we have the &lt;a href="http://www.rei.com/product/777554"&gt;Black Diamond Orbit lantern&lt;/a&gt; and the &lt;a href="http://www.rei.com/product/799383"&gt;Mammut TR1 headlamp&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l6puqkCOxX1qz7sas.jpg" alt=""/&gt;&lt;img src="http://media.tumblr.com/tumblr_l6puqwc0ta1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;Both are super bright. Unfortunately, Steve&amp;#8217;s dog chewed up the lantern, which does in fact resemble a dog toy. It still works fine - a testament to its durability, at least. &lt;a href="http://www.e-omc.com"&gt;Oregon Mountain Community&lt;/a&gt; had the best deal on the headlamp.&lt;/p&gt;

&lt;p&gt;Other miscellanous items&amp;#8230;&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;A couple &lt;a href="http://www.rei.com/product/783480"&gt;MSR PackTowl&lt;/a&gt; compact and lightweight towels.&lt;/li&gt;
&lt;li&gt;A &lt;a href="http://www.rei.com/product/737335"&gt;firesteel&lt;/a&gt;, so I can struggle to ignite things until Erin gets frustrated and uses her lighter.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.rei.com/product/401139"&gt;This coffee pot&lt;/a&gt; - Erin&amp;#8217;s vice, not mine. You&amp;#8217;re responsible for carrying this one, Erin!&lt;/li&gt;
&lt;li&gt;Plates, bowls, stove fuel, soap, and a clothesline.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Think I&amp;#8217;m missing something? &lt;a href="http://blog.brianbeck.com/post/911431304/bike-adventure-gear-part-1-camping#comments"&gt;Help me out in the comments!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my next post, I&amp;#8217;ll write about the most important gear - our bikes and accessories.&lt;/p&gt;</description><link>http://blog.brianbeck.com/post/911431304</link><guid>http://blog.brianbeck.com/post/911431304</guid><pubDate>Thu, 05 Aug 2010 23:12:00 -0700</pubDate></item><item><title>The State of the Weblog</title><description>&lt;p&gt;My media server is down, so some content may be missing (pictures, linked documents), and I&amp;#8217;m using a temporary theme.&lt;/p&gt;

&lt;p&gt;My last day of work in Cleveland is one week from today. The week after that I&amp;#8217;ll be riding my bicycle to Seattle with my girlfriend, camping and couchsurfing on the way. It&amp;#8217;ll take us about five weeks, and I&amp;#8217;ll be posting frequent updates here. Hopefully our cycling adventures capture your interest as much as code and Cleveland musings.&lt;/p&gt;

&lt;p&gt;Follow if it is adventure that you seek&amp;#8230;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l6e6pt2nxv1qz7sas.png" alt="bicycle"/&gt;&lt;/p&gt;</description><link>http://blog.brianbeck.com/post/881516268</link><guid>http://blog.brianbeck.com/post/881516268</guid><pubDate>Fri, 30 Jul 2010 15:37:48 -0700</pubDate></item><item><title>Serious Games talk at Case</title><description>&lt;p&gt;&lt;a href="http://media.brianbeck.com/images/Serious_Games.pdf"&gt;&lt;img src="http://media.tumblr.com/tumblr_l0skrohHIE1qz7sas.png" alt="Serious Games flyer"/&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ll be giving a talk on serious games at the next meeting of the CWRU Hacker Society on Wednesday, April 14th, 8pm in Glennan 313.&lt;/p&gt;

&lt;p&gt;The scope will be much wider than my previous talks on Unit Testing Achievements. A rough outline:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;What are serious games?&lt;/li&gt;
&lt;li&gt;How can they be applied to software?&lt;/li&gt;
&lt;li&gt;How do they affect behavior?&lt;/li&gt;
&lt;li&gt;What&amp;#8217;s out there now?&lt;/li&gt;
&lt;li&gt;What&amp;#8217;s left to be explored?&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;See you there!&lt;/p&gt;</description><link>http://blog.brianbeck.com/post/517068133</link><guid>http://blog.brianbeck.com/post/517068133</guid><pubDate>Mon, 12 Apr 2010 18:49:00 -0700</pubDate></item><item><title>Achievement Unlocked</title><description>&lt;p&gt;[This post is adapted from a lightning talk I gave at the &lt;a href="http://lists.idyll.org/listinfo/testing-in-python"&gt;Testing in Python&lt;/a&gt; Birds-of-a-Feather session at PyCon 2010.]&lt;/p&gt;

&lt;p&gt;One of those most fun advancements in video games in recent years is not about the improved graphics, or playing with hundreds of people at once. It&amp;#8217;s that &lt;strong&gt;games have evolved beyond points&lt;/strong&gt;. While a good point system may be a good indicator of a player&amp;#8217;s abilities, it doesn&amp;#8217;t tell the whole story. Many modern games, even if they don&amp;#8217;t involve points, have introduced the concept of &lt;strong&gt;achievements&lt;/strong&gt;. Achievements are awarded for completing game-specific challenges&amp;#8212;essentially, they are merit badges.&lt;/p&gt;

&lt;h4&gt;Examples&lt;/h4&gt;

&lt;p&gt;From &lt;a href="http://www.teamfortress.com/"&gt;Team Fortress 2&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_kycus6P6MJ1qz7sas.png" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;From &lt;a href="http://www.thebeatlesrockband.com/"&gt;The Beatles: Rock Band&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_kycusnZi3e1qz7sas.png" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;From &lt;a href="http://foursquare.com/"&gt;foursquare&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_kycusztzdZ1qz7sas.png" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;These add another level of fun to the games in question. &lt;strong&gt;I think it&amp;#8217;s about time we stole this idea for software testing.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testing Achievements&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_kycuz53wtJ1qz7sas.png" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;To make this happen, I announced an &lt;a href="http://github.com/exogen/nose-achievements"&gt;Achievements plugin for nose&lt;/a&gt;, the Python test runner. Here are a few highlights:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Night Shift&lt;/strong&gt;&lt;br/&gt;
Make a failing test suite pass between midnight and 5am.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Punctuality&lt;/strong&gt;&lt;br/&gt;
Make a failing test suite pass at 9am.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Coffee Break&lt;/strong&gt;&lt;br/&gt;
The test suite takes between 5 and 15 minutes to run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy Ending&lt;/strong&gt;&lt;br/&gt;
All tests in the suite fail&amp;#8230;except the last.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My God, It&amp;#8217;s Full of Dots&lt;/strong&gt;&lt;br/&gt;
The suite has at least 2,001 passing tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sausage Fingers&lt;/strong&gt;&lt;br/&gt;
At least two distinct syntax errors are raised by the test suite.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are You Mocking Me?&lt;/strong&gt;&lt;br/&gt;
Import a mocking library.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;100% Code Coverage, Level x&lt;/strong&gt;&lt;br/&gt;
100% of at least 2&lt;sup&gt;(x+7)&lt;/sup&gt; statements are executed.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://exogen.github.com/nose-achievements/"&gt;You can view the full list of achievements here&lt;/a&gt;. Many of these are working right now.&lt;/p&gt;

&lt;h4&gt;Next Steps&lt;/h4&gt;

&lt;p&gt;Announcing unlocked achievements on Twitter or IRC, global or project-specific leaderboards, pluggable achievement expansion packs&amp;#8230;&lt;/p&gt;

&lt;p&gt;Share your ideas in the comments!&lt;/p&gt;</description><link>http://blog.brianbeck.com/post/409316644</link><guid>http://blog.brianbeck.com/post/409316644</guid><pubDate>Wed, 24 Feb 2010 09:08:00 -0800</pubDate></item><item><title>Phaeton by Kevin Cornell &amp; Randy Jones. This typeface really...</title><description>&lt;img src="http://25.media.tumblr.com/tumblr_kwnolnWhiI1qz7r2ao1_500.gif"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;&lt;a href="http://www.veer.com/partner/link.aspx?i=1380&amp;p=view/UMT0000447"&gt;Phaeton&lt;/a&gt; by Kevin Cornell &amp; Randy Jones. This typeface really stood out in &lt;a href="http://ilovetypography.com/2010/01/21/my-favourite-fonts-of-2009"&gt;ILT’s favorites of 2009&lt;/a&gt;. Love it!&lt;/p&gt;</description><link>http://blog.brianbeck.com/post/347528906</link><guid>http://blog.brianbeck.com/post/347528906</guid><pubDate>Fri, 22 Jan 2010 08:03:23 -0800</pubDate></item><item><title>Emergency party at my place</title><description>&lt;p&gt;Dear Reader,&lt;/p&gt;

&lt;p&gt;You knew keeping this blog in your RSS reader would pay off one day, didn&amp;#8217;t you? You did, right?&lt;/p&gt;

&lt;p&gt;Well now you can reap the rewards, my friend. There comes a time.&lt;/p&gt;

&lt;p&gt;You are invited over to my house on Friday, November 13 for a party and performances by several talented musicians.&lt;/p&gt;

&lt;p&gt;There will be a full bar. Also an actual, physical bar. Celebrated Clevelander Marta &amp;#8220;Martender&amp;#8221; Lapczynski will be bartending.&lt;/p&gt;

&lt;p&gt;We&amp;#8217;re getting started at 10 PM; music at 11. Everything is free.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s your invitation with the details:
&lt;img src="http://media.tumblr.com/tumblr_ksxjqmjY5M1qz7sas.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;See you there, Internet lovelies!&lt;/p&gt;</description><link>http://blog.brianbeck.com/post/239979785</link><guid>http://blog.brianbeck.com/post/239979785</guid><pubDate>Tue, 10 Nov 2009 21:56:00 -0800</pubDate></item><item><title>
  “The Cleveland Tourism Board gave me 14 million dollars...</title><description>&lt;iframe width="400" height="225" src="http://www.youtube.com/embed/ysmLA5TqbIY?wmode=transparent&amp;autohide=1&amp;egm=0&amp;hd=1&amp;iv_load_policy=3&amp;modestbranding=1&amp;rel=0&amp;showinfo=0&amp;showsearch=0" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;br/&gt;&lt;br/&gt;&lt;blockquote&gt;
  &lt;p&gt;“The Cleveland Tourism Board gave me 14 million dollars about 8 months ago to make a promotional video to bring people to Cleveland. As usual, I waited till the last minute and I ended up having to shoot and edit it in about an hour yesterday afternoon.” — &lt;a href="http://www.youtube.com/user/bishopvids"&gt;bishopvids&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description><link>http://blog.brianbeck.com/post/97196132</link><guid>http://blog.brianbeck.com/post/97196132</guid><pubDate>Fri, 17 Apr 2009 07:55:19 -0700</pubDate></item><item><title>Cleveland Code Co-op meeting on Sunday</title><description>&lt;p&gt;The fifth meeting of the &lt;a href="http://nooss.org/wiki/Cleveland_Code_Co-op"&gt;Cleveland Code Co-op&lt;/a&gt; will commence this
Sunday, February 22, from 13:00 till 19:00.  We&amp;#8217;re expecting more
participants than usual, and likely projects so far include:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&lt;a href="http://github.com/jleedev/redit/"&gt;redit&lt;/a&gt;, a text editor in Ruby&lt;/li&gt;
&lt;li&gt;&lt;a href="http://code.google.com/p/cwru-hackers/"&gt;80sheep&lt;/a&gt;, an ADC (peer-to-peer) client in Python&lt;/li&gt;
&lt;li&gt;a Python tutorial for beginners&lt;/li&gt;
&lt;li&gt;your wildest software fantasies&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;This month&amp;#8217;s meeting will take place in the EECS student lounge at
Case Western Reserve University, which is located in the Glennan
Building.  &lt;a href="http://www.nooss.org/wiki/Cleveland_Code_Co-op/CWRU_Location"&gt;Directions are located on the wiki&lt;/a&gt;.  You can also join us on IRC in &lt;a href="irc://irc.freenode.net#c3"&gt;#C3 on irc.freenode.net&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Food and drinks will be provided!  Hope to see you there.&lt;/p&gt;</description><link>http://blog.brianbeck.com/post/79756939</link><guid>http://blog.brianbeck.com/post/79756939</guid><pubDate>Thu, 19 Feb 2009 12:55:53 -0800</pubDate></item><item><title>Python instance descriptors: when class descriptors aren't dynamic enough</title><description>&lt;p&gt;&lt;a href="http://users.rcn.com/python/download/Descriptor.htm"&gt;Python descriptors&lt;/a&gt; are great for customizing access to attributes on a class or instance.  They are a big win for tasks like mapping Python objects to data from non-Python sources (such as SQL), since mapped attributes will need to be encoded/decoded and connected to other attributes in some way.&lt;/p&gt;

&lt;p&gt;Below is a very simple descriptor; as you can see, accessing it from &lt;em&gt;both the class and the instance&lt;/em&gt; invoke the descriptor protocol:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Test(object):
    pass

class Descriptor(object):
    def __get__(self, instance, owner):
        return "Hello, world."

&amp;gt;&amp;gt;&amp;gt; Test.x = Descriptor()
&amp;gt;&amp;gt;&amp;gt; Test.x
'Hello, world.'
&amp;gt;&amp;gt;&amp;gt; test = Test()
&amp;gt;&amp;gt;&amp;gt; test.x
'Hello, world.'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;However, in order to add descriptors to an object, they must be added to the object&amp;#8217;s class.  Descriptors added to an instance do not invoke the descriptor protocol:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; test.y = Descriptor()
&amp;gt;&amp;gt;&amp;gt; test.y
&amp;lt;__main__.Descriptor object at 0x16fe810&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This means that creating an instance with dynamic (determined at runtime) descriptors requires either the heavy-handed approach of generating a class just for that object (since adding descriptors to its class will add them to all other instances of the class), or the ad-hoc approach of redefining &lt;code&gt;getattr&lt;/code&gt;/&lt;code&gt;setattr&lt;/code&gt; behavior (essentially re-implementing your own descriptor protocol).&lt;/p&gt;

&lt;p&gt;It turns out the latter approach is not as messy as it first sounds.  Below is a class that enables &amp;#8220;instance descriptors&amp;#8221;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class InstanceDescriptorMixin(object):
    def __getattribute__(self, name):
        value = object.__getattribute__(self, name)
        if hasattr(value, '__get__'):
            value = value.__get__(self, self.__class__)
        return value

    def __setattr__(self, name, value):
        try:
            obj = object.__getattribute__(self, name)
        except AttributeError:
            pass
        else:
            if hasattr(obj, '__set__'):
                return obj.__set__(self, value)
        return object.__setattr__(self, name, value)

class Test(InstanceDescriptorMixin):
    pass

&amp;gt;&amp;gt;&amp;gt; test = Test()
&amp;gt;&amp;gt;&amp;gt; test.z = Descriptor()
&amp;gt;&amp;gt;&amp;gt; test.z
'Hello, world.'
&lt;/code&gt;&lt;/pre&gt;</description><link>http://blog.brianbeck.com/post/74086029</link><guid>http://blog.brianbeck.com/post/74086029</guid><pubDate>Thu, 29 Jan 2009 09:41:00 -0800</pubDate><category>python</category></item><item><title>"The purpose of syntax highlighting is to turn your code into a map, not The Jimi Hendrix Experience."</title><description>“The purpose of syntax highlighting is to turn your code into a map, not The Jimi Hendrix Experience.”</description><link>http://blog.brianbeck.com/post/68776504</link><guid>http://blog.brianbeck.com/post/68776504</guid><pubDate>Tue, 06 Jan 2009 12:29:26 -0800</pubDate></item><item><title>geopy sprint at December C³ meeting</title><description>&lt;p&gt;Today (Sunday) the third meeting of the &lt;a href="http://nooss.org/wiki/Cleveland_Code_Co-op"&gt;Cleveland Code Co-op&lt;/a&gt; will be held from 1pm to 7pm at &lt;a href="http://www.gypsybeans.com/"&gt;Gypsy Beans &amp;amp; Bakery&lt;/a&gt;.  We&amp;#8217;ll be focusing on &lt;a href="http://exogen.case.edu/projects/geopy/"&gt;geopy&lt;/a&gt; again, continuing our sprint goals from &lt;a href="http://blog.brianbeck.com/post/57991307/geopy-sprint"&gt;last time&lt;/a&gt;.  All are welcome to attend.  You can join us via IRC in &lt;a href="irc://irc.freenode.net#c3"&gt;#c3 on irc.freenode.net&lt;/a&gt;.&lt;/p&gt;</description><link>http://blog.brianbeck.com/post/64744298</link><guid>http://blog.brianbeck.com/post/64744298</guid><pubDate>Sat, 13 Dec 2008 20:51:15 -0800</pubDate></item></channel></rss>

