<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>ongardie.net</title><link>http://ongardie.net/blog/</link><description>ongardie.net Blog</description><lastBuildDate>Wed, 19 Jun 2013 22:31:38 GMT</lastBuildDate><generator>PyRSS2Gen-1.0.0</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Manual Window Placement in i3 (Part 2)</title><link>http://ongardie.net/blog/i3-manual-placement2/</link><description>&lt;p&gt;
This is the second part of a series on making the i3 window manager work the
way I want. I left off
&lt;a href="http://ongardie.net/blog/i3-manual-placement"&gt;last time&lt;/a&gt;
with the goal of changing the way windows are placed as they are created, and I
had a couple of pointers from the i3 hacking howto for where to start looking.
This post covers how I've set up my test environment.
&lt;/p&gt;

&lt;p&gt;
I started looking in &lt;code&gt;src/manage.c&lt;/code&gt; but soon found my way into
&lt;code&gt;src/con.c&lt;/code&gt;, which does most of the grunt work surrounding
containers. There are a ton of conditional branches in the i3 source code,
so running i3 with debug logging on (&lt;code&gt;i3 -d all&lt;/code&gt;) was essential in
figuring out which code paths were being executed.
&lt;/p&gt;

&lt;p&gt;
One particularly relevant log message, &lt;blockquote&gt;Inserting con = x after last
focused tiling con y&lt;/blockquote&gt; led me to &lt;code&gt;con_attach()&lt;/code&gt;, the
function in charge of placing a new window in i3's layout tree. I think that's
one key function I'll need to change.
&lt;/p&gt;

&lt;p&gt;
I started playing around with changing the layouts of things and creating extra
containers in there but quickly got frustrated. The problem was that I was
&lt;em&gt;using&lt;/em&gt; my buggy version of i3 while iterating on the code and testing.
Testing also became difficult, since running the tools to analyze what's going
on requires opening new windows, but opening new windows affects i3's state.
&lt;/p&gt;

&lt;p&gt;
A better approach is to run i3 inside a nested X server. This way you can keep
your editor, browser, and other tools open outside of the test environment, and
keep the test environment minimal, clean, and easy to reset.
&lt;/p&gt;

&lt;p&gt;
I had used &lt;a href="http://en.wikipedia.org/wiki/Xnest"&gt;Xnest&lt;/a&gt; in the past,
but I found that i3bar didn't display fonts for me under Xnest. I don't know
what the problem was there, but I came across
&lt;a href="http://en.wikipedia.org/wiki/Xephyr"&gt;Xephyr&lt;/a&gt;, a replacement for
Xnest that supports modern X extensions. Fortunately, Xephyr can run i3 and
i3bar properly. Xephyr allows the nested server to grab the keyboard (toggled
with Ctrl+Shift), which is quite handy for window manager development.
&lt;/p&gt;

&lt;p&gt;
I'm also getting a lot of mileage from i3's &lt;code&gt;contrib/dump-asy.pl&lt;/code&gt;
script, which uses i3's JSON-based IPC interface to show you a graphical
representation of the layout tree. This script has been helpful in
understanding the tree transformations that occur as I test my changes to i3.
For example, it's showing me that I have a bunch of nested containers with only
one child (oops). I've made a few minor improvements to the script, and Michael
Stapelberg has already accepted a couple of these minor patches.
&lt;/p&gt;

&lt;p&gt;
To use &lt;code&gt;contrib/dump-asy.pl&lt;/code&gt; with a nested X server, you need to
help it find i3's IPC socket. It uses
&lt;a href="https://metacpan.org/module/AnyEvent::I3"&gt;AnyEvent::I3&lt;/a&gt; internally,
whose default constructor finds the i3 running on your current
&lt;code&gt;DISPLAY&lt;/code&gt;. You don't want to launch the script with the
&lt;code&gt;DISPLAY&lt;/code&gt; set to the nested X server, since then it would launch
also launch &lt;code&gt;gv&lt;/code&gt; inside the nested X server. Instead, construct the
AnyEvent::I3 instance as follows, for a nested X server running on
&lt;code&gt;DISPLAY=:1&lt;/code&gt;:
&lt;/p&gt;

&lt;pre&gt;
chomp(my $path = qx(DISPLAY=:1 i3 --get-socketpath));
my $i3 = i3($path);
&lt;/pre&gt;

&lt;p&gt;
Now that I can use my editor reliably and query what's going on in a controlled
testing environment, I should be able to make some real progress.
&lt;/p&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/i3-manual-placement2/</guid><pubDate>Tue, 07 May 2013 04:39:00 GMT</pubDate></item><item><title>Manual Window Placement in i3 (Part 1)</title><link>http://ongardie.net/blog/i3-manual-placement/</link><description>&lt;p&gt;
I've been using
&lt;a href="http://en.wikipedia.org/wiki/Tiling_window_manager"&gt;tiling window managers&lt;/a&gt;
for the past couple of years. I started with
&lt;a href="http://en.wikipedia.org/wiki/Awesome_(window_manager)"&gt;awesome&lt;/a&gt;,
then
&lt;a href="http://notion.sourceforge.net/"&gt;Notion&lt;/a&gt; (a fork of
&lt;a href="http://en.wikipedia.org/wiki/Ion_(window_manager)"&gt;Ion&lt;/a&gt;; Ion is
no longer maintained),
and now I'm in the process of moving to
&lt;a href="http://en.wikipedia.org/wiki/I3_(window_manager)"&gt;i3&lt;/a&gt;.
For those of you that aren't familiar with it, the screenshots all look the
same. They all behave differently, though, and I guess you just have to find
one that fits your mental model.
&lt;/p&gt;

&lt;p&gt;
When you open a new window in most tiling window managers, your existing
windows get rearranged or resized to make room for it. This is kind of one main
idea, actually, and it works reasonably well when opening your second or third
window. Beyond two or three, depending on the screen size and applications, it
starts to suck.
&lt;/p&gt;

&lt;p&gt;
Awesome is a
&lt;a href="http://en.wikipedia.org/wiki/Dynamic_window_manager"&gt;dynamic window manager&lt;/a&gt;,
meaning it assigns each workspace a layout, and that layout determines how
windows are placed as they are opened. A common layout involves a spiral of
ever-shrinking window sizes. The first window opened will occupy the entire
screen. The second window will take half the real estate from the first. Then
the third window will take half the real estate from the second, etc.
&lt;/p&gt;

&lt;p&gt;
The net result of this dynamic approach, however, is that window placement is
unstable. When you launch a window (in a large enough tile to see the
contents), your other windows get displaced and resized to make room.
This is the single reason why I switched from awesome to Notion.
&lt;/p&gt;

&lt;p&gt;
Notion's approach is very simple but powerful. Every tile is actually a
tabbed set of windows. If you launch a new window, it creates a new tab
in the same container. You get three commands for managing windows:
split a container vertically, split a container horizontally, and
unsplit. Split containers can be nested arbitrarily.
&lt;/p&gt;

&lt;p&gt;
I really like Notion's basic approach. I just had a few minor gripes with
Notion as a whole. Looking over my list, I don't think any are show-stoppers,
and most of them I could probably fix with some configuration or minor hacks.
&lt;/p&gt;

&lt;p&gt;
But I happened to come across i3, and I was impressed by the way they're
managing their project. I'd recommend checking out their &lt;a
href="http://i3wm.org/screenshots/"&gt;videos&lt;/a&gt;, including the lead developer's
hour-long Google tech talk. Rare for these sorts of projects, it aims for
well-documented code, has automated tests, and has an active community.
&lt;/p&gt;

&lt;p&gt;
I was hoping i3 would work like Notion out of the box, but unfortunately their
model is a bit different. i3 and Notion support the same layouts in principle:
i3 splits workspaces into nested containers, where each container is either
tabbed, split horizontally, or split vertically. However, i3 behaves differently
when placing a new window. If you're in a tabbed container, yes, it creates a
new tab. But if you're in a split container, it creates a new split, resizing
your existing windows in that container. That's not what I want.
&lt;/p&gt;

&lt;p&gt;
I'm not seeing any options to control this behavior, so it looks like I'm going
to have to get my hands dirty and hack it up myself. Given their container
model, it shouldn't be too hard in principle. I guess what I want is:
if you're opening a window as part of a tabbed container, open a new tab (no
change from before). If you're opening a window as part of a split container,
put the current window in a tabbed subcontainer, and create the new window as a
new tab there. Maybe that's it?
&lt;/p&gt;

&lt;p&gt;
So I don't lose my place, the
&lt;a href="http://build.i3wm.org/docs/hacking-howto.html#_manage_windows_src_main_c_manage_window_and_reparent_window"&gt;hacking howto&lt;/a&gt;
has a couple of sections that seem relevant:
"8. Manage windows (src/main.c, manage_window() and reparent_window())"
and "9. What happens when an application is started?".
More on this later once I've jumped into the code...
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Update:&lt;/strong&gt; &lt;a href="http://ongardie.net/blog/i3-manual-placement2"&gt;part 2&lt;/a&gt;
explains how I set up my test environment.
&lt;/p&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/i3-manual-placement/</guid><pubDate>Wed, 01 May 2013 07:22:00 GMT</pubDate></item><item><title>Is It Worth the Time?</title><link>http://ongardie.net/blog/worth-the-time/</link><description>&lt;p&gt;
Today's &lt;a href="http://xkcd.com"&gt;XKCD&lt;/a&gt; starts to answer: how much time
should I spend making a routine task faster?
&lt;/p&gt;

&lt;a href="http://xkcd.com/1205/"&gt;&lt;img src="http://imgs.xkcd.com/comics/is_it_worth_the_time.png" alt="XKCD 1205: Is It Worth the Time?" /&gt;&lt;/a&gt;

&lt;p&gt;
I really like this comic. As a Ph.D. student, I have a lot of control over how
I spend my time, and this question comes up a lot. (I'm even writing about
analyzing how I spend my time.) Relative to the people I work with, I think I
err on the side of spending more time optimizing my workflow, and I think
programmers in general tend to do this more than others.
&lt;/p&gt;

&lt;p&gt;
Obviously you shouldn't spend all your time optimizing. We joke that one
optimizing friend (Aleks) will only need one keystroke by the time he's done;
it'll set off some sort of complex scheme for something-or-other. The details
are moot, of course, since he'll never reach that point.
&lt;/p&gt;

&lt;p&gt;
Still, I don't think Randall's chart is the definitive answer. It can be rational
to spend more time "optimizing" than you'd naïvely expect to shave off:
&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;
&lt;p&gt;
You may grossly underestimate how much time you shave off. If you're
eliminating a frustration, in particular, the expected time should include lost
productivity due to becoming frustrated. If these minor frustrations add up,
eventually you'll just shut down.
&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;
Improvements to your workflow can be shared if they apply to other people; this
multiplies their effect. This is why I'd rather have my labmates use the same
tools as me.
&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;
Although doing a routine task is usually not interesting, optimizing a routine
task often is. So at least for me, the path to getting something done may be
shorter through optimization rather than through procrastination.
&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;
Improving your workflow makes you faster at improving
your workflow. The experience and knowledge gained while doing this leads
to making faster improvements next time around. It also exposes low-hanging
fruit for other workflow improvements you may not have considered.
This argument may seem circular, but it's not: you're shaving time off future
optimizations, which shaves time off tasks that you wouldn't have otherwise
optimized.
&lt;/p&gt;
&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;
These arguments aren't earth-shaking, but at least there's some ammunition to
use in defense of over-optimizing.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Update:&lt;/strong&gt; Cory Doctorow made some good
&lt;a href="http://boingboing.net/2013/04/29/how-much-time-should-you-spend.html"&gt;counter-arguments&lt;/a&gt;
on Boing Boing.
&lt;/p&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/worth-the-time/</guid><pubDate>Mon, 29 Apr 2013 23:38:00 GMT</pubDate></item><item><title>Bullets in Inkscape</title><link>http://ongardie.net/blog/inkscape-bullets/</link><description>&lt;p&gt;
&lt;a href="http://inkscape.org"&gt;Inkscape&lt;/a&gt; is a good, open-source drawing
program for vector graphics. I'm currently using it to make a research poster,
but unfortunately, Inkscape doesn't do bullets. This post discusses your
options if you want to use bullets in your Inkscape drawing and introduces a
simple Inkscape extension that makes this much easier.
&lt;/p&gt;

&lt;p&gt;
Your first option is to use an external program like Scribus or Tex to generate
the bullets and text, then import that into Inkscape. This seems like a lot of
work to me. I don't want to flip between different programs or files for this.
&lt;/p&gt;

&lt;p&gt;
The second option is to draw the bullets manually &lt;em&gt;next to&lt;/em&gt; your text
box. This is pretty time-consuming, but it works if you have just a few bullets
to place and your text won't change much. A circle is a sane choice, but you
can use whatever you want as a bullet.
&lt;/p&gt;

&lt;p&gt;
The third option is to place Unicode bullets manually &lt;em&gt;inside&lt;/em&gt; your text
box. To do this, you're limited to using Unicode characters such as bullets,
triangles, and dashes. You can find these on the Internet and copy-and-paste
these into your text boxes. The main drawback with this approach is spacing: if
you wrap your line, you need to insert spacing to indent the next line. The
best way to get the same indent level as you had on the line above is to insert
the same exact Unicode character as before, but this time make it transparent
(or white). This is workable, but it gets really tedious if you have a lot of
bullets. It's even more tedious if you want bullets of a different color
&amp;mdash; in my case, I wanted blue bullets and black text.
&lt;/p&gt;

&lt;p&gt;
I created a simple Inkscape extension to make the third approach more
tolerable. The basic idea is to just replace strings in text boxes with
bullets and spacing. It's easiest if I just show you:
&lt;/p&gt;
&lt;img src="http://ongardie.net/var/blog/inkscape-bullets/beforeafter.png" alt="extension transforms special characters into bullets" /&gt;

&lt;p&gt;
Every time you run the extension, it applies the following replacements:
&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th colspan="2"&gt;Input&lt;/th&gt;
&lt;th&gt;Replaced with&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;*&amp;nbsp;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;asterisk space space&lt;/td&gt;
&lt;td&gt;top-level bullet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;#92;&amp;nbsp;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;backslash space space&lt;/td&gt;
&lt;td&gt;indent same as top-level bullet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;&lt;/td&gt;
&lt;td&gt;space space space dash space&lt;/td&gt;
&lt;td&gt;second-level bullet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#92;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;space space space backslash space&lt;/td&gt;
&lt;td&gt;indent same as second-level bullet&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;
Here's how to add this extension to Inkscape. You'll need to create two files
in &lt;code&gt;~/.config/inkscape/extensions/&lt;/code&gt;. The first file,
&lt;a href="http://ongardie.net/var/blog/inkscape-bullets/bullets.inx"&gt;bullets.inx&lt;/a&gt;,
describes to Inkscape how to display and run the extension; it's just
boilerplate. The second file,
&lt;a href="http://ongardie.net/var/blog/inkscape-bullets/bullets.sh"&gt;bullets.sh&lt;/a&gt;,
is the code that gets executed when you run the extension:
&lt;/p&gt;
&lt;pre&gt;
#!/bin/bash

# top-level bullet and space
bullet='&amp;lt;tspan style="fill:#3465a4;"&amp;gt;●&amp;lt;&amp;#92;/tspan&amp;gt; '
bulletnext='&amp;lt;tspan style="fill:none;"&amp;gt;●&amp;lt;&amp;#92;/tspan&amp;gt; '

# second-level bullet and space
dash=$bulletnext'&amp;lt;tspan style="fill:#3465a4;"&amp;gt; –&amp;lt;&amp;#92;/tspan&amp;gt; '
dashnext=$bulletnext'&amp;lt;tspan style="fill:none;"&amp;gt; –&amp;lt;&amp;#92;/tspan&amp;gt; '

# the last argument to this script is the filename read from
shift $(( $# - 1 ))
f=$1

sed -e "s/&amp;#92;&amp;#92;*  /$bullet/" &amp;#92;
    -e "s/&amp;#92;&amp;#92;&amp;#92;&amp;#92;  /$bulletnext/" &amp;#92;
    -e "s/   - /$dash/"  &amp;#92;
    -e "s/   &amp;#92;&amp;#92;&amp;#92;&amp;#92; /$dashnext/" &amp;#92;
    $f
&lt;/pre&gt;

&lt;p&gt;
As you can see, there's not much magic here. The script just runs
&lt;code&gt;sed&lt;/code&gt; to find-and-replace a few strings with Unicode characters of
the desired color.
&lt;/p&gt;

&lt;p&gt;
And that's it. It's not the prettiest thing in the world, but now you can
create bullets in Inkscape without tearing your hair out.
&lt;/p&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/inkscape-bullets/</guid><pubDate>Sun, 14 Apr 2013 03:12:00 GMT</pubDate></item><item><title>Color GDB Prompt</title><link>http://ongardie.net/blog/gdb-color/</link><description>&lt;p&gt;
To add color to your GDB prompt, place the following in your &lt;code&gt;~/.gdbinit&lt;/code&gt; file:
&lt;/p&gt;
&lt;pre&gt;
# keep trailing space on next line
set prompt \033[0;33m(gdb)\033[0m&amp;nbsp;
&lt;/pre&gt;
&lt;p&gt;
This makes it easier to find your place visually.
&lt;/p&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/gdb-color/</guid><pubDate>Sun, 07 Apr 2013 21:50:00 GMT</pubDate></item><item><title>Leveraging Web Technologies for Local Programs</title><link>http://ongardie.net/blog/node-webkit/</link><description>&lt;p&gt;
Client-side web programming (HTML, JavaScript, CSS) has improved greatly in
recent years. You could make a reasonable argument that this is the best
environment for building user interfaces today: it's quick, it looks decent,
there are tons of libraries and stylesheets available, and the
developer tools are quite good. Firefox even has a
&lt;a href="https://developer.mozilla.org/en-US/docs/Tools/Page_Inspector/3D_view"&gt;3D Inspector&lt;/a&gt;
view these days &amp;mdash; if that doesn't convince you, I don't know what will.
&lt;/p&gt;

&lt;p&gt;
Meanwhile, &lt;a href="nodejs.org"&gt;node.js&lt;/a&gt; has become a reasonable platform
for server-side JavaScript that interacts with the outside world. Node provides
libraries for accessing the filesystem, making network requests (not just
HTTP), and running arbitrary processes. And it has over 25,000 third-party
libraries to help you out.
&lt;/p&gt;

&lt;p&gt;
This environment already makes sense for building local applications. You'd run
a node.js server locally to handle interaction with the outside world, and
you'd load up a web page in your browser to provide the user interface. Your
browser and server would communicate over HTTP requests as usual.
Hide the browser's toolbars and it doesn't even look out of place.
&lt;/p&gt;

&lt;p&gt;
The &lt;a href="https://github.com/rogerwang/node-webkit"&gt;node-webkit&lt;/a&gt; project
takes this one forward: it integrates the node.js libraries into a
&lt;a href="http://www.webkit.org"&gt;Webkit&lt;/a&gt; environment. So now
instead of splitting your local application into a server and a client
component, having these communicate over HTTP, and having to launch these
separately, you can structure these applications in a much simpler way. There's
no HTTP involved: your JavaScript just acts on user input directly, calling
into node.js libraries when it needs to.
&lt;/p&gt;

&lt;p&gt;
I've been playing around with node-webkit a bit the last few days, and I must
say I'm impressed with how productive of an environment it is to program in.
The number of JavaScript libraries out there really makes up for the ugly bits
of the language. I feel like I've been shying away from building graphical
applications because of the overhead of doing so with something like PyGTK; I
think node-webkit might change this. Node-webkit applications require so little
boilerplate that this approach makes sense even for one-off scripts where you'd
like user interaction.
&lt;/p&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/node-webkit/</guid><pubDate>Thu, 04 Apr 2013 04:38:00 GMT</pubDate></item><item><title>SQLite Database in Git</title><link>http://ongardie.net/blog/sqlite-in-git/</link><description>&lt;p&gt;
I store nearly all files of even moderate importance in
&lt;a href="http://git-scm.com"&gt;Git&lt;/a&gt; (including this blog post). These are
usually plain-text files, but sometimes it's necessary to put binary files
under version control. Unfortunately, those are typically difficult to diff and
merge, but I recently discovered some features of Git that make this less
painful. This blog post focuses on &lt;a href="http://www.sqlite.org"&gt;SQLite&lt;/a&gt;
database files, but at least some of it applies to other binary file types.
&lt;/p&gt;

&lt;p&gt;
My problem specifically involved managing changes to an SQLite database that
contained results for a research study. The database was changing as new
results arrived and were processed, and it was important to me to track its
changes in case of manual or programming errors.
&lt;/p&gt;

&lt;p&gt;
SQLite stores its database in a pretty complex format
(&lt;a href="http://www.sqlite.org/fileformat2.html"&gt;described here&lt;/a&gt;).
While diffing two SQLite databases can sometimes be human-readable, this
entirely depends on the binary that happens to fall right around the modified
values. It's doable but sometimes requires a lot of annoying horizontal
scrolling past screenfuls of control characters. Life's too short for that.
&lt;/p&gt;

&lt;p&gt;
SQLite can dump entire databases out as SQL statements, and Git can be
configured to do this when generating diffs. In a
&lt;code&gt;.gitattributes&lt;/code&gt; or &lt;code&gt;.git/info/attributes&lt;/code&gt; file, give
Git a filename pattern and the name of a diff driver, which we'll define
next. In my case, I added:
&lt;/p&gt;
&lt;pre&gt;
db.sqlite3 diff=sqlite3
&lt;/pre&gt;

&lt;p&gt;
Then in &lt;code&gt;.git/config&lt;/code&gt; or &lt;code&gt;$HOME/.gitconfig&lt;/code&gt;, define the diff driver. Mine looks like:
&lt;/p&gt;
&lt;pre&gt;
[diff "sqlite3"]
    textconv = dumpsqlite3
&lt;/pre&gt;

&lt;p&gt;
I chose to define an external &lt;code&gt;dumpsqlite3&lt;/code&gt; script, since this can
be useful elsewhere. It just dumps SQL to stdout for the filename given by its
first argument:
&lt;/p&gt;
&lt;pre&gt;
#!/bin/sh
sqlite3 $1 .dump
&lt;/pre&gt;

&lt;p&gt;
At this point, &lt;code&gt;git diff&lt;/code&gt; should show you plain-text diffs, as
should browsing Git commits. There's still one problem left: sometimes SQLite's
binary database will change, but the actual database contents remain the same.
This results in a &lt;code&gt;git status&lt;/code&gt; that says the database has changed
but a &lt;code&gt;git diff&lt;/code&gt; that says it hasn't.
&lt;/p&gt;

&lt;p&gt;
I don't know enough about SQLite to know why this happens. I thought it was
because SQLite doesn't compact free space right away in its database files, but
I ran into a case where even if I vacuum two database files with identical
contents, they still have different binaries.
&lt;/p&gt;

&lt;p&gt;
One brute solution would be to dump the database contents to SQL and read
them back into a "fresh" SQLite database. This should result in a canonical
binary database, since SQLite doesn't seem to store anything like a
timestamp in there. I suspect you could have your diff driver do this
automatically every time it runs, but I haven't tried it yet.
&lt;/p&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/sqlite-in-git/</guid><pubDate>Thu, 04 Apr 2013 02:16:00 GMT</pubDate></item><item><title>rlwrap: readline Wrapper Program</title><link>http://ongardie.net/blog/rlwrap/</link><description>&lt;p&gt;
Dealing with a basic command-line prompt in a loop can be painful, so many
programs, such as shells, interactive programming languages and debuggers,
provide a more featureful prompt. For example, pressing the up and down arrows
in a good prompt will flip through previously entered input lines. Programs
will often make use of the
&lt;a href="http://www.gnu.org/s/readline/"&gt;GNU readline library&lt;/a&gt; for this
functionality.
&lt;/p&gt;

&lt;p&gt;
If you need to use a program that only has a basic prompt, you may be able to
wrap it with the program
&lt;a href="http://utopia.knoware.nl/~hlub/uck/rlwrap/#rlwrap"&gt;rlwrap&lt;/a&gt; to get
some more advanced features. From the man page:
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
rlwrap  runs  the  specified command, intercepting user input in order to
provide readline's line editing, persistent history and completion.
&lt;/p&gt;
&lt;p&gt;[...]&lt;/p&gt;
&lt;p&gt;
There are many options to add (programmable) completion, handle multi-line
input, colour and re-write prompts. If  you  don't need them (and you probably
don't), you can skip the rest of this manpage.
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
For example, I recently used rlwrap with jdb, the Java debugger, and Ikarus, a
Scheme compiler.
&lt;/p&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/rlwrap/</guid><pubDate>Thu, 29 Dec 2011 01:56:00 GMT</pubDate></item><item><title>The Cost of Exceptions of C++</title><link>http://ongardie.net/blog/exceptions/</link><description>&lt;p&gt;
Most people seem to have an opinion as to whether exceptions in C++ are slow or
fast, but very few people have put any useful numbers out there. Here's a lower
bound:
&lt;/p&gt;

&lt;pre&gt;
&lt;font face="monospace"&gt;
&lt;font color="#c000c0"&gt;#include &lt;/font&gt;&lt;font color="#c00000"&gt;&amp;lt;inttypes.h&amp;gt;&lt;/font&gt;
&lt;font color="#c000c0"&gt;#include &lt;/font&gt;&lt;font color="#c00000"&gt;&amp;lt;stdio.h&amp;gt;&lt;/font&gt;

&lt;font color="#008000"&gt;const&lt;/font&gt;&amp;nbsp;&lt;font color="#008000"&gt;uint64_t&lt;/font&gt;&amp;nbsp;count = &lt;font color="#c00000"&gt;1000000&lt;/font&gt;;

&lt;font color="#008000"&gt;inline&lt;/font&gt;&amp;nbsp;&lt;font color="#008000"&gt;uint64_t&lt;/font&gt;
rdtsc()
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#008000"&gt;uint32_t&lt;/font&gt;&amp;nbsp;lo, hi;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#af5f00"&gt;asm&lt;/font&gt;&amp;nbsp;&lt;font color="#008000"&gt;volatile&lt;/font&gt;(&lt;font color="#c00000"&gt;&amp;quot;rdtsc&amp;quot;&lt;/font&gt;&amp;nbsp;: &lt;font color="#c00000"&gt;&amp;quot;=a&amp;quot;&lt;/font&gt;&amp;nbsp;(lo), &lt;font color="#c00000"&gt;&amp;quot;=d&amp;quot;&lt;/font&gt;&amp;nbsp;(hi));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#af5f00"&gt;return&lt;/font&gt;&amp;nbsp;(((&lt;font color="#008000"&gt;uint64_t&lt;/font&gt;) hi &amp;lt;&amp;lt; &lt;font color="#c00000"&gt;32&lt;/font&gt;) | lo);
}

&lt;font color="#008000"&gt;int&lt;/font&gt;
main()
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000c0"&gt;// Measure the cost of throwing and catching an int.&lt;/font&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#008000"&gt;uint64_t&lt;/font&gt;&amp;nbsp;start = rdtsc();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#af5f00"&gt;for&lt;/font&gt;&amp;nbsp;(&lt;font color="#008000"&gt;uint64_t&lt;/font&gt;&amp;nbsp;i = &lt;font color="#c00000"&gt;0&lt;/font&gt;; i &amp;lt; count; i++) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#af5f00"&gt;try&lt;/font&gt;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#af5f00"&gt;throw&lt;/font&gt;&amp;nbsp;&lt;font color="#c00000"&gt;0&lt;/font&gt;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} &lt;font color="#af5f00"&gt;catch&lt;/font&gt;&amp;nbsp;(&lt;font color="#008000"&gt;int&lt;/font&gt;) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000c0"&gt;// do nothing&lt;/font&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#008000"&gt;uint64_t&lt;/font&gt;&amp;nbsp;stop = rdtsc();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(&lt;font color="#c00000"&gt;&amp;quot;Cycles per exception: &lt;/font&gt;&lt;font color="#c000c0"&gt;%lu&lt;/font&gt;&lt;font color="#c000c0"&gt;\n&lt;/font&gt;&lt;font color="#c00000"&gt;&amp;quot;&lt;/font&gt;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (stop - start) / count);
}
&lt;/font&gt;
&lt;/pre&gt;

&lt;p&gt;
The code just measures the time it takes to throw the number 0 as an exception
and catch it.
&lt;/p&gt;

&lt;p&gt;
Using g++ version 4.4.4, compiled with -O3 in 64-bit mode, and running on an
otherwise idle Intel Xeon E5620 CPU at 2.4 GHz, this benchmark takes 2.18 to
2.21 microseconds on average per exception.
&lt;/p&gt;

&lt;p&gt;
So the cheapest exceptions on a modern CPU would cost about 2 microseconds.
When you throw an exception in a real project rather than a microbenchmark,
this cost is significantly higher. Anecdotally, we typically see times closer
to 5 microseconds for exceptions in the context of &lt;a
href="http://ramcloud.stanford.edu"&gt;RAMCloud&lt;/a&gt;, the project I work on at
school.
&lt;/p&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/exceptions/</guid><pubDate>Thu, 10 Nov 2011 19:25:00 GMT</pubDate></item><item><title>Shared Feed Items</title><link>http://ongardie.net/blog/shared-feed/</link><description>&lt;img style="float:right" src="http://ongardie.net/var/blog/shared-feed/reader_logo.jpg" alt="Google Reader logo" /&gt;

&lt;p&gt;
Lately, I've been sharing items from my news feeds on Google Reader that I find
interesting. You can view these
&lt;a href="http://www.google.com/reader/shared/ongardie"&gt;on the web&lt;/a&gt;
or as an
&lt;a href="http://www.google.com/reader/public/atom/user%2F11643238364635815369%2Fstate%2Fcom.google%2Fbroadcast"&gt;Atom feed&lt;/a&gt;.
(You don't need to be a Google Reader user yourself to view my shared items.)
&lt;/p&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/shared-feed/</guid><pubDate>Sun, 14 Mar 2010 06:34:00 GMT</pubDate></item><item><title>Upgrading to Debian Squeeze</title><link>http://ongardie.net/blog/squeeze/</link><description>&lt;a href="http://www.debian.org/" alt="www.debian.org"&gt;&lt;img style="float:right" src="http://ongardie.net/var/blog/squeeze/debian_logo.png" alt="Debian logo" /&gt;&lt;/a&gt;

&lt;p&gt;
I've switched my laptop over from Debian Lenny (stable) to Squeeze (testing).
While I made it this far with the aging software available in Lenny by
pulling newer packages from backports and unstable, I finally gave in for
Python 2.6.
&lt;/p&gt;

&lt;p&gt;
In case it helps anyone else, my laptop is a Lenovo Thinkpad T61 with an Intel
graphics chip and wifi card. Much of what broke is related to
&lt;a href="http://en.wikipedia.org/wiki/Mode-setting#Linux"&gt;kernel mode-setting (KMS)&lt;/a&gt;.
Here's the list:
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I had &lt;code&gt;vga=794&lt;/code&gt; in my &lt;code&gt;/etc/default/grub&lt;/code&gt;, which is
no longer compatible. On Squeeze's kernel with this setting, the console
framebuffer did not display anything. I think the &lt;code&gt;GRUB_GFXMODE&lt;/code&gt;
variable is supposed to replace it.&lt;/li&gt;
&lt;li&gt;X failed to start and failed to let me switch back to the consoles on
Squeeze's kernel
(&lt;a href="http://packages.debian.org/squeeze/linux-image-2.6.32-trunk-amd64"&gt;linux-image-2.6.32-trunk-amd64&lt;/a&gt; 2.6.32-5).
I think you need an Intel graphics chip and 4GB of RAM to enjoy this bug (which
seems at least related to FreeDesktop's
&lt;a href="http://bugs.freedesktop.org/show_bug.cgi?id=25510"&gt;Bug #25510&lt;/a&gt;).
If you're so lucky, the kernel in unstable fixes the problem for me
(&lt;a href="http://packages.debian.org/unstable/linux-image-2.6.32-2-amd64"&gt;linux-image-2.6.32-2-amd64&lt;/a&gt; 2.6.32-8).&lt;/li&gt;
&lt;li&gt;I had a residual config file that apt did not purge at
&lt;code&gt;/etc/udev/rules.d/z60_xserver_xorg_input_wacom.rules&lt;/code&gt; that caused
screenfuls of warnings early in the boot process.&lt;/li&gt;
&lt;li&gt;Something has broken &lt;code&gt;ifconfig wlan0 up&lt;/code&gt; on boot, but an easy
work-around is to turn the hardware radio kill switch to off and then back
to on.&lt;/li&gt;
&lt;li&gt;Despite my efforts, Bluetooth is enabling itself. I'll have to find a way
to turn that off again.&lt;/li&gt;
&lt;li&gt;Instead of using &lt;code&gt;module-assistant&lt;/code&gt; to build the ThinkPad SMAPI
module, I installed the &lt;code&gt;tp-smapi-dkms&lt;/code&gt; package.&lt;/li&gt;
&lt;li&gt;IPython doesn't ship with &lt;code&gt;/usr/bin/ipython2.6&lt;/code&gt; yet, but copying
&lt;code&gt;/usr/bin/ipython2.5&lt;/code&gt; seems to work fine. (It uses &lt;code&gt;$0&lt;/code&gt;
to determine which version of Python to call.)&lt;/li&gt;
&lt;/ul&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/squeeze/</guid><pubDate>Sun, 21 Feb 2010 23:48:00 GMT</pubDate></item><item><title>Book Log</title><link>http://ongardie.net/blog/book-log/</link><description>&lt;p&gt;
&lt;p&gt;
In addition to my &lt;a href="http://ongardie.net/misc/movies/"&gt;movie log&lt;/a&gt;, I've now
started a &lt;a href="http://ongardie.net/misc/books/"&gt;book log&lt;/a&gt; going back to last
summer.
&lt;/p&gt;

&lt;h2&gt;100 Movies by May 10th?&lt;/h2&gt;
&lt;p&gt;
In other news, the movie log is now up to 87 films. I hadn't yet cranked out
any numbers with it, but this announcement is as good a time as any to start,
right?
&lt;/p&gt;

&lt;p&gt;
The movie log seems to grow roughly linearly over time. Assuming that a linear
model fits the data and that I am capable of basic statistics (neither of which
we should count on), I will have watched 100 films by the 716th day since the
start of the log, which comes out to May 10, 2010. Here's a pretty graph:
&lt;img style="display: block; margin-left: auto; margin-right: auto" src="http://ongardie.net/var/blog/book-log/movies_over_time.png" alt="movies watched over time" /&gt;
&lt;/p&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/book-log/</guid><pubDate>Sun, 14 Feb 2010 05:19:00 GMT</pubDate></item><item><title>Rice.edu Email Account Deleted</title><link>http://ongardie.net/blog/rice-email/</link><description>&lt;p&gt;
Rice has deleted my undergraduate email account, diego.ongaro@rice.edu , since
I am no longer a student there. If you tried to send to that address and
received a bounce notification, please resend your email to the same username at
alumni.rice.edu instead.
&lt;/p&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/rice-email/</guid><pubDate>Mon, 30 Nov 2009 07:21:00 GMT</pubDate></item><item><title>Twin Peaks iPhone Panorama</title><link>http://ongardie.net/blog/twin-peaks/</link><description>&lt;p&gt;
I went up to
&lt;a href="http://en.wikipedia.org/wiki/Twin_Peaks_(San_Francisco,_California)"&gt;Twin Peaks&lt;/a&gt;
in San Francisco with &lt;a href="http://jicksta.com"&gt;Jay&lt;/a&gt; a few weeks ago. It
was a nice view but kind of a worst-case scenario for a photo: my iPhone camera
(VGA), poor lighting as the sun was setting, and stong winds.
&lt;/p&gt;
&lt;p&gt;
That day I took a bunch of overlapping shots with my phone. Then I used the
&lt;a href="http://www.gimp.org"&gt;GIMP&lt;/a&gt;'s automatic white balance correction on
each of them. Next I stitched them together with
&lt;a href="http://hugin.sourceforge.net"&gt;Hugin&lt;/a&gt;, and finally I edited
the stitched image with the GIMP. The following mediocre image is the result
(&lt;a href="http://ongardie.net/var/blog/twin-peaks/pan_large.jpg"&gt;click&lt;/a&gt;
for the full 1534x652 image):
&lt;/p&gt;

&lt;a href="http://ongardie.net/var/blog/twin-peaks/pan_large.jpg"&gt;
&lt;img src="http://ongardie.net/var/blog/twin-peaks/pan_small.jpg" alt="panorama" /&gt;
&lt;/a&gt;

&lt;p&gt;
The 1 megapixel result really wasn't worth the time. Even in the thumbnail,
it's easy to see that multiple source images are contributing their different
colors and brightness levels. Maybe Hugin could correct for more of this with
the proper settings, but I haven't taken the time to learn it well enough to
know how. Although mine has a slightly larger angle, I think
&lt;a href="http://en.wikipedia.org/wiki/File:San_Francisco_panorama_from_Twin_Peaks.jpg"&gt;the one on wikipedia&lt;/a&gt;
still wins.
&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;
I also took this suprising shot:
&lt;/p&gt;
&lt;img src="http://ongardie.net/var/blog/twin-peaks/slanted.jpg" alt="slanted Golden Gate bridge" /&gt;

&lt;p&gt;
It turns out the iPhone's cheap camera scans horizontally from top to bottom.
As I was in a car moving left, the lines lower on the image were scanned later
and appear shifted to the right. Kirk Mastin has an
&lt;a href="http://lofihistyle.com/2008/11/iphone-rolling-shutter-creative/"&gt;interesting post&lt;/a&gt;
about this rolling shutter effect and what you can do with it.
Jeffrey Erlich also has an awesome
&lt;a href="http://www.flickr.com/photos/jerlich/sets/72157614852342118/with/3331783600/"&gt;album&lt;/a&gt;
that makes use of this effect.
&lt;/p&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/twin-peaks/</guid><pubDate>Sun, 08 Nov 2009 02:27:00 GMT</pubDate></item><item><title>Xfce Stopwatch Plugin</title><link>http://ongardie.net/blog/stopwatch/</link><description>&lt;p&gt;
I needed an excuse to try &lt;a href="http://mmassonnet.blogspot.com"&gt;Mike&lt;/a&gt;'s
&lt;a href="http://git.xfce.org/bindings/xfce4-vala/"&gt;Vala bindings for Xfce&lt;/a&gt;,
so I created a new little plugin for the panel, the
&lt;a href="http://goodies.xfce.org/projects/panel-plugins/xfce4-stopwatch-plugin"&gt;xfce4-stopwatch-plugin&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
In the original release announcement on July 28th, I wrote:
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
This is the first release of the stopwatch panel plugin, which you can
use to time yourself on different tasks. It's stable and usable, but
quite minimal still.
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
The functionality is best summarized with this image from the web site:
&lt;img src="http://ongardie.net/var/blog/stopwatch/help.png" alt="screenshots" /&gt;
&lt;/p&gt;

&lt;h2&gt;Vala&lt;/h2&gt;
&lt;p&gt;
From their web site,
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
&lt;a href="http://live.gnome.org/Vala"&gt;Vala&lt;/a&gt; is a new programming language
that aims to bring modern programming language features to GNOME developers
without imposing any additional runtime requirements and without using a
different ABI compared to applications and libraries written in C.
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
Instead of having to write tons of
&lt;a href="http://library.gnome.org/devel/gobject/unstable/howto-gobject.html"&gt;boilerplate code&lt;/a&gt;
to create new GObjects in C and for other common tasks in developing GTK-based
applications, Vala builds these features into the language. The Vala code you
write passes through the Vala compiler, which produces GObject-based C code.
From there, GCC compiles that to a binary as usual. There is no runtime, so
Vala-produced code can run as fast as hand-coded C.
&lt;/p&gt;

&lt;p&gt;
Vala makes it easy to write fast, object-oriented code for GTK-based projects.
With Mike's Xfce bindings for Vala, you gain access to Xfce's libraries from
Vala, letting you write panel plugins or other Xfce projects in Vala. It's a
cool idea and something I definitely wanted to try.
&lt;/p&gt;

&lt;h2&gt;Developing the Stopwatch Plugin&lt;/h2&gt;
&lt;p&gt;
In general, Vala is pretty easy to write if you've worked with GObject before.
I did hit a few bugs while developing even this simple plugin, so it's evident
that Vala and the Xfce bindings aren't mature yet:
&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;
I filed &lt;a href="http://bugzilla.gnome.org/show_bug.cgi?id=587150"&gt;GNOME Bug 587150&lt;/a&gt;,
a bug in Vala's POSIX bindings for the &lt;code&gt;time_t&lt;/code&gt; type. Vala treats it
as a GObject instead of an integer, making it unusable to pass around your
program in many ways. This bug hasn't seen any attention yet, but I've worked
around it for Stopwatch by not using &lt;code&gt;time_t&lt;/code&gt;.
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Evan Nemerson fixed this one.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
I &lt;a href="http://git.xfce.org/bindings/xfce4-vala/commit/?id=f1695e8f95e9647db4989c968cf4768476272e0e"&gt;patched&lt;/a&gt;
a small bug in Xfce's Vala bindings for the
&lt;a href="http://www.xfce.org/documentation/4.6/api/libxfce4panel/XfceHVBox.html"&gt;XfceHVBox&lt;/a&gt;
widget. The Vala compiler was producing calls to &lt;code&gt;xfce_hv_box_new()&lt;/code&gt;
instead of &lt;code&gt;xfce_hvbox_new()&lt;/code&gt;, which of course caused a problem when
GCC tried to resolve the symbol.
&lt;/li&gt;

&lt;li&gt;
I also filed &lt;a href="http://bugzilla.gnome.org/show_bug.cgi?id=589930"&gt;GNOME Bug 589930&lt;/a&gt;,
a bug in Vala's generated code for &lt;code&gt;sscanf&lt;/code&gt;. It always added an
extra NULL argument at the end of the arguments list. Jürg Billeter fixed this
one quickly with
&lt;a href="http://git.gnome.org/cgit/vala/commit/?id=7d5a61e38664ceabfe6a903af38d057bdf831a4b"&gt;this commit&lt;/a&gt;,
which made it into Vala 0.7.5.
&lt;/li&gt;

&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;
Despite these hurdles, writing the Stopwatch plugin in Vala has been a
pleasure. Admittedly the plugin doesn't do much, but the code is very short and
straight-forward.
&lt;/p&gt;

&lt;p&gt;
Stopwatch will probably see just one or two more releases before it's
feature-complete. I'd also like to port the Places plugin to Vala at some
point, but I'm waiting to see how volume management plays out once
&lt;a href="http://gezeiten.org/post/2009/06/Preview:-Browsing-SFTP-with-Thunar"&gt;ThunarVFS is gone&lt;/a&gt;.
&lt;/p&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/stopwatch/</guid><pubDate>Mon, 17 Aug 2009 05:49:00 GMT</pubDate></item><item><title>Lighttpd Fails to Bind to Localhost</title><link>http://ongardie.net/blog/lighttpd-bind-localhost/</link><description>&lt;img style="float:left" src="http://ongardie.net/var/blog/lighttpd-bind-localhost/lighttpd_logo.png" alt="lighttpd logo" /&gt;

&lt;p&gt;
I installed the web server &lt;a href="http://www.lighttpd.net"&gt;lighttpd&lt;/a&gt;
on my laptop to test some configuration settings. As I didn't want to expose
the server on the network, I uncommented
&lt;code&gt;server.bind = "localhost"&lt;/code&gt; from
&lt;code&gt;/etc/lighttpd/lighttpd.conf&lt;/code&gt;.
&lt;/p&gt;

&lt;p style="clear: both"&gt;
Then, restarting lighttpd failed with the following error:
&lt;/p&gt;
&lt;pre&gt;
&lt;span style="display:none"&gt;(network.c.201)&lt;/span&gt;getaddrinfo failed:  Name or service not known ' localhost '
&lt;/pre&gt;

&lt;p&gt;
This is lighttpd 1.4.19-5 from main on Debian Lenny.
&lt;/p&gt;

&lt;p&gt;
I was still able to ping localhost and checked my &lt;code&gt;/etc/hosts&lt;/code&gt; file,
but everything seemed fine. Finally, I checked the line of code the error
points to (network.c line 201) and noticed it's part of an IPv6-specific chunk
of code.
&lt;/p&gt;

&lt;p&gt;
I found I could work around this issue by disabling IPv6 entirely in
&lt;code&gt;/etc/lighttpd/lighttpd.conf&lt;/code&gt;. For the uninitiated, comment out this
line:
&lt;/p&gt;
&lt;pre&gt;
&amp;#35;&amp;#35; Use ipv6 only if available.
include_shell "/usr/share/lighttpd/use-ipv6.pl"
&lt;/pre&gt;

&lt;h2&gt;Other Reports of This Issue&lt;/h2&gt;
&lt;p&gt;
A &lt;a href="http://forum.lighttpd.net/topic/64647"&gt;couple reports&lt;/a&gt; of the
same problem can be found on the old lighttpd forums, but no resolution was
reached. Unfortunately, I can't reply there because those forums are now
locked, and historical threads were not copied to lighttpd's new forums. The
first report was from Debian's 1.4.19-1 package, and the second report does not
identify the version.
&lt;/p&gt;

&lt;p&gt;
A &lt;a href="http://lists.debian.org/debian-user-spanish/2009/03/msg00751.html"&gt;post&lt;/a&gt;
on the debian-user-spanish list reports the same problem on Debian Lenny but
received no replies.
&lt;/p&gt;

&lt;p&gt;
That mailing list post does point to
&lt;a href="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=489063"&gt;Debian bug 489063&lt;/a&gt;
(which doesn't come up on Google when you search for the error message). There,
Pierre Habouzit, one of lighttpd's maintainers on Debian, suggests using
&lt;code&gt;server.bind = "::1"&lt;/code&gt; instead of &lt;code&gt;server.bind = "localhost"&lt;/code&gt;
when IPv6 is enabled. This will start up the server without errors, but then I
can only access it as &lt;code&gt;http://ip6-localhost/&lt;/code&gt; (not
&lt;code&gt;http://localhost/&lt;/code&gt;).
&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;
This is a pretty annoying little issue, and it hasn't fully been resolved.
At a minimum, this:
&lt;/p&gt;
&lt;pre&gt;
&amp;#35;&amp;#35; bind to localhost only (default: all interfaces)
# server.bind                = "localhost"
&lt;/pre&gt;
&lt;p&gt;
should be:
&lt;/p&gt;
&lt;pre&gt;
&amp;#35;&amp;#35; bind to localhost only (default: all interfaces)
&amp;#35;&amp;#35; use ::1 when IPv6 is enabled or localhost for IPv4
&amp;#35;&amp;#35; (see Debian bug #489063)
# server.bind                = "::1"
# server.bind                = "localhost"
&lt;/pre&gt;
&lt;p&gt;
That would at least point people in the right direction.
&lt;/p&gt;
&lt;p&gt;
I've sunk enough time into this for now, though.
I'll post an update here if I pursue this any further.
&lt;/p&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/lighttpd-bind-localhost/</guid><pubDate>Wed, 05 Aug 2009 17:21:00 GMT</pubDate></item><item><title>Chef Roger's Knife List</title><link>http://ongardie.net/blog/chef-roger-knives/</link><description>&lt;p&gt;
Last semester at Rice, I took the class Cooking with Chef Roger. The
man is passionate about his knives, and he gave us a list of brands he
recommends. From one of the few scraps of notes that survived, here is
Chef Roger Elkhouri's list of quality brands for chef's knives (French
knives):
&lt;/p&gt;

&lt;a style="float:right" href="http://commons.wikimedia.org/wiki/File:Chef's_Knife.jpg"&gt;&lt;img src="http://ongardie.net/var/blog/chef-roger-knives/chefs_knife.jpg" alt="chef's knife" /&gt;&lt;/a&gt;

&lt;h2&gt;Mid-Range Brands&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.cuisinart.com/"&gt;Cuisinart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.kitchenaid.com/"&gt;KitchenAid&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Top-of-the-Line Brands&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://usa.jahenckels.com/"&gt;J.A. Henckels&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.wusthof.com/"&gt;Wusthof&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.fdick.com/"&gt;Friedr. Dick&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.victorinox.com/"&gt;Victorinox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.global-knife.com/"&gt;Global&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.kershawknives.com/products.php?brand=shun"&gt;Shun&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/chef-roger-knives/</guid><pubDate>Sun, 02 Aug 2009 19:56:00 GMT</pubDate></item><item><title>Xorg.conf for QEMU/KVM</title><link>http://ongardie.net/blog/qemu-xorg/</link><description>&lt;p&gt;
If you want to use a large resolution with a QEMU or KVM virtual
machine, you'll need to manually specify a few things in xorg.conf.
Out of the box, you can usually only use resolutions up to 800x600,
although Fedora and Ubuntu have
&lt;a href="https://bugzilla.redhat.com/show_bug.cgi?id=251264"&gt;patched this&lt;/a&gt;
up to 1024x768.
&lt;/p&gt;

&lt;p&gt;
I created this
&lt;a href="http://ongardie.net/var/blog/qemu-xorg/xorg.conf"&gt;xorg.conf&lt;/a&gt;
to work with larger resolutions. With it, I was able to use up to
1280x1024 with the default emulated graphics and up to 1920x1200 when
passing the &lt;code&gt;-std-vga&lt;/code&gt; option to QEMU or KVM.
&lt;/p&gt;

&lt;p&gt;
To make use of this:
&lt;/p&gt;
&lt;ol&gt;
 &lt;li&gt;
    Back up your existing &lt;code&gt;/etc/X11/xorg.conf&lt;/code&gt; in your
    virtual machine, if any.
 &lt;/li&gt;
 &lt;li&gt;
    Save the file to &lt;code&gt;/etc/X11/xorg.conf&lt;/code&gt; in your virtual
    machine:
&lt;pre&gt;
sudo wget -O /etc/X11/xorg.conf &amp;#92;
http://ongardie.net/var/blog/qemu-xorg/xorg.conf
&lt;/pre&gt;
  &lt;/li&gt;
  &lt;li&gt;
    If you want to use a resolution other than 1280x1024, modify the
&lt;code&gt;Modes&lt;/code&gt; line to suit your needs.
  &lt;/li&gt;
  &lt;li&gt;
    Start or restart your virtual machine's X server.
  &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
If you're having problems, try passing QEMU/KVM the &lt;code&gt;-std-vga&lt;/code&gt; flag.
&lt;/p&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/qemu-xorg/</guid><pubDate>Wed, 01 Jul 2009 05:02:00 GMT</pubDate></item><item><title>Cgit Hacking</title><link>http://ongardie.net/blog/cgit-hacking/</link><description>&lt;img src="http://ongardie.net/var/blog/cgit-hacking/cgit-logo.png" alt="cgit logo" style="float:right" /&gt;
&lt;p&gt;
Last week I hacked a couple new features into
&lt;a href="http://hjemli.net/git/cgit/about/"&gt;cgit&lt;/a&gt;, a web interface
for Git, since it's the one I
&lt;a href="http://ongardie.net/git/"&gt;use on ongardie.net&lt;/a&gt;. I added
&lt;code&gt;https://&lt;/code&gt; URLs for the Atom feed and also syntax highlighting when
viewing files.
&lt;/p&gt;

&lt;h2&gt;HTTPS URLs for Cgit's Atom feed&lt;/h2&gt;
&lt;p&gt;
Cgit generates Atom feeds so that you can keep track of changes from
your feed reader. Unfortunately, that requires a full URL, which it
assumed started with &lt;code&gt;http://&lt;/code&gt;. This obviously didn't work
for &lt;code&gt;https://&lt;/code&gt;-only installations.
&lt;/p&gt;
&lt;p&gt;
I modified cgit to check the &lt;code&gt;HTTPS&lt;/code&gt; CGI variable. If it's
set to &lt;code&gt;on&lt;/code&gt;, cgit now generates full URLs starting with
&lt;code&gt;https://&lt;/code&gt;. While this isn't part of the official CGI spec,
most servers will set it, including Apache and lighttpd.
&lt;/p&gt;
&lt;p&gt;
Lars Hjemli, the maintainer of cgit,
&lt;a href="http://hjemli.net/git/cgit/commit/?h=wip&amp;amp;id=086fef8a4a1a5f90eafb21fcbc4b3731d6736cb1"&gt;merged in my change&lt;/a&gt;, 
so it should be part of a future cgit release:
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
This looks good. I've merged it into my wip-branch on
&lt;a href="http://hjemli.net/git/cgit"&gt;http://hjemli.net/git/cgit&lt;/a&gt;
where I'll let it cook for a little while before merging to my master.
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Syntax Highlighting for Cgit&lt;/h2&gt;
&lt;p&gt;
Cgit is useful for browsing around a project's history, but it didn't do
syntax highlighting for source code. This made it unpleasant to use for
reading complete files (as opposed to diffs).
&lt;/p&gt;

&lt;p&gt;
I modified cgit to make use of the
&lt;a href="http://www.andre-simon.de/doku/highlight/en/highlight.html"&gt;highlight&lt;/a&gt;
program, when available, to color source code. If highlight is
unavailable or fails, cgit falls back to the old black-and-white view.
&lt;/p&gt;

&lt;p&gt;
While the patch is small and self-contained, it's specific to highlight
and just tacked on in the source code. Lars didn't take this one:
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
I like the result, but I think the implementation has to be more
generic. And I'm currently about to add support for a few plugins/hooks
to cgit which I think can be used to achieve the same result so lets see
how that works out first, ok?
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;
I'll be working with Lars on getting a cleaner solution merged into his
tree once he's added support for plugins. In the mean time, feel free to
use the code from my repository, which seems to work just fine.
&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;
Both of these features can be found on my cgit repo:
&lt;/p&gt;
&lt;ul&gt;
 &lt;li&gt;git clone http://ongardie.net/cgit.git&lt;/li&gt;
 &lt;li&gt;&lt;a href="http://ongardie.net/git/cgit/"&gt;cgit front-end&lt;/a&gt; (running
here with both of these changes)&lt;/li&gt;
&lt;/ul&gt;
See the &lt;code&gt;https&lt;/code&gt; and &lt;code&gt;highlight&lt;/code&gt; branches,
respectively. Both were branched from cgit's &lt;code&gt;master&lt;/code&gt; branch.
</description><guid isPermaLink="true">http://ongardie.net/blog/cgit-hacking/</guid><pubDate>Wed, 17 Jun 2009 18:45:00 GMT</pubDate></item><item><title>Tabs in Vim</title><link>http://ongardie.net/blog/vim-tabs/</link><description>&lt;img src="http://ongardie.net/var/blog/vim-tabs/vim-logo.png" alt="Vim logo" style="float:right" /&gt;
&lt;p&gt;
Version 7 of Vim introduced tabs to the editor, and these are a few of
my tab-related tips.
If you aren't familiar with tabs in Vim, start with the basics
on
&lt;a href="http://blog.golden-ratio.net/2008/08/19/using-tabs-in-vim/"&gt;The Golden Ratio&lt;/a&gt;
or
&lt;a href="http://www.linux.com/archive/articles/59533"&gt;Linux.com&lt;/a&gt;.
&lt;/p&gt;

&lt;h2&gt;Open Files in Tabs&lt;/h2&gt;
&lt;p&gt;
If you want to open multiple files in their own tabs in a new Vim
session, use the &lt;code&gt;-p&lt;/code&gt; flag on the command line for
&lt;code&gt;vim&lt;/code&gt; or &lt;code&gt;gvim&lt;/code&gt;. For example, to open all files
in the current directory, use the following:&lt;/p&gt;
&lt;pre&gt;
vim -p *
&lt;/pre&gt;

&lt;p style="padding-top: 10px"&gt;
When you give Vim multiple files to edit, its default behavior is to
use several buffers. If you want to use tabs as the default behavior
instead (that is, without typing the &lt;code&gt;-p&lt;/code&gt; flag every time),
set up a couple shell aliases. For bash, place these in your
&lt;code&gt;~/.bashrc&lt;/code&gt;:
&lt;/p&gt;
&lt;pre&gt;
alias vim='vim -p'
alias gvim='gvim -p'
&lt;/pre&gt;

&lt;p style="padding-top: 10px"&gt;
Also, Vim will open a maximum of 10 tabs like this by default. To
increase that limit to, for example, 50, add the following to your
&lt;code&gt;~/.vimrc&lt;/code&gt;:
&lt;/p&gt;
&lt;pre&gt;
set tabpagemax=50
&lt;/pre&gt;

&lt;h2&gt;Easier Tab Navigation&lt;/h2&gt;
&lt;p&gt;
When you have more than a few tabs open, it can become difficult to
navigate them with only the keyboard. You can use
&lt;code&gt;{count}gt&lt;/code&gt; to go to the &lt;em&gt;count&lt;/em&gt;-th tab
(starting with 1), but counting them yourself is a waste of time.
Placing the tab number on its label solves this problem.
&lt;/p&gt;
&lt;img src="http://ongardie.net/var/blog/vim-tabs/vim-tab-labels.png" alt="Vim tab labels" /&gt;
&lt;p&gt;
You can see how I set a custom tab label in
&lt;a href="http://ongardie.net/git/vim/commit/?id=ae39cc8678860376a07cd3e797f78135cb134fa3"&gt;this&lt;/a&gt;
commit to my Vim configuration repository.
The blog post on
&lt;a href="http://blog.golden-ratio.net/2008/08/19/using-tabs-in-vim/"&gt;The Golden Ratio&lt;/a&gt;
has another custom tab label you could check out.
&lt;/p&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/vim-tabs/</guid><pubDate>Fri, 29 May 2009 06:51:00 GMT</pubDate></item><item><title>Overlooked Python Built-Ins</title><link>http://ongardie.net/blog/python-builtins/</link><description>&lt;img src="http://ongardie.net/var/blog/python-builtins/python-logo.png" alt="Python logo" style="float:right" /&gt;
&lt;p&gt;
So, I just realized that I re-implemented two built-in Python
functions on a small project I'm working on for
&lt;a href="http://www.etszone.com"&gt;ETSZONE&lt;/a&gt;.
I just didn't know that these existed, so I'm writing about them here
in case you've overlooked them too.
&lt;/p&gt;

&lt;h2&gt;&lt;a href="http://docs.python.org/library/functions.html#sorted"&gt;sorted&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
This is useful if you want to sort a copy of a list. Use
&lt;code&gt;sorted()&lt;/code&gt; instead of copying the list and then using
&lt;code&gt;list.sort()&lt;/code&gt;.
&lt;/p&gt;
&lt;p&gt;
This was my re-implementation (and I think I still like its name
better):
&lt;/p&gt;
&lt;pre&gt;
def sort(seq, **args):
    x = list(seq)
    x.sort(**args)
    return x
&lt;/pre&gt;
&lt;p&gt;
The &lt;code&gt;sorted&lt;/code&gt; function has been available since Python v2.4.
&lt;/p&gt;

&lt;h2&gt;&lt;a href="http://docs.python.org/library/functions.html#enumerate"&gt;enumerate&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
This is useful when you want a foreach loop, but you also need a loop
counter around. Use &lt;code&gt;enumerate()&lt;/code&gt; instead of keeping a
counter elsewhere.
&lt;/p&gt;
&lt;p&gt;
For example, I was writing out a spreadsheet with
&lt;a href="http://ooolib.sourceforge.net/"&gt;ooolib-python&lt;/a&gt;.
For each spreadsheet cell to write, I had to specify row and column
indexes. I could write more natural loops with &lt;code&gt;enumerate&lt;/code&gt;,
while still having a counter to use as a row or column index.
&lt;/p&gt;
&lt;p&gt;
This was my re-implementation (and its name would have never caught
on):
&lt;/p&gt;
&lt;pre&gt;
def indexiter(iterable):
    return zip(range(len(iterable)), iterable)
&lt;/pre&gt;
&lt;p&gt;
The &lt;code&gt;enumerate&lt;/code&gt; function has been available since Python v2.3.
Read about the optional &lt;code&gt;start&lt;/code&gt; parameter in the
&lt;a href="http://docs.python.org/library/functions.html#enumerate"&gt;docs&lt;/a&gt;
- it looks useful, but it's new in Python 2.6.
&lt;/p&gt;

&lt;hr /&gt;
This shows that it's a good idea to occasionally browse back through
the very basic support a language gives you, since you might just find
a couple useful tools in there that you had overlooked. If you're into
Python, start
&lt;a href="http://docs.python.org/library/functions.html"&gt;here&lt;/a&gt;.
</description><guid isPermaLink="true">http://ongardie.net/blog/python-builtins/</guid><pubDate>Sat, 23 May 2009 06:52:00 GMT</pubDate></item><item><title>Stack Overflow DevDays Registration</title><link>http://ongardie.net/blog/stack-devday-reg/</link><description>
&lt;p&gt;
&lt;img src="http://ongardie.net/var/blog/stack-devday-reg/stackoverflow.png" alt="Stack Overflow logo" /&gt;
&lt;/p&gt;

&lt;p&gt;
I just read about Stack Overflow DevDays on &lt;a href="http://www.joelonsoftware.com"&gt;Joel on Software&lt;/a&gt;
(&lt;a href="http://www.joelonsoftware.com/items/2009/05/12.html"&gt;post&lt;/a&gt;):
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
It's going to be in October, in five separate cities. In each city, we're
planning a one-day event.
&lt;/p&gt;

&lt;p&gt;
We decided to cram as many diverse topics as possible into a single day
event. Like a tasting menu at a great restaurant, we'll line up six great
speakers in each city.
&lt;/p&gt;

&lt;p&gt;
This is not going to be just a Java conference or a .NET conference or a
Ruby conference. This will be completely ecumenical. We'll have somebody to
introduce Microsoft's new web framework, ASP.NET MVC, but we'll also get
someone to talk about writing code for Google's new mobile operating
system, Android. And in each city, we'll find one local computer science
professor or graduate student to tell us about something new and
interesting in academia.
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
I picked up one of the $10 student tickets for San Francisco.
Now, I'm not a big &lt;a href="http://stackoverflow.com/"&gt;Stack Overflow&lt;/a&gt;
user, but, at that price, I had to go for it. I'm especially hoping to hear
more about the first 4 topics listed:
Android, Objective C and iPhone development, Google App Engine, and Python.
&lt;/p&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/stack-devday-reg/</guid><pubDate>Wed, 13 May 2009 04:17:00 GMT</pubDate></item><item><title>Extract Unique Lines From a File</title><link>http://ongardie.net/blog/sort-uniq/</link><description>&lt;p&gt;
If you want to get rid of duplicate lines from a file or pipe, use
&lt;/p&gt;
&lt;pre&gt;sort -u&lt;/pre&gt; or &lt;pre&gt;sort | uniq&lt;/pre&gt;

&lt;br /&gt;

&lt;p&gt;
For example, maybe you're searching for another front-end to &lt;code&gt;libpurple&lt;/code&gt;,
the library underneath &lt;a href="http://www.pidgin.im/"&gt;pidgin&lt;/a&gt;.
You try to use &lt;code&gt;apt-cache rdepends&lt;/code&gt;
but find the output is cluttered with duplicate entries
(&lt;a href="http://bugs.debian.org/335925"&gt;bug #335925&lt;/a&gt;).
&lt;/p&gt;

&lt;pre&gt;
$ apt-cache rdepends libpurple0 | tail -n +3 | sort
  finch
  finch
  libpurple-bin
  libpurple-bin
  libpurple-dev
  libpurple-dev
  msn-pecan
  pidgin
  pidgin
  pidgin-dbg
  pidgin-dbg
  pidgin-facebookchat
  pidgin-librvp
  pidgin-mpris
  pidgin-nateon
  pidgin-plugin-pack
  pidgin-privacy-please
  pidgin-privacy-please
  pidgin-sipe
  telepathy-haze
  telepathy-haze
&lt;/pre&gt;
&lt;p&gt;
Note that I've trimmed off the header (with &lt;code&gt;tail&lt;/code&gt;)
and sorted the list (with &lt;code&gt;sort&lt;/code&gt;) here to make this more obvious.
&lt;/p&gt;

&lt;p&gt;
Using the above tip to see only unique lines, you can easily work around this bug:
&lt;/p&gt;
&lt;pre&gt;
$ apt-cache rdepends libpurple0 | tail -n +3 | sort -u
  finch
  libpurple-bin
  libpurple-dev
  msn-pecan
  pidgin
  pidgin-dbg
  pidgin-facebookchat
  pidgin-librvp
  pidgin-mpris
  pidgin-nateon
  pidgin-plugin-pack
  pidgin-privacy-please
  pidgin-sipe
  telepathy-haze
&lt;/pre&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/sort-uniq/</guid><pubDate>Fri, 08 May 2009 06:52:00 GMT</pubDate></item><item><title>Off-Brand Q-tips</title><link>http://ongardie.net/blog/q-tips/</link><description>&lt;p&gt;To start off this blog, I'm writing about things you stick in your ear. I suspect I'll end up writing about techier subjects soon enough. Nevertheless, it's probably worthwhile to &lt;em&gt;attempt&lt;/em&gt; to set a precedent of, at least occasionally, writing about something low-tech.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Q-tips, or rather &lt;em&gt;cotton swabs&lt;/em&gt;, always warn you not to insert them into your ear canal. After all, they officially have a &lt;a href="http://www.qtips.com/variety.php"&gt;variety of legitimate uses&lt;/a&gt;. Let's face it though: they were &lt;a href="http://home.nycap.rr.com/useless/q-tips/"&gt;created for ear cleaning&lt;/a&gt;, so they work rather well for that.&lt;/p&gt;

&lt;div class="center"&gt;&lt;img src="http://ongardie.net/var/blog/q-tips/ear_warning.jpg" alt="Warning on Q-tips package" /&gt;&lt;/div&gt;

&lt;p&gt;Well, cotton swabs aren't something you need to buy very often. You have to run out of them to realize just how nice they are. My roommate Matt and I ran out of cotton swabs on Monday a couple weeks ago. So, of course, that Wednesday I had a doctor's appointment. The ear thermometer must have had a fun time in there...&lt;/p&gt;

&lt;p&gt;Anyway, I was still pretty thankful we ran out. We had the off-brand, wannabe Q-tips before. The ones with a tiny amount of cotton on each end. The ones that will not give until they entirely bend in the center. I've grown to hate the off-brands with a passion, and yet seem to keep encountering them.&lt;/p&gt;

&lt;img  style="float:right" src="http://ongardie.net/var/blog/q-tips/price_per_unit.jpg" alt="Per unit price of off-brand cotton swabs" /&gt;

&lt;p&gt;It's marketing. The real Q-tips are more expensive at the store. The off-brands cost a couple bucks less, and you &lt;em&gt;get more&lt;/em&gt; - the price per unit of the off-brands can't be beat. The problem is, you don't want more. You &lt;em&gt;really&lt;/em&gt; don't want more of them. You'll go home with your 300-pack of $1.99 cotton swabs, try to clean your ear with one, and get just a little pissed off at how ineffective it is. The next day after your shower, you'll again be a little pissed off. Even if you share your cotton swabs with someone else, you're still going to be a little pissed off, every single day, for about the next 5 months. Is that really worth saving a couple bucks?&lt;/p&gt;
</description><guid isPermaLink="true">http://ongardie.net/blog/q-tips/</guid><pubDate>Sat, 29 Dec 2007 07:50:00 GMT</pubDate></item></channel></rss>