<?xml version="1.0" encoding="utf-8"?>
<!-- If you are running a bot please visit this policy page outlining rules you must respect. http://www.livejournal.com/bots/ -->
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:lj="http://www.livejournal.com">
  <id>urn:lj:livejournal.com:atom1:pinterface</id>
  <title>The Opinions Expressed Herein are My Own</title>
  <subtitle>and any facts backing them are purely coincidental</subtitle>
  <author>
    <name>pixel</name>
  </author>
  <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/"/>
  <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom"/>
  <updated>2013-05-11T04:03:48Z</updated>
  <lj:journal userid="850656" username="pinterface" type="personal"/>
  <link rel="service.feed" type="application/x.atom+xml" href="http://pinterface.livejournal.com/data/atom" title="The Opinions Expressed Herein are My Own"/>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:44829</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/44829.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=44829"/>
    <title>Upgrading the Linux Kernel when Using a USB Boot Disk</title>
    <published>2013-05-11T04:03:48Z</published>
    <updated>2013-05-11T04:03:48Z</updated>
    <category term="infrequent processes"/>
    <category term="work"/>
    <category term="linux"/>
    <content type="html">&lt;p&gt;In order to protect any sensitive data on my work laptop, I use full-drive encryption.  To aid recovery in case of theft, it normally boots to a honeypot installation of Windows with Prey installed.  To boot into Linux, one must use a USB boot disk&lt;a href="#kernel-update-usb-disk-footnote-1" rel="nofollow"&gt;[1]&lt;/a&gt; which contains the contents of /boot.&lt;/p&gt;

&lt;p&gt;Once in a while, it is necessary to upgrade the kernel.  I don't do this very often, so it seems like the sort of process which should be documented.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Mount /boot read-write: &lt;code&gt;`mount -o rw /boot`&lt;/code&gt;&lt;br&gt;
I generally have /boot mounted read-only, in part because I don't usually
have the thumbdrive plugged in (I don't boot very often, after all), and
to ensure I don't accidentally make changes to it without being prepared
to undergo this full process.&lt;/li&gt;
&lt;li&gt;Install kernel updates: &lt;code&gt;`sudo aptitude full-upgrade`&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Reboot.  Pray it works.&lt;/li&gt;
&lt;li&gt;Insert backup boot disk.  (Just in case the thumbdrive on my keychain goes bad or gets lost.)&lt;/li&gt;
&lt;li&gt;Copy files from the updated boot disk to the backup: &lt;code&gt;`rsync -av /boot /media/usb2`&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Remove the original boot disk.  This will help prevent unfortunate mistakes.&lt;/li&gt;
&lt;li&gt;Alter grub.cfg of backup boot disk to refer to the proper UUID:
&lt;code&gt;`sudo sed -i s/$UUID_OF_BOOT/$UUID_OF_BACKUP/ grub/grub.cfg`&lt;/code&gt;&lt;br&gt;
&lt;code&gt;`blkid`&lt;/code&gt; comes in handy for finding the relevant UUIDs.&lt;/li&gt;
&lt;li&gt;Reboot.  Pray it works.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Assuming both boot disks successfully boot the machine with the updated kernel, congratulations!  You have successfully updated the kernel!&lt;/p&gt;

&lt;p&gt;&lt;a name="kernel-update-usb-disk-footnote-1"&gt;&lt;/a&gt;[1] It's not quite as much a waste of a thumbdrive as you might think.  The sticks have a FAT partition of ~90% or so of the advertised capacity, so they can still be used to transfer files between computers or for data storage.&lt;/p&gt;

&lt;p&gt;New year, new job, &lt;a href="http://pinterface.dreamwidth.org/" rel="nofollow"&gt;new blog&lt;/a&gt;.  I'd 301 redirect you if I could, but since I can't you'll have to click through to &lt;a href="http://pinterface.dreamwidth.org/1276.html#comments" rel="nofollow"&gt;read &lt;img src="http://www.dreamwidth.org/tools/commentcount?user=pinterface&amp;amp;ditemid=1276" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;" /&gt; comments&lt;/a&gt; or &lt;a href="http://pinterface.dreamwidth.org/1276.html?mode=reply" rel="nofollow"&gt;leave your own&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:44665</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/44665.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=44665"/>
    <title>A Public Service Announcement About rm and tildes</title>
    <published>2013-04-22T04:09:30Z</published>
    <updated>2013-04-22T04:09:30Z</updated>
    <category term="oops"/>
    <category term="linux"/>
    <category term="public service announcement"/>
    <category term="backups"/>
    <category term="rm"/>
    <category term="emacs"/>
    <content type="html">&lt;p&gt;If you happen to be lax in upgrading software, you might have an older version of magit where if M-x magit-status is allowed to initialize a git repository where none was before, it has a tendency to create said repository in the directory '$HOME/repo/~/repo'[1].&lt;/p&gt;

&lt;p&gt;If this happens, and one wishes to remove that annoying and non-useful '~' directory, do not, I repeat, do not run the command:&lt;/p&gt;
&lt;blockquote&gt;rm -r ~&lt;/blockquote&gt;

&lt;p&gt;That is bad.  Remember shell expansion!  You need to quote the tilde:&lt;/p&gt;
&lt;blockquote&gt;rm -r '~'&lt;/blockquote&gt;

&lt;p&gt;But also note that even the latter should not be done within eshell, as it seems to be intent on expanding the tilde anyway.  Use a real shell.&lt;/p&gt;

&lt;p&gt;Also, &lt;em&gt;always&lt;/em&gt; do &lt;tt&gt;`ls $dir`&lt;/tt&gt; before you do &lt;tt&gt;`rm $dir`&lt;/tt&gt;, just to double-check what you're deleting.  Even if you're sure, check anyway.&lt;/p&gt;

&lt;p&gt;Because otherwise, you might accidentally delete your home directory.&lt;/p&gt;

&lt;p style="margin-top: 4em;"&gt;On the bright side, I can now confirm my backups work.&lt;/p&gt;

&lt;p&gt;[1] see &lt;a href="https://github.com/magit/magit/issues/383" rel="nofollow"&gt;bug 383&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;New year, new job, &lt;a href="http://pinterface.dreamwidth.org/" rel="nofollow"&gt;new blog&lt;/a&gt;.  I'd 301 redirect you if I could, but since I can't you'll have to click through to &lt;a href="http://pinterface.dreamwidth.org/783.html#comments" rel="nofollow"&gt;read &lt;img src="http://www.dreamwidth.org/tools/commentcount?user=pinterface&amp;amp;ditemid=783" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;" /&gt; comments&lt;/a&gt; or &lt;a href="http://pinterface.dreamwidth.org/783.html?mode=reply" rel="nofollow"&gt;leave your own&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:44431</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/44431.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=44431"/>
    <title>Live from the DMV!  (This Program was Recorded Earlier)</title>
    <published>2013-01-26T20:32:15Z</published>
    <updated>2013-01-26T20:32:15Z</updated>
    <category term="privacy"/>
    <category term="dmv"/>
    <category term="real life"/>
    <content type="html">&lt;p&gt;I recently renewed my driver's license.  There were a few changes from the last time I did it, and they aren't really for the better.&lt;/p&gt;

&lt;p&gt;First, they now require removal of glasses, hats, and human expression from your picture, to aid the facial recognition software used.  While I offered a mild objection to removing my glasses and having a blank expression, it regrettably did not occur to me to state my objection to the usage of facial recognition software at all until after I was done.&lt;/p&gt;

&lt;p&gt;Wish I had, though.  For several reason: first, because I &lt;em&gt;do&lt;/em&gt; object to the government using facial recognition software on my pictures, or really storing any biometric data on me at all; and second because I want to know if there's a process to handle such objections.  Obviously the DMV is not the place to effect change, but knowing if there are procedures in place for objections would at least give me a place to start.&lt;/p&gt;

&lt;p&gt;Well, I had always planned on moving out of state eventually, anyway.  I guess I'll add "DMV uses facial recognition software" to the list of reasons to leave, and the list of things to check for any place I might otherwise be inclined to move to.&lt;/p&gt;

&lt;p&gt;Second, they no longer provide your actual license.  Instead, they provide a temporary paper license and mail the real one.  So now, instead of potentially being lifted by someone showing their face who would have to look similar enough to fool the person giving it to you, your license can be lifted anonymously by someone within the postal system, or anyone with access to your mailbox.  This is apparently so they can take time to more carefully verify your identity to prevent identity theft, so the fact it makes licenses easier to steal is hilarious.&lt;/p&gt;

&lt;p&gt;Third, unless you specifically object, signing up for a license now automatically enrolls you into the selective service database if you're eligible.  While I object to the very existence of that database, auto-enrollment makes vastly more sense than the manual enrollment that was supposedly mandated when I was within the eligible age range.&lt;/p&gt;

&lt;p&gt;It gets harder and harder to keep a low data profile.  Le sigh.&lt;/p&gt;

&lt;p&gt;New year, new job, &lt;a href="http://pinterface.dreamwidth.org/" rel="nofollow"&gt;new blog&lt;/a&gt;.  I'd 301 redirect you if I could, but since I can't you'll have to click through to &lt;a href="http://pinterface.dreamwidth.org/732.html#comments" rel="nofollow"&gt;read &lt;img src="http://www.dreamwidth.org/tools/commentcount?user=pinterface&amp;amp;ditemid=732" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;" /&gt; comments&lt;/a&gt; or &lt;a href="http://pinterface.dreamwidth.org/732.html?mode=reply" rel="nofollow"&gt;leave your own&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:44197</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/44197.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=44197"/>
    <title>Getting a Job, a Retrospective</title>
    <published>2013-01-13T01:37:40Z</published>
    <updated>2013-01-13T01:37:40Z</updated>
    <category term="work"/>
    <category term="lessons learned"/>
    <category term="personal growth"/>
    <content type="html">&lt;p&gt;Being largely burnt out on the &lt;a href="http://getbalm.com/" rel="nofollow"&gt;skin cream&lt;/a&gt; business, I decided near the beginning of 2012 it was time for a change of pace and decided to look for a job.&lt;/p&gt;

&lt;p&gt;Step one: &lt;a href="http://cialug.org/" rel="nofollow"&gt;Leave&lt;/a&gt; &lt;a href="http://pyowa.org/" rel="nofollow"&gt;the&lt;/a&gt; house.  Achievement unlocked!&lt;/p&gt;

&lt;p&gt;What I heard from people in these groups, and from various places on the Internet, is that now is a great time to be a programmer.  Jobs are easy to come by, they said!  The pay is great, they said!&lt;/p&gt;

&lt;p&gt;As it turns out, there are a few things that make it somewhat more difficult for me to find work: first, is location.  This town, which I would love to leave but not quite yet, thanks to the banks and insurance industry which dominate it, is a Java and .NET shop through and through, and they demand experience in those languages.  Also, banks and insurance companies are very stodgy, and maintain a considerably stricter dress code than I can bring myself to adhere to.  So for multiple reasons, this town's two primary industries are almost entirely out.&lt;/p&gt;

&lt;p&gt;So I'm largely left looking at the PHP, Python, and Ruby shops.  PHP because however much I hate it I have experience in it, and Python and Ruby because places which use Python and Ruby are enlightened enough to realize programmers can learn new programming languages.  That's a relatively small number of places in this town, but at least it's non-zero.&lt;/p&gt;

&lt;p&gt;Attending meetings is fun, but I'm terrible at networking (it requires talking, which I am wont not to do), so wasn't particularly helpful in terms of finding work.  But a &lt;a href="http://www.starmind.org/2012/04/07/so-you-want-a-new-job-adapted-from-a-presentation/" rel="nofollow"&gt;conveniently-time presentation&lt;/a&gt; by one of the CIALUG members on how he got a $20k/year pay hike with his new job proved interesting.&lt;/p&gt;

&lt;p&gt;First was the suggestion that, contrary to the opining on Hacker News, recruiters were not all terrible people, and a recommendation of the people at &lt;a href="http://www.thepalmergroup.com/" rel="nofollow"&gt;Palmer Group&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First sign of trouble: their baraccuda was doing deep packet inspection and rejected my e-mails on the basis of my home IP not being authorized to act as an SMTP server—that it isn't being used as one is, apparently, entirely irrelevant.  Had to craft a special rule to remove the Received: header before I could relay mail to them.  (Alas, postmaster@ was completely non-responsive.)&lt;/p&gt;

&lt;p&gt;Once I got through, my initial contact was quite nice.  Then I got handed off to a fellow who clearly was not interested.  But, with some encouraging from my initial contact, I met with him anyway and ... it did not go well.  We parted ways mutually unimpressed, and I never heard from him again.&lt;/p&gt;

&lt;p&gt;So much for &lt;em&gt;that&lt;/em&gt; recruiting agency.&lt;/p&gt;

&lt;p&gt;Second was the presenter's resume (alas, I cannot now find it), which I thought was pretty cool and modeled mine after.  Which is a pretty high compliment, actually: I've looked at resume examples online, and they all result in pretty much the same reaction: "This is boring and stupid.  Why the hell would anyone read this?".  That abundance of awful resumes kept me from even trying to make my own for years, and it wasn't until I saw the presenter's that I realized they could be not-terrible.&lt;/p&gt;

&lt;p&gt;Unfortunately for my desire for privacy, my resume isn't terribly impressive if restricted solely to work-related items, so I had to pad it out with a little open-source work.  I'd have vastly prefered to keep those lives separate (hence my not linking to a copy of my resume, though I've actually mentioned most of the things on it here), but felt I needed the extra oomph.  I expect my resume post-new-job to better hold up without violating that separation.&lt;/p&gt;

&lt;p&gt;There's not a lot of privacy in job hunting, actually.  People want things like your name.  Dice has the audacity to require a phone number and street address.  I'm an introverted nerd: I don't take phone calls, and I sure as heck don't want &lt;em&gt;mail&lt;/em&gt;.  Fortunately, "000-000-0000" and "Undisclosed" are considered valid inputs for those fields.&lt;/p&gt;

&lt;p&gt;Anyway, privacy issues aside, and resume in hand, I start looking for work.  So I peruse Craiglist want ads, and post my resume on Dice (the trick, of course, is that unlike &lt;a href="http://pinterface.livejournal.com/33362.html" rel="nofollow"&gt;last time&lt;/a&gt;, I'd actually like to end up with a job), and browse job sites.&lt;/p&gt;

&lt;p&gt;Great googly moogly are help wanted ads ever awful!  I can't even read more than a few a week, they're just so terrible.  They either leave me wondering what the job even &lt;em&gt;is&lt;/em&gt;, or they leave me wondering why anybody would &lt;em&gt;want&lt;/em&gt; it.&lt;/p&gt;

&lt;p&gt;So I send my resume out to a few places.  Nobody bites.  One actually sent me a "hey, thanks for sending us your resume", but otherwise I get nothing.  I periodically adjust my info on Dice, and see from my server logs that some of the links I helpfully included in my resume are being clicked on.&lt;/p&gt;

&lt;p&gt;Dice nets me two contacts at this point.  A recruiter and an interview request.&lt;/p&gt;

&lt;p&gt;The company requesting an interview doesn't sound all that interesting—just basic PHP site development—but I figure I could use the practice and go.  And I was right about needing the practice, because I bombed the interview, &lt;em&gt;hard&lt;/em&gt;.  Couldn't even accurately define &lt;a href="http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller" rel="nofollow"&gt;MVC&lt;/a&gt;.  Naturally, they passed.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://executiveresources.com/" rel="nofollow"&gt;The recruiter&lt;/a&gt; was a nice lady who tried to get me a job at &lt;a href="https://www.webfilings.com/" rel="nofollow"&gt;WebFilings&lt;/a&gt; as a "Scrum Master", whatever that is.  I wasn't terribly thrilled about the commute, but she made a convincing argument for giving them a try.  But, after a month or two of her contacts being out of the office, they eventually decided to fill the position from within.&lt;/p&gt;

&lt;p&gt;Visibility supposedly helps, so I gave &lt;a href="http://pinterface.livejournal.com/tag/talks,python" rel="nofollow"&gt;my presentation at Pyowa&lt;/a&gt;.  That netted me an interview—and their head guy from Chicago seemed to really like me—, but for whatever reason, they too passed.  Which made me sad, because I really liked them and would likely have accepted in spite of the non-stellar pay because the work that was 3-6 months out (converting their monolithic architecture to a service-oriented one) sounded &lt;em&gt;really fun&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Somewhere in here I also send my resume to &lt;a href="http://www.businessolver.com/" rel="nofollow"&gt;a company&lt;/a&gt; which hosted one of the CIALUG meetings, because they said they were looking for people.  They do a little googling, end up on my father's personal site, and peruse the pictures page, presumably trying to remember who I was (I'm not recognizably there, but they don't know that) and possibly confusing me for my dad.  I get a polite brush-off.&lt;/p&gt;

&lt;p&gt;Monster is mentioned at a Pyowa meeting.  I sign up and post my resume.  And, while it results in vastly more contacts than Dice, they're all offers to become an insurance salesman.  And they have unsubscribe links, which should give you and idea of how personal they are.&lt;/p&gt;

&lt;p&gt;Suddenly, &lt;a href="http://www.aureusgroup.com/" rel="nofollow"&gt;another recruiter&lt;/a&gt; contacts me through Dice.  She loves my resume, then proceeds to ask questions which can largely be answered by reading it or my profile.  I grate my teeth and point this out as politely as I can while I answer the questions.  During the phone conversation, "How much do you make now?" "I'd rather not say." "Well I understand and maybe you'll tell me later."  (paraphrased), which I think is a little odd (the only thing about money anybody else has asked is how much I'd like to &lt;em&gt;get&lt;/em&gt;) but don't worry too much about.  I get asked to fill out a form online to get into their system.  This makes me not happy, but people aren't exactly beating down my door with money, so I go for it.  And their form wants information I can't give it (What month did I start?  It was &lt;em&gt;nine years ago&lt;/em&gt;, I don't remember!), and information I won't give it (current pay).  Not to be deterred, I e-mail the recruiter asking for suggestions.  That went something like this:&lt;/p&gt;

&lt;dl&gt;
&lt;dt&gt;Recruiter&lt;/dt&gt;&lt;dd&gt;"You should tell us your current salary."&lt;/dd&gt;
&lt;dt&gt;Me&lt;/dt&gt;&lt;dd&gt;"No.  Stop asking or we're done here."&lt;/dd&gt;
&lt;dt&gt;Recruiter&lt;/dt&gt;&lt;dd&gt;"Okay, bye."&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;The exchange was somewhat more politely verbose, of course, but that's the gist of it.&lt;/p&gt;

&lt;p&gt;And then I pretty much forgot about Dice until I get an interview request from &lt;a href="https://www.bettrlife.com/" rel="nofollow"&gt;a little startup&lt;/a&gt; which enticed me with things like private offices and no dress code.  So I do the interview, and I have no idea how to judge it.  No real technical questions, no coding on the whiteboard, just "tell me about yourself / your work" (after a long pause: "I don't normally talk about myself, help me out here and ask me some questions!"), and chumming with a few of the existing coders (during which I did &lt;em&gt;very little&lt;/em&gt; of the talking).&lt;/p&gt;

&lt;p&gt;But they made an offer, and it wasn't half bad in terms of pay, either.  They agreed to a significant narrowing of the scope of their non-compete—which was originally so vague you could construe it as prohibiting clipping coupons from the newspaper—, and I accepted.&lt;/p&gt;

&lt;p&gt;So new job for Pixie!  It's not perfect—the commute is longer than I'd like (about 20 minutes), the company-provided computers are &lt;em&gt;laptops&lt;/em&gt; of all things, and they use Google apps&lt;sup&gt;&lt;a href="#google-apps-sucks" rel="nofollow"&gt;1&lt;/a&gt;&lt;/sup&gt;—, but it should be interesting.&lt;/p&gt;

&lt;p&gt;Here's some things I learned during this experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recruiters "love my resume", but if I could just go ahead and make it completely boring that'd be great.&lt;/li&gt;
&lt;li&gt;You can e-mail a link to your resume, using the e-mail as a cover letter.  Links to resumes do, in fact, get clicked.  (Handy for tracking!)&lt;/li&gt;
&lt;li&gt;Links &lt;em&gt;on resumes&lt;/em&gt; also get clicked.  (Also handy for tracking.)&lt;/li&gt;
&lt;li&gt;Visibility is a really good way to get companies interested.  It's also the most work.&lt;/li&gt;
&lt;li&gt;Monster may get you more contacts faster, but Dice will actually get &lt;em&gt;relevant&lt;/em&gt; contacts.&lt;/li&gt;
&lt;li&gt;Like dating, you get much better response rates from those who come to you.&lt;/li&gt;
&lt;li&gt;Wearing a t-shirt and shorts to an interview will not prevent you from getting an offer.&lt;/li&gt;
&lt;li&gt;Every interviewer will bring up Lisp if it's on the resume.&lt;/li&gt;
&lt;li&gt;Questions about the technology stack and development process tend to elicit a response of "that's a good question".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And now, some months after accepting a position and working for a while (this entry was in my drafts folder so long I forgot about it!), I can add a few things to the list:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Somewhere along the line, my Dice-tagged e-mail address was acquired by spammers.  Ugh.&lt;/li&gt;
&lt;li&gt;While I was worried having coworkers would reveal I'm a terrible programmer, turns out I'm not half-bad.  (Assuming my measurements are correct, my net effect on our primary repository has been roughly -74,000 lines, in spite of numerous feature expansions and improvements.)&lt;/li&gt;
&lt;li&gt;Working on a laptop isn't so bad.  My only real complaint is that they cheaped out on the screen, so it's got even fewer pixels than the already-pathetic "full HD" so many laptops tout as if it were decent.&lt;/li&gt;
&lt;li&gt;Working 40-50 hours a week kills nearly all of my free time.  I have yet to figure out how other people manage full-time work plus side projects.&lt;/li&gt;
&lt;li&gt;Having an office is awesome.  How anybody gets work done without the ability to make quiet something which was noisy is beyond me.&lt;/li&gt;
&lt;li&gt;I really like the new job.  Yay!&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;sup&gt;&lt;a name="google-apps-sucks"&gt;1&lt;/a&gt;&lt;/sup&gt; Good T.B.Lee, people use this crap?  None of it works with JavaScript disabled, and with JavaScript enabled it brings my computer to a griding halt.  And then some of it &lt;em&gt;still&lt;/em&gt; doesn't even work (go go Groups infinite redirect!).  Fortunately, I've managed to almost entirely avoid it.&lt;/p&gt;

&lt;p&gt;New year, new job, &lt;a href="http://pinterface.dreamwidth.org/" rel="nofollow"&gt;new blog&lt;/a&gt;.  I'd 301 redirect you if I could, but since I can't you'll have to click through to &lt;a href="http://pinterface.dreamwidth.org/338.html#comments" rel="nofollow"&gt;read the &lt;img src="http://www.dreamwidth.org/tools/commentcount?user=pinterface&amp;amp;ditemid=338" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;" /&gt; comments&lt;/a&gt; or &lt;a href="http://pinterface.dreamwidth.org/338.html?mode=reply" rel="nofollow"&gt;leave your own&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:43860</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/43860.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=43860"/>
    <title>The Reunion</title>
    <published>2012-09-04T03:59:04Z</published>
    <updated>2012-09-04T03:59:04Z</updated>
    <category term="personal"/>
    <content type="html">&lt;p&gt;I wouldn't have expected it ten years ago, but I've found myself curious
lately&lt;sup&gt;&lt;a name="fnr1-how-i-found-out" href="#fn1-how-i-found-out" rel="nofollow"&gt;1&lt;/a&gt;&lt;/sup&gt; where my high school peers ended up and if I was the biggest loser among the
class&lt;sup&gt;&lt;a name="fnr2-award-for-most-pathetic" href="#fn2-award-for-most-pathetic" rel="nofollow"&gt;2&lt;/a&gt;&lt;/sup&gt;, so I made one of my rare trips outside the house to attend the
ten-year high school reunion.&lt;/p&gt;

&lt;p&gt;Regrettably, my camera is currently in Chicago undergoing repairs, so I was
unable to document the event with pictures.  From what I saw of picture-taking,
there likely won't be many pictures for posterity.  That's unfortunate, but we
can at least document the event in words, so here goes:&lt;/p&gt;

&lt;p&gt;Men of the 2002 graduating class, we have gotten fat!  Some of the women have
too, of course, but not nearly in the staggering proportions of us men: by rough
estimates, I would say 90% of us men have grown in girth, to maybe 50% of the
women.&lt;/p&gt;

&lt;p&gt;Well, at least we're well-fed.&lt;/p&gt;

&lt;p&gt;Facial hair is surprisingly popular for the men.  I was additionally surprised
at how many people remarked on my beard; apparently people do not recall that I
was much too lazy to shave in high school and generally had a beard back then as
well.&lt;/p&gt;

&lt;p&gt;I was quite pleased to see many of the women wearing comfortable shoes, rather
than high-heels.  Still, there was no shortage of women wearing shoes which
essentially forced them to spend the evening on their tippy-toes.  8+-inch heels
are crazy, ladies!&lt;/p&gt;

&lt;p&gt;I felt about as short as I did in high school, though a number of people I
remember being taller than I was are now much closer to eye level.  Either I've
gotten taller, or some of you have gotten shorter.&lt;/p&gt;

&lt;p&gt;Facebook is not only the most popular method of keeping in touch, as far as I
can tell it's the &lt;em&gt;only&lt;/em&gt; method.  There was not one "Hey, what's your e-mail?",
not one "Hey, what's your phone number?", not one "Hey, what's your blog?", not
even an "Are you on Google Plus?"&amp;mdash;just "Are you on Facebook?".&lt;/p&gt;

&lt;p&gt;No.  No I am not.&lt;/p&gt;

&lt;p style="width: 15em; float: right; margin-left: 2em; margin-top: 0;" title="This is a joke, kids."&gt;
A special note to their husbands: You bastards!  You decimated the reunion
hookup market!&lt;/p&gt;

&lt;p&gt;Much to my surprise, a number of the ladies who were in my social circle are
married and have kids now.  Bucking both the trends of highly intelligent women
waiting until mid-thirties to have children &lt;em&gt;and&lt;/em&gt; of women failing to lose the
baby fat, because they are lookin' fiiiiiiine.  &lt;i&gt;*ahem*&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;More people than I expected are still in town.  I thought I was the only one!
You'd think this town would be small enough I'd have run in to one of them at
some point, but apparently not.  (Though that may also be explained by my
disinclination to leave the house.)&lt;/p&gt;

&lt;p&gt;Many people are still in the midwest, even if not in Iowa.  Omaha, Kansas City,
South Dakota, and Chicago were all represented.&lt;/p&gt;

&lt;p&gt;IT was well-represented as a professional group, though there's undoubtedly some
bias towards it given my high-school peers.  Lawyers were also quite
well-represented.&lt;/p&gt;

&lt;p&gt;Nobody advertised what they were paid, myself included, so I do not know how we
all rank in terms of wealth, but I think I can safely surmise that those of us
who showed up are doing okay.  Not spectacular, but well enough.&lt;/p&gt;

&lt;p&gt;On a more personal level (and boy I really hope I'm getting the names right,
because I'm trying dagnabbit):&lt;/p&gt;

&lt;p&gt;Amy A. said hi to me!  Okay, that sounds a little weird when I say it like that,
but we never hung out back then, and I &lt;em&gt;may&lt;/em&gt; have had a crush on her at one
point.  She's a sexy lawyer now, which would have been nice to know a few weeks
ago when negotiating the non-compete for my new job, but is nonetheless
something to keep in mind for the future.&lt;/p&gt;

&lt;p&gt;Chris K. still tells the best stories, which will serve him well in the criminal
justice system.&lt;/p&gt;

&lt;p&gt;Tori L. is a teacher now, and mad props to her for it.  As someone who sometimes
thinks about trying his hand at teaching, but knows he'd be terrible, I've got a
lot of respect for those who can actually do it.&lt;/p&gt;

&lt;p&gt;Congrats to Josh C. on surviving so many years of retail.  You're a better man
than me, my friend.  Also congrats on getting out of it! &lt;tt&gt;:)&lt;/tt&gt;&lt;/p&gt;

&lt;p&gt;Sri, me and Laura both miss you and hope you're doing well.&lt;/p&gt;

&lt;p&gt;A big congratulations to Lauren H. for sobering up during the past ten years.
That kind of successful life change is truly inspirational.&lt;/p&gt;

&lt;p&gt;Andrew W., whom I did not get a chance to talk to, was looking quite dapper.
Way to show up the rest of us men and get more handsome, rather than more
rotund, Andrew!&lt;/p&gt;

&lt;p&gt;A big &lt;del&gt;Ha ha, suckers!&lt;/del&gt;
&lt;ins style="text-decoration:none;"&gt;Congratulations!&lt;/ins&gt; to those of you who
have chosen to join the ranks of parenthood, as well as congrats to those of you
who are now permanently off the dating market.  There are more of you in both
categories than I really expected, but I'm happy for you all the same.&lt;/p&gt;

&lt;p&gt;If you weren't there, you were missed, and you should come next time!  I didn't
even get an invite and still managed to show up, so the rest of you have no
excuse. &lt;tt&gt;:P&lt;/tt&gt;&lt;/p&gt;

&lt;p&gt;And, of course, a big thanks to Pete L. for arranging the whole affair.  He got
a 10+% turnout for our class, which I thought was pretty darn impressive, and
could not have picked a nicer night for it.  Hopefully next time I'll be
included in the list of invitees. &lt;tt&gt;;)&lt;/tt&gt;&lt;/p&gt;


&lt;p style="margin: 2em 0;"&gt;P.S.: If you're wondering what I've been up to, it amounts to "not much"
punctuated by a &lt;a href="http://pinterface.livejournal.com/tag/california" rel="nofollow"&gt;few&lt;/a&gt; &lt;a href="http://route66trip07.blogspot.com/" rel="nofollow"&gt;interesting&lt;/a&gt; &lt;a href="http://pinterface.livejournal.com/41121.html" rel="nofollow"&gt;excursions&lt;/a&gt;.  Also, if you'd like my e-mail address, just ask Pete; he's got it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;sup&gt;&lt;a name="fn1-how-i-found-out" href="#fnr1-how-i-found-out" rel="nofollow"&gt;curious&lt;/a&gt;&lt;/sup&gt; I found out about the reunion on Friday, because I googled for it.  Fortuitous timing!&lt;/li&gt;
&lt;li&gt;&lt;sup&gt;&lt;a name="fn2-award-for-most-pathetic" href="#fnr2-award-for-most-pathetic" rel="nofollow"&gt;loser&lt;/a&gt;&lt;/sup&gt; Yes.  Yes I am.&lt;/li&gt;
&lt;/ol&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:43635</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/43635.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=43635"/>
    <title>Introducing clavatar</title>
    <published>2012-08-26T03:02:41Z</published>
    <updated>2012-08-26T03:29:16Z</updated>
    <category term="bountyoss"/>
    <category term="libravatar"/>
    <category term="gravatar"/>
    <category term="programming"/>
    <category term="clavatar"/>
    <category term="lisp"/>
    <content type="html">&lt;p&gt;Earlier this week I discovered &lt;a href="http://libravatar.org/" rel="nofollow"&gt;Libravatar&lt;/a&gt;, a federated &lt;a href="http://gravatar.com/" rel="nofollow"&gt;Gravatar&lt;/a&gt; clone.  "Neat.", I said to myself in a very Bender-like tone.&lt;/p&gt;

&lt;p&gt;Then I found myself in need of a GitHub account and repo to play with &lt;a href="https://bountyoss.com/" rel="nofollow"&gt;BountyOSS&lt;/a&gt;'s progressing GitHub integration.  A test repo would be boring, so I thought to myself "Hey, this federated avatar stuff is pretty neato, I'll do a repo involving that.".  So I did.&lt;/p&gt;

&lt;p&gt;And the result is &lt;a href="https://github.com/pinterface/clavatar" rel="nofollow"&gt;clavatar&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you're building some sort of site with users, and you want to add avatar support without having to host all those pesky images yourself, you can use clavatar to find an appropriate avatar URL for a given e-mail address or OpenID/URL.  It supports libravatar-style federated avatars, Libravatar-as-a-service, Gravatar, and even &lt;a href="http://unicornify.appspot.com/" rel="nofollow"&gt;Unicornify&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;(clavatar:get-avatar-url &lt;span style="color: #8b2252;"&gt;"avatars@example.com"&lt;/span&gt; &lt;span style="color: #7a378b;"&gt;:size&lt;/span&gt; 120)
&lt;span style="color: #b22222;"&gt;; &lt;/span&gt;&lt;span style="color: #b22222;"&gt;=&amp;gt; #&amp;lt;URI ...&amp;gt;&lt;/span&gt;
(clavatar:get-avatar-url &lt;span style="color: #8b2252;"&gt;"http://example.com/user/avatars"&lt;/span&gt;)
&lt;span style="color: #b22222;"&gt;; &lt;/span&gt;&lt;span style="color: #b22222;"&gt;=&amp;gt; #&amp;lt;URI ...&amp;gt;&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Most of the dependencies are readily available through Quicklisp, but you will need a more recent copy of iolib.  And I do mean &lt;em&gt;recent&lt;/em&gt;—the patch required for clavatar to work &lt;a href="https://github.com/sionescu/iolib/commit/b3358f46976ed067e01431733e75a43c4d167548" title="Add SRV record support" rel="nofollow"&gt;landed earlier today&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:43510</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/43510.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=43510"/>
    <title>Video of Burgled-Batteries Talk is Available</title>
    <published>2012-07-12T05:03:15Z</published>
    <updated>2012-07-13T05:09:04Z</updated>
    <category term="talks"/>
    <category term="burgled-batteries"/>
    <category term="python"/>
    <category term="lisp"/>
    <content type="html">&lt;p&gt;(This will be my last post on &lt;a href="http://talks.kepibu.org/2012/pyowa-bb/" rel="nofollow"&gt;this talk&lt;/a&gt;, I promise!)&lt;/p&gt;

&lt;p&gt;You can now &lt;a href="http://www.youtube.com/watch?v=wkg0Vphegks" rel="nofollow"&gt;watch my talk on Youtube&lt;/a&gt;, if you are so inclined.&lt;/p&gt;

&lt;p&gt;Sadly, the first 22 minutes have an echo which makes it...awkward to listen to.  Due to being very nervous, I stuck more closely to the script than in my rehearsals, though, so if you've &lt;a href="http://talks.kepibu.org/2012/pyowa-bb/talk.html" rel="nofollow"&gt;read the talk&lt;/a&gt; you can skip the video.  Q&amp;amp;A starts at 30:30; unfortunately I was a bad presenter and failed to repeat the questions (even after being reminded that I should, gah!), so my answers may not make much sense.&lt;/p&gt;

&lt;p&gt;Nobody laughed at my scripted jokes, but people did say afterwards they found the talk interesting, so hooray for that!  It was a lot of work, and I'm kinda happy it's over and I can get back to actual programming now. &lt;tt&gt;:)&lt;/tt&gt;&lt;/p&gt;

&lt;p&gt;Thanks to the &lt;a href="http://pyowa.org/" rel="nofollow"&gt;Pyowa&lt;/a&gt; group for having me and recording the presentation, and also thanks to &lt;a href="http://www.texturacorp.com/" rel="nofollow"&gt;Textura&lt;/a&gt; for sponsoring both the meeting and drinks afterwards!&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:43202</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/43202.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=43202"/>
    <title>burgled-batteries: The Talk (July 10th!)</title>
    <published>2012-07-09T09:43:28Z</published>
    <updated>2012-07-09T09:43:28Z</updated>
    <category term="talks"/>
    <category term="burgled-batteries"/>
    <category term="python"/>
    <category term="programming"/>
    <category term="lisp"/>
    <content type="html">&lt;p&gt;I will be giving my talk on embedding CPython into Lisp (burgled-batteries) at &lt;a href="http://www.pyowa.org/" rel="nofollow"&gt;Pyowa&lt;/a&gt;, on Tuesday, July 10th.  &lt;a href="http://groups.google.com/group/pyowa/browse_thread/thread/aeac7cfa82be538a" rel="nofollow"&gt;The meeting&lt;/a&gt; is scheduled to start at 6PM CDT.&lt;/p&gt;

&lt;p&gt;If anybody wants to show up and heckle me in person, the address is 4445 Corporate Drive, West Des Moines, IA (&lt;a href="http://goo.gl/maps/Tqw2" rel="nofollow"&gt;Google maps&lt;/a&gt;).  But I understand if nobody wants to drive hours on end for that. &lt;tt&gt;:)&lt;/tt&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, I have been unable to confirm whether there will be a Google+ hangout for lispers to join in, or any video recorded.  (I remain hopeful, because Pyowa has done them before, but can make no promises.)  I'll try to pester the appropriate parties to link to either of those things from the &lt;a href="https://twitter.com/pyowa" rel="nofollow"&gt;Pyowa twitter feed&lt;/a&gt;, if they're available.  You might also try Pyowa's &lt;a href="http://www.youtube.com/user/iowapython" rel="nofollow"&gt;youtube&lt;/a&gt; or &lt;a href="https://plus.google.com/111538658049305487567" rel="nofollow"&gt;Google+&lt;/a&gt; accounts, just in case.&lt;/p&gt;

&lt;p&gt;Apologies that I cannot be more definitive about the possible methods of remote participation. &lt;tt&gt;:/&lt;/tt&gt;&lt;/p&gt;

&lt;p&gt;Slides, and my current script, are &lt;a href="http://talks.kepibu.org/2012/pyowa-bb/talk.html" rel="nofollow"&gt;already available&lt;/a&gt; (last run-through was ~35 minutes, somewhat less than my original timings, though I've expanded the latter half of the talk).  Thanks to those who have taken the time to review and provide feedback on my earlier drafts.  There's still time to offer some if you have any!&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:42970</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/42970.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=42970"/>
    <title>burgled-batteries: The Talk (Coming Soon?)</title>
    <published>2012-06-27T06:01:49Z</published>
    <updated>2012-06-27T06:01:49Z</updated>
    <category term="talks"/>
    <category term="burgled-batteries"/>
    <category term="python"/>
    <category term="programming"/>
    <category term="lisp"/>
    <content type="html">&lt;p&gt;My &lt;a href="http://www.pyowa.org/" rel="nofollow"&gt;local Python users group&lt;/a&gt; has expressed some interest in my giving a talk on &lt;a href="http://repo.kepibu.org/burgled-batteries/" rel="nofollow"&gt;burgled-batteries&lt;/a&gt;.  I figured "hey, why not?".&lt;/p&gt;

&lt;p&gt;They happen to be pretty good about recording presentations and doing Google+ hangouts and posting the videos to YouTube and so forth, so once I have a date for the talk and know where any of that stuff will be I'll mention where to find it and then the Lisp world can admire my awkwardness in front of a crowd, possibly maybe even join in and embarrass me with questions I should know the answers to but don't.&lt;/p&gt;

&lt;p&gt;In the mean time, if anybody would like to help me with my talk, I'm all ears.  I've got a &lt;a href="http://talks.kepibu.org/2012/pyowa-bb/talk.html" rel="nofollow"&gt;draft here&lt;/a&gt; that currently takes 45-50 minutes to run through.  Am I glossing over dealing with CPython too much?  Is there anything fellow Lispers would like to see more or less of in the talk?  Is it so terrible I should just toss it and start over?  Etc.&lt;/p&gt;

&lt;p&gt;It's a git repo, so you can do &lt;code&gt;git clone http://talks.kepibu.org/2012/pyowa-bb/.git/ pyowa-bb&lt;/code&gt; if you feel the urge to send patches, but general advice would be great too.  It'll be my very first talk, it'd be nice if it were at least mildly interesting to somebody somewhere. &lt;tt&gt;:)&lt;/tt&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:42630</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/42630.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=42630"/>
    <title>Firefox has Gone Rogue</title>
    <published>2012-06-12T00:50:44Z</published>
    <updated>2012-06-12T01:57:56Z</updated>
    <category term="wtf"/>
    <category term="usability"/>
    <category term="firefox"/>
    <content type="html">&lt;p&gt;Firefox just force-"upgraded" itself to v12, from 3.6.  Since I was staying on
3.6 for some very specific reasons (one of which being so I could take
screenshots for an entry noting everything they've screwed up in newer versions
of FF), I am &lt;em&gt;not&lt;/em&gt; happy.  Of course, since I never &lt;em&gt;gave&lt;/em&gt; it permission to
update to 12, I'm also not happy for reasons of "installing without permission
is what malware does, jerkwads".  There's also anger due to the "I just wanted
to do some work, not spend all day reconfiguring firefox" angle.&lt;/p&gt;

&lt;p&gt;Seeing as I am now unable to take aforementioned screenshots, here's the entry,
minus illustrating pictures:&lt;/p&gt;

&lt;h3&gt;The Many and Horrifying UI Sins of Firefox&lt;/h3&gt;

&lt;dl&gt;
&lt;dt&gt;Elimination of browser.link.open_external&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;For those of us with browser.link.open_newwindow set to the only sane value
(1—or "If I want it in a new tab/window, I'll ****ing tell you!"), the merging
of the completely different browser.link.open_external option was a sad day
indeed, because it meant that links from other applications (say, your mail
program) would destroy whatever page you were on, rather than opening in a new
window (or tab) as would be proper.&lt;/p&gt;

&lt;p&gt;see &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=469082" rel="nofollow"&gt;bug 469082&lt;/a&gt;, &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=324164" rel="nofollow"&gt;bug 324164&lt;/a&gt;, &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=509664" rel="nofollow"&gt;bug 509664&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=509664#c20" rel="nofollow"&gt;comment
20&lt;/a&gt; in bug 509664, which states "links from external programs should never
... open new windows".  Which is, ya know, the complete opposite of how many of
the people configuring open_external had it set.  Good job
listening!&amp;lt;/sarcasm&amp;gt;&lt;/p&gt;

&lt;p&gt;Corrective actions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://addons.mozilla.org/en-US/firefox/addon/restore-open_external/" rel="nofollow"&gt;Restore Open_External&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;might&lt;/em&gt; also be correctable by setting the undocumented preference
      browser.link.open_newwindow.override.external in very new versions of FF&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;

&lt;dt&gt;Opening Add-Ons configuration in a tab&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;see &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=597164#c3" rel="nofollow"&gt;comment
#3&lt;/a&gt; on the largely
unrelated &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=597164" rel="nofollow"&gt;bug
597164&lt;/a&gt; for what is pretty much my reasoning for thinking it bad, but written
by somebody else.&lt;/p&gt;

&lt;p&gt;Corrective action: &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/add-ons-manager-dialog-for-ff4/" rel="nofollow"&gt;Add-ons manager Dialog Returns&lt;/a&gt; (can not be uninstalled)
&lt;/p&gt;&lt;/dd&gt;

&lt;dt&gt;Combined back/forward history dropdowns&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;If I bring up the backwards history menu, it's because I want to go back,
and showing the opposite direction does not make sense.  Likewise for forwards.
Further, disjoint menus nicely follow Fitts' Law, where the greater number of
pages skipped requires the greater amount of effort, making it perfectly
intuitive.&lt;/p&gt;

&lt;p&gt;[img of combined dropdown] Quick, what do I click on to go back four pages?&lt;/p&gt;

&lt;p&gt;Corrective
action: &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/NoUn-Buttons/" rel="nofollow"&gt;NoUn
Buttons&lt;/a&gt; (was also necessary in FF3)—but beware it is not yet up to snuff on
newer firefoxen: it sorts the dropdowns properly, but fails to remove back items
from forward list, and vice versa.  (But &lt;em&gt;does&lt;/em&gt; if you right click.  The
hell?)&lt;/p&gt;&lt;/dd&gt;

&lt;dt&gt;Combined reload / stop buttons&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;"Reload" and "Stop" do two completely different things and on that point
alone should not be combined.&lt;/p&gt;

&lt;p&gt;Corrective actions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Can be suppressed by adding a spacer between the two buttons.
Unfortunately, this means you get an ugly extra space between them for your
troubles.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://addons.mozilla.org/en-US/firefox/addon/active-stop-button/" rel="nofollow"&gt;Active
Stop Button&lt;/a&gt; claims to include correction in addition to other, possibly
unwanted, behavioral changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;

&lt;dt&gt;Moved reload / stop buttons&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;Since the dawn of browsers, the buttons have been Back, Forward, Reload,
Stop.  Thou shalt not alter this order nor insert items in between.  You don't
even need any extra buttons (am I the only one who finds the Home button
completely pointless?).&lt;/p&gt;

&lt;p&gt;Corrective action: Rearrange.&lt;/p&gt;&lt;/dd&gt;

&lt;dt&gt;Tabs on top&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;This [img] is the browser UI.  This [img] is the browser UI with tabs on
top.  Any questions?&lt;/p&gt;

&lt;p&gt;NB: The illustration would have colored browser UI, document, and document
selector different colors, thus highlighting that with "tabs on top" (really
"tabs in the middle") the document selector is in the middle of the browser UI,
rather than between the browser UI and the document, where it belongs as the
part of the browser UI which transitions between documents.&lt;/p&gt;

&lt;p&gt;Corrective action: May be deselected in UI.&lt;/p&gt;&lt;/dd&gt;

&lt;dt&gt;URL Formatting&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;Why show the full URL, when you can confuse the hell out of people by
adding obnoxious coloring in an attempt to make the full URL less readable?&lt;/p&gt;

&lt;p&gt;Corrective action: set browser.urlbar.formatting.enabled to false in
about:config&lt;/p&gt;&lt;/dd&gt;

&lt;dt&gt;&lt;a href="http://" rel="nofollow"&gt;http://&lt;/a&gt; trimmed from URL bar&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;Dear Firefox, please stop copying Chrome.  If I wanted Chrome, I'd be
using it.  Kthx.&lt;/p&gt;

&lt;p&gt;Corrective action: set browser.urlbar.trimURLs to false in about:config&lt;/p&gt;&lt;/dd&gt;

&lt;dt&gt;Non-native widgets&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;While the non-native tabs in FF3 bugs me (and, by extension, the
non-native tabs in FF4+), the non-native widget that bugs me the most in newer
versions of Firefox is the URL bar.  They took a beautiful, native-looking thing
and shat all over it, turning this lovely thing [img] into this monstrosity
[img].&lt;/p&gt;

&lt;p&gt;Corrective action: None known.&lt;/p&gt;&lt;/dd&gt;

&lt;dt&gt;Remember password and Share location dialogs&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;This is what it looked like in FF3: [img]&lt;br&gt;
This is what you get in newer versions of FF: [img]&lt;/p&gt;
&lt;p&gt;Notice the large number of problems immediately apparent:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FF3 offered each available option with a single click.  FFn requires
selecting the item from a drop-down menu.&lt;/li&gt;
&lt;li&gt;In FF3, the default was obvious.  In FFn it is not.  In fact, notice how the
share location dialog makes it look like FF will share your location if you
simply dismiss it.&lt;/li&gt;
&lt;li&gt;FFn's dialog is vastly more intrusive.  Whereas FF3's could be ignored until
one was ready to deal with it, FFn's &lt;em&gt;demands&lt;/em&gt; attention by covering part
of the page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Corrective action: None known.&lt;/p&gt;&lt;/dd&gt;

&lt;dt&gt;Elimination of the status bar&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;First off, the status bar is where all the little bits you sometimes use
to interact with extensions go.  Sticking that stuff in the toolbar would take
up way too much space for anybody with more than one extension.  Second, it
provides a &lt;em&gt;stable&lt;/em&gt; place to look for certain information.&lt;/p&gt;

&lt;p&gt;Of course, it wouldn't bother me so much if I didn't have to install a gorram
extension just to get the status text on the status bar.  Look, I'm sorry you
can only afford a netbook as a Firefox UI designer, but some of us have real
computers and can afford the twelve pixels for the status bar.  There's no need
to be so hostile towards it.&lt;/p&gt;

&lt;p&gt;Corrective action: &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/status-4-evar/" rel="nofollow"&gt;Status-4-Evar&lt;/a&gt;&lt;/p&gt;&lt;/dd&gt;

&lt;dt&gt;Status bar has a close button&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;Who the hell decided a status bar needed a close button?  And on the
opposite side of every other close button, to boot!&lt;/p&gt;

&lt;p&gt;Corrective actions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://addons.mozilla.org/en-US/firefox/addon/status-4-evar/" rel="nofollow"&gt;Status-4-Evar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://addons.mozilla.org/en-US/firefox/addon/hide-add-on-bar-close-button/" rel="nofollow"&gt;Hide Add-on-Bar-Close-Button&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/dd&gt;
&lt;dt&gt;Right click -&amp;gt; View Link Info has gone away&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;I'm what, ten minutes into actually using FF12 and already I'm noticing missing features?  Ugh.&lt;/p&gt;

&lt;p&gt;Corrective action: None known.&lt;/p&gt;&lt;/dd&gt;
&lt;dt&gt;URL in status bar is abbreviated in the middle, rather than the end&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;I very nearly missed that a thing was abbreviated because the marker I was used to no longer exists at the end.  That's not necessarily bad (I was thrown off when "Find" no longer popped up a dialog box, for instance, but that was a clear improvement), but putting "..." in the middle means it's now impossible to tell the difference between "long thing with ... in it" and "long thing cut short" (and you can't exactly format "..." in a distinguishing manner, to differentiate).&lt;/p&gt;
&lt;p&gt;Corrective action: None known.&lt;/p&gt;&lt;/dd&gt;
&lt;/dl&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:42326</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/42326.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=42326"/>
    <title>Frikkin' Scavengers</title>
    <published>2012-06-05T06:36:51Z</published>
    <updated>2012-06-05T06:36:51Z</updated>
    <category term="things i don&amp;apos;t get"/>
    <category term="wtf"/>
    <category term="life"/>
    <content type="html">&lt;p&gt;My city's Spring Cleanup thing, the once a year they come around and pick up large, loose trash, is upon us.  With it come the scavengers—people who drive around picking up things they'd consider useful.  It's sort of like a city-wide garage sale where every item is free.&lt;/p&gt;

&lt;p&gt;So we threw a few items on the curb for the scavengers.  What I expected would happen is if a scavenger wanted an item, they'd take it.  Turns out, not so much: they'll destroy your item to get the part they want, then leave you holding the pieces of your now broken and useless item.&lt;/p&gt;

&lt;p&gt;I put out some old CRT monitors—not knowing whether the city will actually take them—thinking "well, maybe a scavenger will want one, and if they don't, and the city doesn't take it, I can just bring it back inside".  I'm no worse off either way, maybe somebody is a little better off.  At least, that was the plan.&lt;/p&gt;

&lt;p&gt;Some chap seemed interested in the monitors, turning them over.  I figured he was looking for some bit of info on the backs.  But then he left, failing to put them monitors upright.  "Well, that's rather rude, I thought." and went to put the monitors upright again.  Upon which I realized the monitors were now missing their built-in VGA cables, because the fellow had &lt;em&gt;sliced them off&lt;/em&gt;; taken the copper (presumably), and left the monitors.&lt;/p&gt;

&lt;p&gt;What the hell, man?  Look, once you &lt;strong&gt;take&lt;/strong&gt; the monitor, I don't care what you do with it.  Extract the copper, trash the rest, whatever.  But breaking my stuff (it's still in my yard, I'm still responsible for it, ergo still mine) and leaving me with a now-useless piece of equipment?  That's willful destruction of property, and a dick move.&lt;/p&gt;

&lt;p&gt;And I am pissed.&lt;/p&gt;

&lt;p&gt;Can't do anything about it because by the time I realized what he had done he was gone, but I'm still pissed.  So very, very pissed.  Because now the monitors are completely useless.  If the city doesn't take them I'll have to pay to recycle them because I can't even stick them back on the shelf as a spare.&lt;/p&gt;

&lt;p&gt;Asshole.&lt;/p&gt;

&lt;p&gt;Threw some printers on the curb, too.  Didn't see the person who took them, but they took the printer and left the paper guides and trays.  Look, they're a part of the thing you're taking!  If you don't want those pieces, throw them out with your own trash, dammit.&lt;/p&gt;

&lt;p&gt;Not nearly as dickish a move as bricking the CRTs, though.&lt;/p&gt;

&lt;p&gt;The guy who took the box of assorted Jeep parts I left out looked sheepish, like he thought he was stealing something.  That, at least, was hilarious.&lt;/p&gt;

&lt;p&gt;Even so, I think I'll just rent a dumpster next time.  Because Mr. Slice-n-Dash has left me bitter.  You don't smash things for the piece you want and leave the pieces, you take the whole thing.  Smashing for parts is completely disrespectful of the people who are leaving these nice things out for those who might find them useful.&lt;/p&gt;

&lt;p style="margin-top: 2em;"&gt;Am I wrong here, internet?  Am I wrong to expect that if someone is going to take something they should take the entire thing and tear it apart on their own turf?&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:42031</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/42031.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=42031"/>
    <title>Passwordless Drive Encryption for Virtual Machines on Linux</title>
    <published>2012-05-18T01:10:49Z</published>
    <updated>2012-05-18T01:10:49Z</updated>
    <category term="linux"/>
    <category term="encryption"/>
    <category term="vm"/>
    <category term="raid"/>
    <content type="html">&lt;p&gt;Recently, I acquired a used Xserve RAID.  Good storage capacity, and way cheaper
than buying new drives.  In the interests of data security I'd like easily
removed drives, such as those in the RAID, to have their contents encrypted.&lt;/p&gt;
&lt;p&gt;The master server is just a house for VMs.  And, because those VMs are generally
free to be rebooted with wild abandon, entering passwords into the VMs
controlling the RAID arrays would be a real downer.  Fortunately, the master
computer to which the RAID is attached is already set up with encrypted hard
drives—which means I can store keyfiles for the RAID arrays on it without
compromising security.&lt;/p&gt;
&lt;p&gt;In fact, thanks to proper layering, the VMs don't even have to know the drives
they're accessing are encrypted.&lt;/p&gt;
&lt;p&gt;Here's how.&lt;/p&gt;


&lt;h3&gt;Set up Drive Encryption&lt;/h3&gt;


&lt;p&gt;First, we'll need a key file.  Random data will do nicely.&lt;/p&gt;

&lt;pre&gt;&lt;span&gt;KEY_FILE&lt;/span&gt;=/etc/luks-keys/$&lt;span&gt;VMNAME&lt;/span&gt;
head -c /dev/random 1024 &amp;gt; $&lt;span&gt;KEY_FILE&lt;/span&gt;
chmod 400 $&lt;span&gt;KEY_FILE&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Next, set up encryption on the RAID array.&lt;/p&gt;

&lt;pre&gt;cryptsetup luksFormat $&lt;span&gt;RAID_DEVICE&lt;/span&gt; $&lt;span&gt;KEY_FILE&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;And then add it to crypttab, so encryption will be automatically set up and torn
down at system start/shutdown.&lt;sup&gt;&lt;a name="pdefvmid-footnote-1r" href="#pdefvmid-footnote-1" rel="nofollow"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;pre&gt;&lt;span&gt;UUID&lt;/span&gt;=&lt;span&gt;`cryptsetup luksUUID $RAID_DEVICE`&lt;/span&gt;
&lt;span&gt;echo&lt;/span&gt; $&lt;span&gt;RAID_VOLUME&lt;/span&gt; &lt;span&gt;UUID&lt;/span&gt;=$&lt;span&gt;UUID&lt;/span&gt; $&lt;span&gt;KEY_FILE&lt;/span&gt; luks &amp;gt;&amp;gt; /etc/crypttab
cryptdisks_start $&lt;span&gt;RAID_VOLUME&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The encryption set up and running, it's just a matter of creating the VM.&lt;/p&gt;




&lt;h3&gt;Configuring the VM&lt;/h3&gt;


&lt;p&gt;I like to create a partition on the regular drive for the VM's OS.  While not
strictly necessary, it gives a bit of flexibility (e.g., the ability to switch
between two different VMs controlling the RAID while testing different NAS
distributions), and leaves the maximum amount of space on the RAID array for
files.&lt;/p&gt;

&lt;pre&gt;lvcreate -L $&lt;span&gt;SIZE&lt;/span&gt; -n $&lt;span&gt;VOLNAME&lt;/span&gt; $&lt;span&gt;VOLGROUP&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;That done, actually make the VM.&lt;/p&gt;

&lt;pre&gt;virt-install --name $&lt;span&gt;VMNAME&lt;/span&gt; &lt;span&gt;\&lt;/span&gt;
  --disk /dev/$&lt;span&gt;VOLGROUP&lt;/span&gt;/$&lt;span&gt;VOLNAME&lt;/span&gt; &lt;span&gt;\&lt;/span&gt;
  --disk $&lt;span&gt;RAID_VOLUME&lt;/span&gt; &lt;span&gt;\&lt;/span&gt;
  …&lt;/pre&gt;

&lt;p&gt;Or, if adding the encrypted disk to an existing VM:&lt;/p&gt;

&lt;pre&gt;virsh attach-disk $&lt;span&gt;VMNAME&lt;/span&gt; $&lt;span&gt;RAID_VOLUME&lt;/span&gt; $&lt;span&gt;VMDEV&lt;/span&gt; --persistent&lt;/pre&gt;

&lt;p&gt;Once inside the VM, you can format the attached volume as normal, none the wiser
to the encryption.  It just works.&lt;/p&gt;
&lt;p&gt;Of course, encryption means if your RAID array loses one too many disks your
data is hosed irrecoverably, so be darn sure to &lt;a href="https://code.google.com/p/cryptsetup/wiki/FrequentlyAskedQuestions#6._Backup_and_Data_Recovery" rel="nofollow"&gt;have a good backup policy&lt;/a&gt; in
place before you start storing critical data on it!&lt;/p&gt;
&lt;p&gt;For the purpose of those backups, it might be desirable to ensure you can take
snapshots of the filesystem.  That's doable, too:&lt;/p&gt;

&lt;pre&gt;&lt;span&gt;VGNAME&lt;/span&gt;=$&lt;span&gt;RAID_VOLUME&lt;/span&gt;
vgcreate $&lt;span&gt;VGNAME&lt;/span&gt; $&lt;span&gt;RAID_DEVICE&lt;/span&gt;
lvcreate -L $&lt;span&gt;SIZE&lt;/span&gt; -n volume $&lt;span&gt;VGNAME&lt;/span&gt;
mkfs -t $&lt;span&gt;FSTYPE&lt;/span&gt; /dev/$&lt;span&gt;VGNAME&lt;/span&gt;/volume&lt;/pre&gt;

&lt;p&gt;where &lt;code&gt;$SIZE&lt;/code&gt; is some size smaller than the extent of the device.  Exactly how
much smaller depends on how much data churn you're expecting while the volume is
snapshotted, but I'd say leaving ~10% for the snapshot is probably
sufficient.&lt;sup&gt;&lt;a name="pdefvmid-footnote-2r" href="#pdefvmid-footnote-2" rel="nofollow"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Then you can attach the logical volume to your VM&lt;/p&gt;

&lt;pre&gt;virsh attach-disk $&lt;span&gt;VMNAME&lt;/span&gt; /dev/$&lt;span&gt;VGNAME&lt;/span&gt;/volume $&lt;span&gt;VMDEV&lt;/span&gt; --persistent&lt;/pre&gt;

&lt;p&gt;and use snapshots to back up the VM from outside with the VM none the wiser.&lt;/p&gt;
&lt;p&gt;Note that the mkfs turns out to be important: if you don't format the logical
volume before mounting it within the VM, the VM will see the LV rather than an unformatted block device and be
very confused.&lt;/p&gt;



&lt;h3&gt;A Note about Fibre Channel&lt;/h3&gt;


&lt;p&gt;Using the mptfc driver with my fibre channel card, I was unable to get
&lt;q style="font-family:monospace;quotes:&amp;quot;`&amp;quot; &amp;quot;`&amp;quot;;white-space:nowrap;"&gt;echo '- - -' &amp;gt; /sys/class/scsi_host/$HOST/scan&lt;/q&gt; to recognize a change in RAID
size, and don't recall having much luck actually specifying the parameters,
either.&lt;/p&gt;
&lt;p&gt;Rescanning was, however, successful with
&lt;q style="font-family:monospace;quotes:&amp;quot;`&amp;quot; &amp;quot;`&amp;quot;;white-space:nowrap;"&gt;echo 1 &amp;gt; /sys/class/scsi_device/$DEV/device/rescan&lt;/q&gt;&lt;/p&gt;
&lt;p&gt;So if scan doesn't help, try rescan.  It certainly beats rebooting!&lt;/p&gt;




&lt;h3&gt;Footnotes&lt;/h3&gt;

&lt;p&gt;&lt;sup&gt;&lt;a name="pdefvmid-footnote-1" href="#pdefvmid-footnote-1r" rel="nofollow"&gt;1&lt;/a&gt;&lt;/sup&gt; Alternatively, you could add a libvirt hook to set up and tear down the
    encryption before and after the VM is booted and shutdown.  That is left as
    an exercise to the reader.&lt;/p&gt;

&lt;p&gt;&lt;sup&gt;&lt;a name="pdefvmid-footnote-2" href="#pdefvmid-footnote-2r" rel="nofollow"&gt;2&lt;/a&gt;&lt;/sup&gt; As a point of reference, upgrading Debian from Stable to Testing requires
    ~7% of a 32GB volume.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:41822</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/41822.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=41822"/>
    <title>DLNA and Netflix: A Review</title>
    <published>2012-05-14T05:14:26Z</published>
    <updated>2012-05-16T12:55:05Z</updated>
    <category term="netflix"/>
    <category term="dlna"/>
    <content type="html">&lt;p&gt;Some time ago, we got a TV that supports DLNA.  I had no idea what that was, but a quick consultation with Wikipedia left me eager to give it a try.&lt;/p&gt;

&lt;p&gt;I've tried a couple of DLNA servers since then, and found all of them wanting in some manner.  I've also been using Netflix streaming of late, so I'll add that to the comparison seeing as it fills the same niche.&lt;/p&gt;

&lt;h3&gt;DLNA&lt;/h3&gt;

&lt;dl&gt;
&lt;dt&gt;Why?&lt;/dt&gt;&lt;dd&gt;I gave DLNA a shot because my TV supports it and it seemed like a good idea.&lt;/dd&gt;
&lt;dt&gt;Pros&lt;/dt&gt;&lt;dd&gt;
&lt;ul&gt;
&lt;li&gt;Works even when internet is down.&lt;/li&gt;
&lt;li&gt;Doesn't leak information about watched shows.&lt;/li&gt;
&lt;li&gt;Content stays available as long as you want it to.&lt;/li&gt;
&lt;li&gt;No commercials!&lt;/li&gt;
&lt;li&gt;No monthly fees.&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;Cons&lt;/dt&gt;&lt;dd&gt;
&lt;ul&gt;
&lt;li&gt;No fast-forward, rewind, chapter skipping, or single-frame progression.&lt;/li&gt;
&lt;li&gt;Can't handle interactive content (DVDs, etc.).&lt;/li&gt;
&lt;li&gt;Client capabilities differ significantly (e.g., in whether they support
     switching between multiple audio streams).&lt;/li&gt;
&lt;li&gt;Wildly varying client capabilities necessitates remuxing and/or
     transcoding, complicating servers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;Verdict&lt;/dt&gt;&lt;dd&gt;DLNA is a nice idea, poorly implemented atop a terrible protocol.
              Because none of the DLNA servers I've tried are perfect, I've
              ended up running two beside each other so I can use the fast one
              when it works, and the featureful one when the fast one can't do
              what I need.&lt;/dd&gt;
&lt;/dl&gt;


&lt;h4&gt;PS3 Media Server&lt;/h4&gt;


&lt;dl&gt;
&lt;dt&gt;Why?&lt;/dt&gt;&lt;dd&gt;I tried this at the recommendation of the local Linux User Group.&lt;/dd&gt;
&lt;dt&gt;Pros&lt;/dt&gt;&lt;dd&gt;
&lt;ul&gt;
&lt;li&gt;Supports pausing, skip forward, and skip backward.&lt;/li&gt;
&lt;li&gt;Ability to force audio to desired language (if available
     in file, of course).&lt;/li&gt;
&lt;li&gt;Debian package available (third-party).&lt;/li&gt;
&lt;li&gt;Can run headless.&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;Cons&lt;/dt&gt;&lt;dd&gt;
&lt;ul&gt;
&lt;li&gt;Slow to browse.  You can speed up browsing a bit by enabling the cache, but
     that broke audio language forcing for me.&lt;/li&gt;
&lt;li&gt;Slow to play.  Files require multiple seconds to start playing, skip
     forward, back, or unpause.&lt;/li&gt;
&lt;li&gt;Unpausing often restarts slightly before or after the pause time.&lt;/li&gt;
&lt;li&gt;Had to scrounge around forums for a profile that (mostly) works with my TV.&lt;/li&gt;
&lt;li&gt;Documentation assumes you're running the GUI, leaving most of the config
     file options un- or poorly-documented.&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;Verdict&lt;/dt&gt;&lt;dd&gt;PMS is okay.  The slowness is infuriating, and configuration
              involved more than starting it up, but it's been very stable.  The
              ability to prefer some languages over others is an excellent
              feature.&lt;/dd&gt;
&lt;/dl&gt;



&lt;h4&gt;MediaTomb&lt;/h4&gt;


&lt;dl&gt;
&lt;dt&gt;Why?&lt;/dt&gt;&lt;dd&gt;I tried this because it was in Debian.&lt;/dd&gt;
&lt;dt&gt;Pros&lt;/dt&gt;&lt;dd&gt;
&lt;ul&gt;
&lt;li&gt;Debian package.&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;Cons&lt;/dt&gt;&lt;dd&gt;
&lt;ul&gt;
&lt;li&gt;XML config file.&lt;/li&gt;
&lt;li&gt;Web interface.&lt;/li&gt;
&lt;li&gt;Can't pause or skip when remuxing or transcoding.&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;Verdict&lt;/dt&gt;&lt;dd&gt;MediaTomb is crap.  XML-based configuration files are terrible,
              and web interfaces are a blight upon mankind that should be
              abolished.  But even if you can look past that, the inability to
              do something as basic as &lt;em&gt;pause&lt;/em&gt; makes it completely worthless.&lt;/dd&gt;
&lt;/dl&gt;



&lt;h4&gt;Serviio&lt;/h4&gt;


&lt;dl&gt;
&lt;dt&gt;Why?&lt;/dt&gt;&lt;dd&gt;I tried this because it was mentioned somewhere on the interwebs.&lt;/dd&gt;
&lt;dt&gt;Pros&lt;/dt&gt;&lt;dd&gt;
&lt;ul&gt;
&lt;li&gt;Browses fast.&lt;/li&gt;
&lt;li&gt;Plays fast.&lt;/li&gt;
&lt;li&gt;Resumes fast.&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;Cons&lt;/dt&gt;&lt;dd&gt;
&lt;ul&gt;
&lt;li&gt;No Debian package.&lt;/li&gt;
&lt;li&gt;Can't switch audio language.&lt;/li&gt;
&lt;li&gt;Must be configured with included GUI client, no config file.&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;Verdict&lt;/dt&gt;&lt;dd&gt;Serviio is decent.  The fast pausing and unpausing is a welcome
              relief from pms's multi-second unpause, and the fast browsing
              makes getting to the file I want to watch much less painful.  The
              lack of a .deb is a bit of a downer, but installation is
              relatively straighforward (untar and run).  While I'd much prefer
              a proper config file, the only thing preventing me from ditching
              pms entirely is the inability to prefer a particular audio
              language.&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;&lt;b&gt;Edit (16.05.2012):&lt;/b&gt; I seem to have spoken too soon on Serviio.  Further testing on a wider range of files has shown it to sometimes have infuriatingly-long start-to-play times and that it works with fewer files than pms.  Alas, it had such promise!&lt;/p&gt;


&lt;h3&gt;Netflix Streaming&lt;/h3&gt;


&lt;dl&gt;
&lt;dt&gt;Why?&lt;/dt&gt;&lt;dd&gt;I tried this because hey, free trial.&lt;/dd&gt;
&lt;dt&gt;Pros&lt;/dt&gt;&lt;dd&gt;
&lt;ul&gt;
&lt;li&gt;Much wider array of content than my local media server.&lt;/li&gt;
&lt;li&gt;Skipping around the video is much nicer than DLNA.&lt;/li&gt;
&lt;li&gt;Selection UI is way better than DLNA.&lt;/li&gt;
&lt;li&gt;Good for discovering things you didn't know about or old things you'd
     forgotten.&lt;/li&gt;
&lt;li&gt;No commercials!&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;Cons&lt;/dt&gt;&lt;dd&gt;
&lt;ul&gt;
&lt;li&gt;Stops working when the internet goes down mid-video.&lt;/li&gt;
&lt;li&gt;No rewind, fast-forward, or single-frame movement.&lt;/li&gt;
&lt;li&gt;The video progress meter never goes away when paused.  (Especially annoying
     when pausing to try and read something, only for that thing to end up
     covered.)&lt;/li&gt;
&lt;li&gt;Never more than 720p.&lt;/li&gt;
&lt;li&gt;Leaks watched show information.&lt;/li&gt;
&lt;li&gt;Many things I'd like to watch aren't available (e.g., no Jack Benny).&lt;/li&gt;
&lt;li&gt;Content regularly disappears or threatens to disappear with minimal notice.&lt;/li&gt;
&lt;li&gt;Many series are only partially available.  E.g., you can watch ReBoot
     seasons 1 and 2, but not 3 or 4; and Sesame Street is missing the first
     forty years or so.&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;Verdict&lt;/dt&gt;&lt;dd&gt;Netflix is awesome, &lt;em&gt;when they have something you'll watch&lt;/em&gt;.
              Searching for something specific is an exercise in futility
              (if you're looking for it, Netflix won't have it), but browsing
              can often result in something interesting.  I very much enjoy when
              the "Comedies from the 1940s" category pops up, for instance; and
              the availability of the wealth of long-running series from the
              Star Trek and Stargate franchises will likely keep me subscribed
              and entertained for quite some time.&lt;/dd&gt;
&lt;/dl&gt;



&lt;h3&gt;Summary&lt;/h3&gt;


&lt;p&gt;Netflix and DLNA are both awesome ideas with not-so-awesome implementations,
but between the two Netflix is an incredible triumph.  DLNA generally works,
and is vastly superior to watching things on a computer monitor, but has little
else in its favor (I suspect I'd ditch it entirely if I had an HTPC running
XBMC).  Netflix certainly has areas in need of improvement, but I was surprised
at just how quickly and completely it supplanted any other method of watching
video content—my biggest annoyance is actually the pause thing, believe it or
not, because I pause to read things &lt;em&gt;all the time&lt;/em&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:41659</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/41659.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=41659"/>
    <title>Accept-Charset is Still Necessary</title>
    <published>2012-03-01T20:38:13Z</published>
    <updated>2012-03-01T20:38:13Z</updated>
    <category term="accept-charset"/>
    <category term="standards"/>
    <category term="http"/>
    <content type="html">&lt;p&gt;&lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=572652" rel="nofollow"&gt;Some people&lt;/a&gt; have apparently been arguing that the Accept-Charset HTTP request header &lt;a href="http://hsivonen.iki.fi/accept-charset/" rel="nofollow"&gt;is unnecessary&lt;/a&gt;.  Obsolete.  Not worth the extra bytes.&lt;sup&gt;&lt;a href="#fn-save-bytes" rel="nofollow"&gt;1&lt;/a&gt;&lt;/sup&gt;  And they've been  doing a pretty good job of arguing it: most newer browsers have stopped sending it.&lt;/p&gt;

&lt;p&gt;This is a mistake.&lt;/p&gt;

&lt;p&gt;The &lt;a href="http://www.ietf.org/rfc/rfc2616.txt" rel="nofollow"&gt;HTTP/1.1 spec&lt;/a&gt; has this to say:&lt;/p&gt;
&lt;blockquote&gt;If no Accept-Charset header is present, the default is that any character set is acceptable.&lt;/blockquote&gt;

&lt;p&gt;But practically speaking, sending any old character set won't work.  For instance, a modern browser is likely to have no idea what to do if you send it EBCDIC.  Which means, from a practical standpoint, you can only assume the available charsets are: what you're told the browser can handle via accept-charset, and what you're told by the standards the browser must support.&lt;/p&gt;

&lt;p&gt;HTTP/1.1 requires only one charset: ISO-8859-1.&lt;/p&gt;

&lt;p&gt;Section 14.2 implies this with:&lt;/p&gt;
&lt;blockquote&gt;If no "*" is present in an Accept-Charset field, then all character sets not explicitly mentioned get a quality value of 0, except for ISO-8859-1, which gets a quality value of 1 if not explicitly mentioned.&lt;/blockquote&gt;

&lt;p&gt;While section 3.7.1 makes it explicit:&lt;/p&gt;

&lt;blockquote&gt;The "charset" parameter is used with some media types to define the character set (section 3.4) of the data. When no explicit charset parameter is provided by the sender, media subtypes of the "text" type are defined to have a default charset value of "ISO-8859-1" when received via HTTP. Data in character sets other than "ISO-8859-1" or its subsets MUST be labeled with an appropriate charset value. See section 3.4.1 for compatibility problems.&lt;/blockquote&gt;

&lt;p&gt;ISO-8859-1 is a strict superset of ASCII, which means you can actually assume the availability of two charsets: ISO-8859-1 and ASCII.  Note, however, the complete and utter lack of a Unicode requirement.&lt;/p&gt;

&lt;p&gt;Now, if you've been around the web for a while, you'll know: way back before utf-8 became largely ubiquitous, not every browser sent an accept-charset header.  Some of those browsers did not support unicode.  (WebTV comes immediately to mind, I'm sure there were numerous others.)&lt;/p&gt;

&lt;p&gt;Which means that, even if we ignored the theoretical concern, we &lt;em&gt;still&lt;/em&gt; should not assume utf-8 support in the absence of a corresponding accept-charset because there are clients it would break.&lt;sup&gt;&lt;a href="#fn-everybody-wrong-but-me" rel="nofollow"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Now, certainly, feel free to require utf-8 support in the next version of HTTP (Google's SPDY does this, IIRC), and eliminate the header then.  That would be appropriate and acceptable.&lt;/p&gt;

&lt;p&gt;But not now.&lt;/p&gt;

&lt;p&gt;Because if you do it now, you bifurcate the HTTP/1.1 protocol.  You split it into the "early 2000s HTTP/1.1" where a missing accept-charset meant you needed to send ISO-8859-1 or ASCII, and the "2012 HTTP/1.1" where it means fuck all.&lt;/p&gt;

&lt;p&gt;There are enough broken things on the web today—don't add to it.  &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=731861" rel="nofollow"&gt;Put accept-charset back&lt;/a&gt;, and let's pretend this never happened.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a name="fn-save-bytes"&gt;&lt;/a&gt;You want to save bytes?  You can save quite a bit more by
changing browser UA strings to "&amp;lt;browser&amp;gt;/&amp;lt;version&amp;gt;", rather than the current "Mozilla/5.0 (&amp;lt;tons of crap&amp;gt;; &amp;lt;browser&amp;gt;/&amp;lt;version&amp;gt;; &amp;lt;even more crap&amp;gt;) &amp;lt;possibly extra crap&amp;gt;".  Better yet, discourage any remaining remnants of browser sniffing (a terrible idea from the start) and eliminate the header entirely.&lt;/li&gt;
&lt;li&gt;&lt;a name="fn-everybody-wrong-but-me"&gt;&lt;/a&gt;That virtually every website in existence wrongly assumes utf-8 support and sends it regardless does not justify modern browsers wrongly failing to advertise their support.  Some of us actually care enough to do this right, and you're making our job harder than it needs to be.&lt;/li&gt;
&lt;/ol&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:41413</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/41413.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=41413"/>
    <title>Accidental Load Testing</title>
    <published>2012-01-29T15:10:31Z</published>
    <updated>2012-01-29T17:00:59Z</updated>
    <category term="meta"/>
    <category term="webservers"/>
    <content type="html">&lt;p&gt;I run a low-traffic webserver.  I'm also marginally obsessed with returning pages quickly (for our &lt;a href="http://www.originaludderbalm.com/" rel="nofollow"&gt;primary site&lt;/a&gt;, as of this writing, Google reports the average time Googlebot spends downloading a page as 159 milliseconds, and that it takes 0.4 seconds to load for users on average).&lt;/p&gt;

&lt;p&gt;However, that's not terribly impressive when your busy season is significantly under 100,000 hits per month.  So I've often wondered what would happen if we were to get a sudden influx of traffic.  Would the server hold, or would it fall over?&lt;/p&gt;

&lt;p&gt;Thanks to an unintentional inclusion in Planet Lisp, my &lt;a href="http://pinterface.livejournal.com/41121.html" rel="nofollow"&gt;previous picture-heavy entry&lt;/a&gt; provided a small taste of what would happen in the event of sudden popularity.&lt;/p&gt;

&lt;img src="http://web.kepibu.org/log/2012/accident-stats/apache_accesses-jan.png"&gt;

&lt;p&gt;A sudden influx of traffic.  It dies off quickly, probably at least in part due to Xach's quick removal of the entry from the Planet Lisp feed.&lt;/p&gt;

&lt;img src="http://web.kepibu.org/log/2012/accident-stats/if_eth0-jan.png"&gt;

&lt;p&gt;As you might expect, lots of hits to the webserver has a strong correlation to the amount of outgoing traffic.&lt;/p&gt;

&lt;img src="http://web.kepibu.org/log/2012/accident-stats/load-jan.png"&gt;
&lt;img src="http://web.kepibu.org/log/2012/accident-stats/memory-jan.png"&gt;

&lt;p&gt;Load and memory usage stayed essentially constant, thanks to the use of lighttpd for static content such as images.  Had all of that traffic hit Apache, I imagine these two graphs would look somewhat different.&lt;/p&gt;

&lt;p&gt;In words, what happens with a large influx of HTTP requests is: not much.  Which is exactly what I want.  A larger influx of traffic, or traffic that would involve PHP pages, is of course another matter entirely and I still don't know how things would hold under that case.  But I'm quite pleased with the non-effect I saw in this case.&lt;/p&gt;

&lt;img src="http://web.kepibu.org/log/2012/accident-stats/fail2ban-jan.png"&gt;

&lt;p&gt;An interesting, and to me surprising, side effect is shown here: SSH probes had a significant jump in number.  I wonder why?&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:41121</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/41121.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=41121"/>
    <title>Nashville, 2010</title>
    <published>2012-01-05T11:34:14Z</published>
    <updated>2012-02-13T21:38:09Z</updated>
    <category term="tourism"/>
    <category term="vacation"/>
    <category term="sparky"/>
    <category term="nashville"/>
    <content type="html">&lt;p&gt;Way back in 2010 I visited my friend &lt;a href="http://sparksnotes.info/" rel="nofollow"&gt;sparky&lt;/a&gt; in Nashville.
It was good times, but I never got around to doing a write-up.&lt;/p&gt;
&lt;p&gt;Instead, I present my visit to Nashville in pictures.&lt;/p&gt;

&lt;h3&gt;Table of Contents&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/41121.html#nashville-getting-there" rel="nofollow"&gt;Getting to Nashville&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/41121.html#nashville-wandering-around" rel="nofollow"&gt;Wandering around Nashville&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/41121.html#nashville-inside-building" rel="nofollow"&gt;A Quick Stop in Union Station&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/41121.html#nashville-back-outside" rel="nofollow"&gt;Back Outside&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/41121.html#nashville-rockets" rel="nofollow"&gt;Rockets!&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/41121.html#nashville-nasa-park" rel="nofollow"&gt;NASA's Theme Park&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/41121.html#nashville-the-launch" rel="nofollow"&gt;Atlantis' Final Launch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/41121.html#nashville-nasa-park-2" rel="nofollow"&gt;More NASA Theme Park&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/41121.html#nashville-the-beach" rel="nofollow"&gt;A Sandy Detour&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/41121.html#nashville-at-night" rel="nofollow"&gt;Nashville at Night&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/41121.html#nashville-night-park" rel="nofollow"&gt;In the Parks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/41121.html#nashville-night-city" rel="nofollow"&gt;In the City&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/41121.html#nashville-ugly-mugs" rel="nofollow"&gt;Ugly Mugs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/41121.html#nashville-countryside" rel="nofollow"&gt;The Countryside&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/41121.html#nashville-host-home" rel="nofollow"&gt;House of Spark&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/41121.html#nashville-library" rel="nofollow"&gt;A Trip to the Library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/41121.html#nashville-church" rel="nofollow"&gt;Craig's Church&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/41121.html#nashville-getting-back" rel="nofollow"&gt;Going Home&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/41121.html#nashville-misc" rel="nofollow"&gt;Miscellanea&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;a name="cutid1"&gt;&lt;/a&gt;
&lt;h3&gt;&lt;a name="nashville-getting-there"&gt;Getting to Nashville&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;I took a plane to Nashville.  This involved some waiting
around in a terminal.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0054.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0054.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Not much to do in a terminal but take pictures of airporty
things.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0055.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0055.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0060.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0060.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0074.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0074.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0082.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0082.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;These chairs were reserved for people in wheelchairs.  Kinda
seems like a step down from being in a chair with wheels.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0058.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0058.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Don't forget to turn off fluid pumps when not in use.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0069.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0069.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It was an afternoon flight.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0077.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0077.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I'm not sure, but this might be a midget joke.  (Clearly
it's not meant for kids, there's nothing to color.)&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0079.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0079.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Apparently elevator permits are actual things.  Unlike my
ability to hold a camera steady.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0088.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0088.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I blame these on feeling "artsy".&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0053.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0053.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0089.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0089.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hooray, the plane!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0090.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0090.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Vroom vroom.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0092.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0092.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;During takeoff, the airfoils were set to 9 degrees.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0094.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0094.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A wild herd of school buses.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0096.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0096.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Guys, I think your boat missed the water!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0113.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0113.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For landing, 22 degrees.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0119.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0119.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A quick change of planes near Gate D28.  So quick I didn't
even go inside the airport.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0125.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0125.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Must be cold outside.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0137.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0137.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I realize the sign itself is asymmetrical, but surely I
can't be the only one bothered by the asymmetricality of the
arrow locations?&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0140.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0140.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Fluffy.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0150.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0150.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nashville!  Clearly, I was ... moved by the music.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0176.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0176.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Threat level Orange means the guy in the orange shirt is a
threat, right?&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0186.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0186.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Ah, there's my host!  Don't just stand there, I'm being
mugged you fool!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0187.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0187.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a name="nashville-wandering-around"&gt;Wandering around Nashville&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Apparently water meters are often confused with traffic
signals.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0188.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0188.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Vegetation!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0190.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0190.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Don't forget kids, it's important your hair color matches
your car.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0197.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0197.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I wish you well, young pine, but I do not expect things will
work out for you.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0209.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0209.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;My host decided he should take a picture.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0210.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0210.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This wall clearly needed to be remembered.  I wonder why?&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0216.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0216.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;More trees should wear nametags.  Really takes the guesswork
out of what species they are.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0218.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0218.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;if it weren't for the Bank of Nashville, this could have
been anywhere.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0220.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0220.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A real American Darling.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0230.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0230.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is mostly what I remember of Nashville.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0235.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0235.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I'm not sure, but I think a nearby power plant might burn
coal.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0241.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0241.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Who goes to a city known for its music and takes pictures of
plants?  This guy!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0244.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0244.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0315.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0315.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;&lt;a name="nashville-inside-building"&gt;A Quick Stop in Union Station&lt;/a&gt;&lt;/h4&gt;


&lt;p&gt;Opulent!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0246.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0246.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;They don't make 'em like that anymore.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0249.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0249.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;"Lost Divas"?&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0252.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0252.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Even the bathroom is swanky!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0254.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0254.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Harper's Weekly&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0256.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0256.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0255.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0255.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Really?  You guys couldn't spring for real logs?&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0262.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0262.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Dammit Frank, you weren't supposed to stare at the sculptor!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0271.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0271.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The ironworker was feeling a little loopy that day.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0283.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0283.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Even the carpet was fancy!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0297.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0297.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a name="nashville-back-outside"&gt;Back Outside&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;Where unattended packages will be confiscated and
destroyed.  By lasers!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0299.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0299.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I wonder what this thing is for?  Oh, handy, they tell me
who to ask.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0300.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0300.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I've got hundreds of out-of-focus pictures of interesting
things, but sparky's ass is one of the few in-focus
pictures.  Go figure.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0304.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0304.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Apparently the rebellion against good grammar is on
Facebook.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0324.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0324.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;"So how's the parking?"
"Eh, it's allright."&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0326.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0326.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Personally, I think commissioned art should look better than
graffiti.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0329.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0329.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0330.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0330.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Cop!  Act natural!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0338.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0338.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In the event of a rampaging giant, this building comes
equipped with handles.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0339.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0339.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Wait, that's not how you put a building together.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0346.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0346.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This was the secret entrance until budget cuts forced them
to close it up.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0347.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0347.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Should I be happy Nashville's citizens can read, or saddened
they need this much instruction on how to cross a street?&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0357.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0357.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;&lt;a name="nashville-rockets"&gt;Rockets!&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;During my trip to Nashville, we took a trip to Florida to
watch a space shuttle take off.&lt;/p&gt;
&lt;h4&gt;&lt;a name="nashville-nasa-park"&gt;NASA's Theme Park&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;Turns out NASA has their own theme park.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0372.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0372.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I think it may have been the shuttle Atlantis.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0375.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0375.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;NASA prefers to get their flags from Patriots.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0383.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0383.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I think my lens is dirty.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0378.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0378.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Just hangin' out.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0391.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0391.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0392.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0392.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For your safety, please do not bring a change of clothes.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0394.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0394.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The ground of NASA!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0399.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0399.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The ashtray of NASA!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0401.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0401.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The admission price of NASA!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0404.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0404.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Space tourism is fraught with DANGER!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0407.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0407.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The trash can of NASA!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0419.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0419.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Oh good, I was really concerned about your environmental
policy.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0423.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0423.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A map!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0439.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0439.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Finally, inside the NASA Theme Park.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0445.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0445.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Some sort of re-entry vehicle?&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0446.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0446.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Naturally, I'm interested in the device holding it.  That
makes sense.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0447.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0447.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A rare Space Croc!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0449.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0449.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I wonder if the darts are included with that
twelve-thousand-dollar rock.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0454.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0454.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Consumerism is in full swing at the NASA Gift Shop.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0455.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0455.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Warning: do not steal this shuttle and fly into space.  You
will burn up on re-entry.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0456.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0456.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The line to see the fake shuttle.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0459.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0459.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I had no idea what those people were standing around for,
and so just walked past everybody.  Nobody said anything.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0465.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0465.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0461.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0461.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;No warning lights went off.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0462.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0462.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;But there were some ladder problems.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0463.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0463.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So I took the elevator back down.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0467.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0467.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I attended a presentation by Buzz Lightyear.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0477.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0477.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I wandered into some building to get out of the heat.  Air
conditioning!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0500.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0500.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Listen for British Intelligence.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0506.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0506.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There's something strange about that cargo.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0509.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0509.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Turns out I'm in line for a movie!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0513.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0513.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;3D doesn't work very well.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0521.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0521.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;After the movie, we traveled back in time.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0533.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0533.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Unfortunately, they keep the doors locked.  Sure looks like
fun in there!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0541.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0541.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;At NASA theme park?  Check.  Taking pictures of plants?
Check.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0384.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0384.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0444.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0444.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0471.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0471.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0487.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0487.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0657.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0657.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0658.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0658.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a name="nashville-the-launch"&gt;Atlantis' Final Launch&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;Everybody's getting ready to watch the launch.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0551.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0551.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0552.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0552.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Quick, take a picture of a tree!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0554.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0554.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A flyby to, uh, make sure nobody is packing a bazooka?&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0556.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0556.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0563.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0563.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Turns out this is about the closest we're gonna get to the
shuttle.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0557.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0557.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Whoooooooosh!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0566.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0566.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0571.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0571.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0577.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0577.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0580.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0580.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The crowd looks on in awe.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0590.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0590.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;While I take a moment to check out some guy's ass.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0591.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0591.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Sparky felt like a kid again; I still had my zoom lens on.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0598.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0598.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a name="nashville-nasa-park-2"&gt;More NASA Theme Park&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;How do you top a shuttle launch?  With LEGOs!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0612.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0612.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Some complete strangers pose while somebody else takes a
picture.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0616.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0616.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I suspect this isn't a robot so much as a sculpture.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0626.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0626.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The answer is in the data!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0632.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0632.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We take revenge against HAL.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0634.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0634.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And journey to Mars!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0636.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0636.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Only to get trapped inside Tron.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0640.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0640.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To ensure astronaut happiness, NASA cultivates Space-Weed.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0643.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0643.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The barcode is a nice touch.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0650.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0650.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Oh, there you are, Sparky.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0653.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0653.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thanks to Sparky's amazing planning, we took a cab back to
where we parked.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0668.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0668.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And, without any sleep, drove back to Nashville.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0670.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0670.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a name="nashville-the-beach"&gt;A Sandy Detour&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;But first, let's check out this test hole.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0678.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0678.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Oh, and maybe spend some time at the beach.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0680.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0680.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It's a very welcoming beach.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0683.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0683.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I still need to clean that lens.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0693.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0693.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I took a lot of pictures of water.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0737.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0737.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Surfin' USA!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0747.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0747.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Sir, I don't care how handsome your smile is, that baby
carriage still looks ridiculous.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0755.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0755.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;&lt;a name="nashville-at-night"&gt;Nashville at Night&lt;/a&gt;&lt;/h3&gt;


&lt;p&gt;Sparky enters a trance and catches up with the Internet.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0762.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0762.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Meanwhile, I explore the local cuisine.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0771.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0771.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a name="nashville-night-park"&gt;In the Parks&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;We stop at a park for some sunset pictures.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0809.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0809.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It's a little creepy.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0817.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0817.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0827.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0827.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Berries!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0852.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0852.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Sparky looks for just the right angle.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0868.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0868.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0874.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0874.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And leaves a message for future generations.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0877.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0877.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Anyswing for the shot!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0894.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0894.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0896.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0896.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We head off to a different park, where we pick up a modeling
client.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0916.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0916.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0917.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0917.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And I find some roses.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0927.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0927.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0929.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0929.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Sparky aims for a water shot.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0935.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0935.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I may have intruded upon a private moment between him and
his camera.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0946.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0946.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Guys, I think you're supposed to land at sunset, not take
off.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0955.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0955.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0956.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0956.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It was a pretty sunset.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0959.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0959.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;What's this?  We've been transported to Europe!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0979.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0979.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I try my hand at a water shot.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_0985.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_0985.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Too dark for pictures?  Not with long exposures!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1019.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1019.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Oh screw it.  Flash!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1028.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1028.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a name="nashville-night-city"&gt;In the City&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;The Nashville night life!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1051.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1051.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Sparky sets up a shot.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1059.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1059.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I become enamoured.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1060.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1060.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Celebrate the music scene.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1069.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1069.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1080.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1080.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Don't forget to buy a t-shirt.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1081.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1081.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;But no parking.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1118.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1118.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This building not well ventilated.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1123.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1123.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Whirrr.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1131.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1131.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Turns out they don't actually print things in Printers
Alley.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1145.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1145.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Apparently the date did not go well.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1157.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1157.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Sparky takes notes.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1164.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1164.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Don't blink.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1176.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1176.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;&lt;a name="nashville-ugly-mugs"&gt;Ugly Mugs&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;While I have surprisingly few pictures of the place, we
spent a large amount of time at &lt;a href="http://uglymugsnashville.com/" rel="nofollow"&gt;Ugly Mugs&lt;/a&gt;, Sparky's
coffeeshop of choice.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1765.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1765.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1185.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1185.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1191.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1191.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1203.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1203.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;My laptop is bigger.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1188.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1188.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;They kept the place nice and warm.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1193.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1193.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In case you wondered about the name.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1194.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1194.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A fine selection.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1201.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1201.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Sparky, get internet at home for that sort of thing!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1210.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1210.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;&lt;a name="nashville-countryside"&gt;The Countryside&lt;/a&gt;&lt;/h3&gt;


&lt;p&gt;We took a trip out to the countryside and took some
pictures.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1215.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1215.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1219.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1219.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The grass was happy to be in focus.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1225.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1225.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A bug photobombs.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1288.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1288.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We pass some bioxide.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1304.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1304.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Heavy traffic.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1319.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1319.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Don't look at me, I'm naked!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1330.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1330.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That soccer field's a real dump.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1360.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1360.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I believe it safe to assume this fellow is monied.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1416.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1416.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;&lt;a name="nashville-host-home"&gt;House of Spark&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;All my pictures are blurry and out of focus.  Boo!  There's
a lovely bamboo forest in the backyard, and the interior is
actually decorated (a former housemate was a decorator,
apparently).  The house itself, however, could stand some
TLC.  And possibly a new roof.&lt;/p&gt;
&lt;h3&gt;&lt;a name="nashville-library"&gt;A Trip to the Library&lt;/a&gt;&lt;/h3&gt;


&lt;p&gt;We went to the library to watch little girls in tutus.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1522.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1522.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1538.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1538.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;At the end they took a bow.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1573.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1573.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The place cleared out quickly.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1655.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1655.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And we could explore the rest of the library.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1665.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1665.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;&lt;a name="nashville-church"&gt;Craig's Church&lt;/a&gt;&lt;/h3&gt;


&lt;p&gt;What does an atheist do at &lt;a href="http://www.mosaicnashville.us/" rel="nofollow"&gt;church&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1671.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1671.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I'm pretty sure it involves fancy equipment.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1690.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1690.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And sound checks.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1710.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1710.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let's slip into something a little more comfortable for the
Lord.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1724.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1724.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;&lt;a name="nashville-getting-back"&gt;Going Home&lt;/a&gt;&lt;/h3&gt;


&lt;p&gt;Before I know it, it's time to say goodbye to Nashville.  So
I hopped on a plane and went home.&lt;/p&gt;
&lt;p&gt;The in-flight entertainment for the first leg of the flight
home was pretty good.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1888.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1888.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1897.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1897.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1904.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1904.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1917.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1917.thumb.jpg"&gt;&lt;/a&gt;
&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1921.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1921.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Due to a small problem, my connecting flight taxied from the
runway back to the airport, where we all got off the plane
and waited.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_1996.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_1996.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And waited.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_2028.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_2028.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And waited.  Finally, we got back
on the plane to go home.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.kepibu.org/log/2012/nashville/img_2065.scaled.jpg" rel="nofollow"&gt;&lt;img border="0" src="http://web.kepibu.org/log/2012/nashville/img_2065.thumb.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a name="nashville-misc"&gt;Miscellanea&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Though not pictured, we both really enjoyed "The Butler Dunnit" at the
in-the-round &lt;a href="http://www.dinnertheatre.com/" rel="nofollow"&gt;Chaffin's Barn Dinner Theatre&lt;/a&gt;.  If you're in Nashville,
it's totally worth a visit.&lt;/p&gt;
&lt;p&gt;I'm not really a music lover, so Nashville's many bars and
live music venues had little to offer me.  We did not attend
any.&lt;/p&gt;
&lt;p&gt;Unfortunately, Nashville was struck with floods before I
arrived, and many of the places we would have visited were
closed for repairs.&lt;/p&gt;
&lt;p&gt;Because it's taken me so long to even do this much, I
haven't done any post-processing on the pictures.  That
means some (mostly night pictures) are much too dark.  It
also means some of my comments may not make much sense
because the thing I'm commenting on is only really visible
at full size, and I haven't done the necessary cropping for
the scaled-down versions presented.  Apologies.&lt;/p&gt;
&lt;p&gt;Sparky: I'd love to include some of the pictures you took
while I was taking pictures of you taking pictures.  If
you happen to have any handy. &lt;tt&gt;:D&lt;/tt&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:40934</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/40934.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=40934"/>
    <title>Strategies for Automatic Release of Foreign Resources</title>
    <published>2011-11-30T09:18:19Z</published>
    <updated>2011-11-30T09:23:38Z</updated>
    <category term="cffi"/>
    <category term="lisp"/>
    <content type="html">&lt;p&gt;Wanting to avoid forcing users of burgled-batteries to deal with cpython reference counts for Python types with unknown translation, I'm exploring not one, but two separate strategies for automatically handling the issue.&lt;/p&gt;

&lt;p&gt;The second, upon which I based my previous &lt;a href="http://pinterface.livejournal.com/40614.html" rel="nofollow"&gt;ill-advised CFFI trick&lt;/a&gt;&lt;a href="#fn-bad-cffi-trick" rel="nofollow"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;, and for which I am grateful to Paul Khuong for &lt;a href="http://www.pvk.ca/Blog/Lisp/finalizing_foreign_pointers_just_late_enough.html" rel="nofollow"&gt;correcting my error&lt;/a&gt;, is to let the GC decide when a resource is no longer needed.  As I discovered attempting to test it, however, this does not necessarily free one from thinking about when a resource can be freed.&lt;/p&gt;

&lt;p&gt;The first approach, which is considerably more deterministic, is also somewhat more limiting in extent.  In that approach, pointers are also wrapped, but the wrapped-value has dynamic-extent within a barrier&lt;a href="#fn-by-any-other-name" rel="nofollow"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;.  Leave the barrier, and any wrappers are relieved of their wrapped value.&lt;/p&gt;

&lt;p&gt;Both approaches have at least one downside in common: wrapped values cannot be used in place of a POINTER.  This can be lessened somewhat for CFFI's TRANSLATE-*-FOREIGN functions (with some caveats involving the use of the EXPAND- variants):
&lt;pre&gt;(defmethod translate-to-foreign ((value wrapped) type)
  (translate-to-foreign (wrapped-value value) type))
(defmethod translate-from-foreign ((value wrapped) type)
  (translate-from-foreign (wrapped-value value) type))
(defmethod free-translated-object ((value wrapped) type param)
  (free-translated-object (wrapped-value value) type param))&lt;/pre&gt;
but MEM-REF and friends (reasonably!) assume POINTERs, so there's no getting around callers noticing the difference.  Whether that's a worthwhile tradeoff depends on your goals.&lt;/p&gt;

&lt;h3&gt;Release by GC&lt;/h3&gt;

&lt;dl&gt;
&lt;dt&gt;The Good&lt;/dt&gt;&lt;dd&gt;Foreign resource has indefinite extent&lt;/dd&gt;
&lt;dt&gt;The Bad&lt;/dt&gt;&lt;dd&gt;Freeing of foreign resource is unpredictable&lt;/dd&gt;
&lt;dt&gt;The Story&lt;/dt&gt;&lt;dd&gt;

&lt;p&gt;While I'm not always particularly good about testing, refcnts are incredibly easy to screw up and tracking down refcnt bugs is unpleasant, so I've been trying to make sure I test things involving them to catch when I screw up.&lt;/p&gt;

&lt;p&gt;After a while flailing about with no idea what I was doing (seriously: at some point I decided adding threads into the mix would make it easier to test things involving the GC), I
had an epiphany.  "Gee, I wonder if trivial-garbage has finalizer-related tests?"  It does.  Well then, I'll just copy whatever they do.&lt;/p&gt;

&lt;pre&gt;;;; I don't really understand this, but it seems to work, and stems
;;; from the observation that typing the code in sequence at the REPL
;;; achieves the desired result. Superstition at its best.
(defmacro voodoo (string)
  `(funcall
    (compile nil `(lambda ()
                    (eval (let ((*package* (find-package :tg-tests)))
                            (read-from-string ,,string)))))))&lt;/pre&gt;

&lt;p&gt;I'm not particularly thrilled with the "call with strings of Lisp code" interface for VOODOO, so I mess with it a little but not too much because I understand it even less than the original author.&lt;/p&gt;

&lt;pre&gt;(defun voodoo (expr)
  (funcall (compile nil `(lambda () (eval (read-from-string (prin1-to-string ',expr))))))
  (values))&lt;/pre&gt;

&lt;p&gt;Having simplified my tests, and confident the remaining problems I was seeing were in fact problems with my tests and not with the thing being tested, I set about discovering what those problems might be.&lt;/p&gt;

&lt;pre&gt;(let* ((wrapped (run code))
       (unwrapped (wrapped-value wrapped)))
  (do-things-with unwrapped))&lt;/pre&gt;

&lt;p&gt;Spot the problem?  If not, here's a hint: after what point is WRAPPED eligible for GC?&lt;/p&gt;

&lt;p&gt;WRAPPED might get GCed at any point after &lt;code&gt;(wrapped-value wrapped)&lt;/code&gt; is calculated.  If that happens, the finalization on WRAPPER changes, and potentially destroys, what UNWRAPPED points to.  And then you've got a problem with the test (or, potentially, user code).&lt;/p&gt;

&lt;p&gt;Lesson learned: don't wander around with an unwrapped pointer in a &lt;code&gt;&amp;amp;body&lt;/code&gt;.  But it's worse than that.  Don't even pass the unwrapped pointer to a function if you can avoid it:&lt;/p&gt;

&lt;pre&gt;(let ((wrapped (run code)))
  (do-things-with (wrapped-value wrapped)))&lt;/pre&gt;

&lt;p&gt;WRAPPED becomes eligible for GC as soon as WRAPPED-VALUE returns, which means the C object might go away before the pointer is passed to DO-THINGS-WITH, or any time during the execution of DO-THINGS-WITH.&lt;/p&gt;

&lt;p&gt;If you're lucky, liveness will be ensured by wrapped pointers being part of some larger datastructure, but if not, it becomes necessary to make sure WRAPPED is required later on, to avoid it becoming eligible for GC too soon.&lt;/p&gt;

&lt;pre&gt;(let* ((wrapped (run code))
       (unwrapped (wrapped-value wrapped)))
  (do-things-with unwrapped)
  (calculate-something-using wrapped))&lt;/pre&gt;

&lt;p&gt;Unfortunately, if using wrapped pointers, one must keep in mind the liveness of the wrapper, lest foreign resources disappear too soon—making them not quite so effortless as I
had hoped.&lt;/p&gt;
&lt;/dd&gt;&lt;/dl&gt;

&lt;h3&gt;Release by Barrier&lt;/h3&gt;

&lt;dl&gt;
&lt;dt&gt;The Good&lt;/dt&gt;&lt;dd&gt;Foreign resource is freed predictably&lt;/dd&gt;
&lt;dt&gt;The Bad&lt;/dt&gt;&lt;dd&gt;Ham-fisted approach&lt;/dd&gt;
&lt;dt&gt;The Story&lt;/dt&gt;&lt;dd&gt;

&lt;p&gt;I started with refcnt barriers first because they're considerably less scary to write.  Their predictability also makes them considerably easier to debug and reason about.&lt;/p&gt;

&lt;pre&gt;(defclass barrier-wrapper ()
  ((value :initarg :wrap :reader wrapped-value)))&lt;/pre&gt;

&lt;p&gt;Wrapper.  The invalidation of pointers upon exiting the barrier necessitates an ability to modify the VALUE slot.  Hopefully nobody does.&lt;/p&gt;

&lt;pre&gt;(defvar *barrier-objects*)
(defun initialize-instance :after ((object barrier-wrapper) &amp;amp;key)
  (push object *barrier-objects*))&lt;/pre&gt;

&lt;p&gt;Nothing fancy.  Just quick-and-easy tracking of wrappers created within a barrier.&lt;/p&gt;

&lt;pre&gt;(defmacro with-barrier (&amp;amp;body body)
  (let ((*barrier-objects* (list)))
    (unwind-protect
        (progn ,@body)
      (mapcar #'invalidate-wrapper *barrier-objects*))))

(defun invalidate-wrapper (wrapper)
  (free-somehow (wrapped-value wrapper))
  (slot-makunbound wrapper 'value))&lt;/pre&gt;

&lt;p&gt;Clearly I'm taking liberties with #'FREE-SOMEHOW, but you get the point.  Upon exiting the extent of the form, we free the resource and invalidate the wrapped value.  I unbind the
slot, but setting it to NIL might better suite your tastes.&lt;/p&gt;

&lt;p&gt;This is certainly useful in some cases, such as where you're processing things in a loop and each iteration is unrelated to the next, so you don't need to carry any values over.  And it's not as if WITH-THING is unheard-of.  But the complete lack of subtlety bothers me.&lt;/p&gt;

&lt;p&gt;While it'd certainly be possible to provide a little more nuance by adding in the ability to promote objects to the next barrier or GC-ability, I'm not convinced reintroducing parts of manual memory management is an appropriate method of dealing with the shortcomings of a system meant to automate it away.&lt;/p&gt;
&lt;/dd&gt;&lt;/dl&gt;

&lt;h3&gt;Conclusions&lt;/h3&gt;

&lt;p&gt;While both are (to me) clear winners over forcing the issue on library users, I don't think either is a clear winner over the other.  Letting the GC handle things is more conceptually elegant, but practically speaking it has some thorny issues that are difficult to overcome and even harder to spot.&lt;a href="#fn-have-fun-finding-that-bug" rel="nofollow"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; Barriers are easy to reason about, but they're lacking in useful nuance, and I suspect would wind up being too large to be practical, or too small to be useful.&lt;/p&gt;

&lt;p&gt;So, for now at least, burgled-batteries admits both approaches, though I have not yet come up with a good way to enable the approaches to be interleaved.&lt;/p&gt;

&lt;p&gt;A third approach might be a sort of hybrid, where an implementation similar to barriers is used not to ensure foreign objects are destroyed upon exiting the form's extent, but to ensure they remain available within it.  A "corral", I guess you might call it?&lt;/p&gt;

&lt;p&gt;At any rate, the search continues for the perfect means of automatically dealing with foreign resources.&lt;/p&gt;

&lt;h3&gt;Footnotes&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a name="fn-bad-cffi-trick"&gt;&lt;/a&gt;One of the great things about being wrong on Planet Lisp instead of just my own little echo chamber: somebody is vastly more likely to notice and correct me.  Trying to debug the problems that would have arisen from my original approach would have been Not Fun.&lt;/li&gt;
&lt;li&gt;&lt;a name="fn-by-any-other-name"&gt;&lt;/a&gt;It is entirely possible I have incorrectly co-opted the term "barrier".  If so, I'd be happy to switch to a more correct term, if one exists.&lt;/li&gt;
&lt;li&gt;&lt;a name="fn-have-fun-finding-that-bug"&gt;&lt;/a&gt;For instance: You unwrap and pass the value to foreign code, foreign code issues a callback, callback triggers a GC, wrapper goes away taking the wrapped foreign value with it.&lt;/li&gt;
&lt;/ol&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:40614</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/40614.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=40614"/>
    <title>CFFI Tricks: Automatic Freeing of C Resources</title>
    <published>2011-11-13T02:50:49Z</published>
    <updated>2011-11-13T12:31:05Z</updated>
    <category term="cffi"/>
    <category term="lisp"/>
    <content type="html">&lt;p&gt;Lisp finalizers, at least the ones provided by &lt;a href="http://www.cliki.net/trivial-garbage" rel="nofollow"&gt;trivial-garbage&lt;/a&gt;, are not at first glance particularly useful.&lt;/p&gt;

&lt;p&gt;You can't reference the object being finalized—on some lisps, the object is already gone by the time you get to the finalizer—so you can't inspect the constituent parts of an object to operate on them.  Closing over the parts only works in the event an object cannot be destructively updated—since most objects in CL &lt;em&gt;can&lt;/em&gt; be destructively updated, that would require resetting the finalizer on update.  Of course, since objects can have multiple
finalizers, and you can't selectively clear them, you might accidentally wipe away someone else's finalizer.&lt;/p&gt;

&lt;p&gt;In short, finalizers are only good for unique, constant objects.  &lt;del&gt;Like, say, your typical usage of a foreign-pointer.&lt;/del&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Note (added 2011.11.13):&lt;/b&gt; Paul Khuong &lt;a href="http://www.pvk.ca/Blog/Lisp/finalizing_foreign_pointers_just_late_enough.html" rel="nofollow"&gt;has pointed out&lt;/a&gt; the below is a bad idea akin to trying to stick a finalizer on a fixnum.  Whoops!&lt;/p&gt;

&lt;pre&gt;(defvar *ptr* (gced-foreign-alloc :int))&lt;/pre&gt;

&lt;p&gt;For this example, we're going to define a wrapper for #'FOREIGN-ALLOC which sets up the finalization of our pointer object.  In your code, you'll probably bake the finalization setup into a method on #'TRANSLATE-FROM-FOREIGN which returns a pointer.&lt;/p&gt;

&lt;pre&gt;(defun gced-foreign-alloc (type &amp;amp;rest rest)
  (let* ((ptr (apply #'foreign-alloc type rest))
         (addr (pointer-address ptr)))
    (tg:finalize ptr
                 (lambda ()
                   (foreign-free (make-pointer addr))))))&lt;/pre&gt;

&lt;p&gt;Because the object being finalized is not passed to the finalizer function, and because closing over it would result in keeping the pointer around indefinitely, we instead close over just enough information to recreate the pointer: the address.&lt;/p&gt;

&lt;p&gt;That's right, we recreate the pointer in order to free it.  This feels a little odd, but the restrictions on portable finalizers rather limit our options; so, we cross our fingers and hope for the best.&lt;a href="#cffi-trick-4-footnote-1" rel="nofollow"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you were expecting a long entry, I'm sorry to disappoint: that's pretty much all there is to it.&lt;/p&gt;

&lt;pre&gt;(setf *ptr* nil)
(tg:gc :full t)&lt;/pre&gt;

&lt;p&gt;There are, however, some caveats to this approach.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Because GC runs cannot be guaranteed to occur at any given time, the pointed-to object may be held far longer than you'd prefer.&lt;/li&gt;
&lt;li&gt;Recreating the pointer with something like &lt;code&gt;(make-pointer (pointer-address *ptr*))&lt;/code&gt;, or even just having a #'POINTER-EQ pointer returned by a C function call, may result in multiple non-EQ objects pointing to the same memory address and too-early freeing.&lt;/li&gt;
&lt;li&gt;If the foreign side moves objects around, the address may no longer be correct once the finalizer runs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One is only an annoyance, and three is liable to cause you problems elsewhere anyway.  That second caveat is a biggie, however, and means this technique is unsafe for use when dealing with arbitrary C code—careful consideration of applicability is necessary.  For example, it's useful in burgled-batteries to automatically handle decrementing
reference counts on untranslatable objects, but I wouldn't use it to &lt;code&gt;free()&lt;/code&gt; memory.&lt;/p&gt;

&lt;h3&gt;Footnotes&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a name="cffi-trick-4-footnote-1"&gt;&lt;/a&gt;Because finalizers operate on a specific object, so long as &lt;code&gt;(eq (make-pointer x) (make-pointer x))&lt;/code&gt; is NIL, there should be no issues.  If it's T, some GC implementations could conceivably be tripped up, but I
think that's unlikely.&lt;/li&gt;
&lt;/ol&gt;

&lt;hr&gt;

&lt;h3&gt;Aside: Greetings Planet Lisp!&lt;/h3&gt;

&lt;p&gt;This being my first new post since I was added to Planet Lisp, here are some other, more generally applicable, CFFI Tricks you may have missed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/40399.html" rel="nofollow"&gt;Instrumenting the Groveller&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/40037.html" rel="nofollow"&gt;Mapping C Arguments to Lisp Return Values&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pinterface.livejournal.com/39882.html" rel="nofollow"&gt;Creating a Lisp Version of a Missing C Function&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:40399</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/40399.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=40399"/>
    <title>CFFI Tricks: Instrumenting the Groveller</title>
    <published>2011-10-26T16:17:57Z</published>
    <updated>2011-10-26T16:17:57Z</updated>
    <category term="cffi"/>
    <category term="lisp"/>
    <content type="html">&lt;p&gt;When interfacing with C, sometimes you want to know something which isn't provided in the shared object or DLL you're using (perhaps because it's tucked away in a C header file instead) and your options are: write a little C to get at that bit of info, or embed that information into your program and hope it doesn't change.  While the latter is certainly less complicated—and often good enough—, the former is the "proper" solution, for which CFFI-Grovel
provides an excellent start.&lt;/p&gt;

&lt;p&gt;But sometimes you want to do something CFFI-Grovel doesn't support.  Writing C yourself is an option, of course, but then you lose out on the help CFFI-Grovel provides getting C code to produce Lisp forms.  So instead, we'd like to tell CFFI-Grovel how to do things it doesn't currently do.&lt;/p&gt;

&lt;p&gt;Enter CFFI-GROVEL::DEFINE-GROVEL-SYNTAX.  It's an internal symbol, but given the terrible machinations we've done using CFFI internals already, this should hardly raise an eyebrow.&lt;/p&gt;

&lt;p&gt;D-G-S is sort of like DEFUN, except it only applies to forms in grovel files.  It takes three hopefully self-explanatory arguments: NAME, LAMBDA-LIST, and BODY.  Within the scope of body, it provides all the variables within LAMBDA-LIST, plus an additional variable CFFI-GROVEL::OUT which is an output stream to the C file being created.&lt;/p&gt;

&lt;p&gt;Let us suppose we would like to grovel the assorted values of a bitfield.  CFFI-Grovel does not currently provide support for this, so we must add it ourselves.  (A responsible Lisper would send a patch upstream for this particular example, but don't let that distract you from the ability to define other things which have no reason to go upstream.)&lt;/p&gt;

&lt;p&gt;First, let's figure out a syntax.  Something like:
&lt;pre&gt;&lt;code&gt;(bitfield (name &amp;amp;keyword base-type)
  &amp;amp;body (lisp-name c-name)+)&lt;/code&gt;&lt;/pre&gt;
suits my fancy, and has a nice parallel with the existing CENUM.  (In fact, most of the code is stolen from cenum.)&lt;/p&gt;

&lt;p&gt;In use, it might look something like this excerpt from burgled-batteries:
&lt;pre&gt;&lt;code&gt;(bitfield method-convention-flags
  (:positional-arguments "METH_VARARGS")
  (:keyword-arguments    "METH_KEYWORDS")
  (:mixed-arguments      "METH_KEYWORDS | METH_VARARGS")
  (:no-arguments         "METH_NOARGS")
  ...)&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;

&lt;p&gt;This nicely parallels the CFFI:DEFBITFIELD form which it generates, so it should be relatively easy to pick up the usage from one to the other.
&lt;pre&gt;&lt;code&gt;(cffi:defbitfield (method-convention-flags)
  (:positional-arguments #x00000001)
  (:keyword-arguments    #x00000002)
  (:mixed-arguments      #x00000003)
  (:no-arguments         #x00000004)
  ...)&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;

&lt;p&gt;So let's get cracking at making this thing work!&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(in-package #:cffi-grovel)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We should probably define our own package, but this is example code and all the symbols are internal to the cffi-grovel package anyway, so we'll cheat.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-grovel-syntax bitfield (name &amp;amp;body masks)
  (destructuring-bind (name &amp;amp;key base-type)
      (ensure-list name)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This gets us started.  The D-BIND gives us the option of passing (name :base-type some-type) as the name, for bitfields that are unusually large or small.  It parallels the same option in CENUM, and DEFBITFIELD.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    (c-section-header out "bitfield" name)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;C-SECTION-HEADER produces a comment in the C code.  While not strictly necessary, it can help you find your place when trying to debug the generated C.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    (c-export out name)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;C-EXPORT produces C code which produces Lisp code which exports the name of the bitfield.  (Modulo CFFI-GROVEL::*AUTO-EXPORT*, which defaults to NIL.)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    (c-format out "(cffi:defbitfield (")&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;C-FORMAT is a wrapper around CL:FORMAT which generates a string from the control-string and format arguments provided, then uses that string to produce an &lt;code&gt;fprintf&lt;/code&gt; form
in C which writes the string produced by FORMAT to the lisp file being generated.  In other words, this makes C code which writes the provided string to our generated lisp file.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    (c-print-symbol out name t)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;C-PRINT-SYMBOL, as you might guess, produces C code which writes out a Lisp symbol.  You may run into package issues if you're doing something particularly fancy in that department.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    (when base-type
      (c-printf out " ")
      (c-print-symbol out base-type t))
    (c-format out ")")&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I think you can figure this out.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    (dolist (mask masks)
      (destructuring-bind (lisp-name c-name)
          mask
        (check-type lisp-name symbol)
        (check-type c-name string)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Nothing fancy here.  Just some sanity checking.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        (c-format out "~%  (")
        (c-print-symbol out lisp-name)
        (c-format out " ")
        (c-printf out "#x%08x" c-name)
        (c-format out ")")))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As if functions in CFFI-GROVEL were named by some logical and consistent scheme, C-PRINTF produces C code which calls &lt;code&gt;fprintf&lt;/code&gt;.  Its arguments are a C printf string, and the names of C arguments to pass to &lt;code&gt;fprintf&lt;/code&gt;.  Though not strictly necessary, we produce a hexadecimal number and set the width of the output to emphasize the flaginess of the numbers in the resulting lisp file.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    (c-format out ")~%")))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Closing things off, and that's it.  A few lines of code, and we can now grovel bitfields.&lt;/p&gt;

&lt;p&gt;The functions and macros we've used here are defined, along with some others, in &lt;a href="http://common-lisp.net/gitweb?p=projects/cffi/cffi.git;a=blob;f=grovel/grovel.lisp;hb=HEAD" rel="nofollow"&gt;cffi/grovel/grovel.lisp&lt;/a&gt;.  While there isn't much in the way of docstrings, the code is straightforward, and reading more of it may help you better understand how to define your own grovel forms.&lt;/p&gt;

&lt;p&gt;Now go forth and grovel heretofore ungrovelled things!&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:40037</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/40037.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=40037"/>
    <title>CFFI Tricks: Mapping C Arguments to Lisp Return Values</title>
    <published>2011-10-17T19:11:04Z</published>
    <updated>2011-10-17T19:44:52Z</updated>
    <category term="cffi"/>
    <category term="lisp"/>
    <content type="html">&lt;p&gt;Unlike Lisp, C lacks the ability to return multiple values, and so some C functions take arguments which are used to return a value.  When dealing with such a C function, we'd really rather convert such things into something more Lispy, like a secondary return value, and not pass an argument to the function at all.&lt;/p&gt;

&lt;p&gt;In other words, given the C function:
&lt;pre&gt;&lt;code&gt;void function return_arg(int num, void * ret)&lt;/code&gt;&lt;/pre&gt;
We'd like to call it as:
&lt;pre&gt;&lt;code&gt;(return-arg num) ; =&amp;gt; ret&lt;/code&gt;&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;Clisp's native FFI can do this—they call it an :out argument.  But of course, being conscientious of other implementations, we'd prefer a solution using a portability layer like CFFI.  Unfortunately, CFFI doesn't have anything like Clisp's :out or :in-out arguments.&lt;/p&gt;

&lt;p&gt;That leaves us with three possible options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Write extra code for FFI functions which return values through the argument list&lt;/li&gt;
&lt;li&gt;Make library users write extra code to deal with return values in the argument list&lt;/li&gt;
&lt;li&gt;Write code to convince CFFI to handle it for us&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Being lazy, and not wanting to write essentially the same boilerplate multiple times, we'd like to avoid 1.  Being fans of clean APIs, we'd like to avoid 2.  Which leaves us with 3.&lt;/p&gt;

&lt;p&gt;Naturally, we'll need a name for our foreign-type wrappers. What Clisp calls :out, I think I'll call RETURN for what I hope is an obvious parallel.  What Clisp calls :in-out, I shall call PLACE.  (What we'll end up defining won't perform reassignment, so PLACE is not strictly accurate, but it'll work for now.)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-foreign-type output-arg (cffi::enhanced-foreign-type)
  ((real-type :initarg :real-type :reader real-type)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This just defines a base-type, so we can share code between the RETURN and PLACE foreign-types.  We give it a real-type slot, which differs from the actual-type slot from CFFI.  CFFI's actual-type slot will be set to :pointer, because a :pointer is how you pass data around in C.  real-type will cover the user-visible type translation.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(define-foreign-type return (output-arg) ()
  (:documentation "A RETURN foreign-type is like Clisp's :OUT."))
(define-parse-method return (real-type)
  (make-instance 'return :actual-type :pointer :real-type (parse-type real-type)))&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;(define-foreign-type place (output-arg) ()
  (:documentation "A PLACE foreign-type is like Clisp's :IN-OUT."))
(define-parse-method place (real-type)
  (make-instance 'place :actual-type :pointer :real-type (parse-type real-type)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And these are our foreign-types.&lt;/p&gt;

&lt;p&gt;To use them, we need to produce two things: a CFFI:DEFCFUN form with all the output-args as :pointers, and a DEFUN which wraps a call to that function to pass in appropriate pointers and do type translation on the values coming out.&lt;/p&gt;

&lt;p&gt;burgled-batteries has this functionality baked into DEFPYFUN—however, that comes with a lot of other baggage, so here's a more single-minded macro.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defmacro defcfun* (name return-type args)
  (multiple-value-bind (lisp-name foreign-name options)
      (cffi::parse-name-and-options name)
    (let* ((internal-lisp-name (symbolicate "%" lisp-name))
           (args (mapcar #'normalize-arg args))
           (*values-accumulator* (gensym "ACCUM"))
           (retval (gensym "RETVAL"))
           (lisp-args (mapcar #'first (remove-if-not #'include-in-argument-list-p args :key #'fourth))))
      `(progn
         (defcfun (,foreign-name ,internal-lisp-name ,@options)
             ,return-type
           ,@(mapcar (lambda (arg) (cl:list (first arg) (third arg))) args))
         (defun ,lisp-name ,lisp-args
           (let ((,*values-accumulator* (cl:list))
                 (,retval '#:you-should-never-see-this-value))
             ,(loop :for (value var actual-type parsed-type) :in (cons '(nil nil nil nil) (reverse args))
                    :for body = `(setf ,retval (,internal-lisp-name ,@(mapcar #'%choose-symbol args)))
                    :then (expand-to-foreign-dyn value var (cl:list body) parsed-type)
                    :finally (cl:return body))
             (push ,retval ,*values-accumulator*)
             (values-list ,*values-accumulator*)))))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To produce an appropriate DEFCFUN, we start with the lisp-name and add a "%" as is the usual convention for internal helper bits.  A gensym would work as well, but this provides something callable for debugging purposes or what-have-you.  The foreign-type of any output-arg argument is simply :pointer.  We'll deal with type translation of those arguments in our wrapper.&lt;/p&gt;

&lt;p&gt;The DEFUN is where the real fun happens: we have an accumulator, which accumulates the return values from both the C function, and the output arguments.  (Alas, no consideration is made for :void functions—for them, the first return value will always be useless.)&lt;/p&gt;

&lt;p&gt;That loop you see calls #'EXPAND-TO-FOREIGN-DYN, which is the most general manner in which CFFI handles the conversion of arguments (as contrasted with #'EXPAND-TO-FOREIGN and #'TRANSLATE-TO-FOREIGN).  We'll get to the implementation of E-T-F-D in a bit.  The loop might be a bit tricky—it's basically flattened out recursion—but I'm sure you can figure it out. &lt;tt&gt;:)&lt;/tt&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defun normalize-arg (arg)
  "Returns (list var gensym actual-type parsed-type)"
  (cond
    ((eq arg '&amp;amp;rest) arg)
    ((listp arg)
     (destructuring-bind (var type) arg
       (let ((parsed-type (parse-type type)))
         (cond
           ((typep parsed-type 'output-arg)
            (list var (gensym (symbol-name var)) :pointer parsed-type))
           (t
            (list var (gensym (symbol-name var)) type parsed-type))))))
    (t (error "oh noez!"))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;NORMALIZE-ARG is not particularly interesting.  Just calculates some necessary gensyms and parses types for us.&lt;/p&gt;

&lt;p&gt;The remaining magic is in E-T-F-D.  Except it's not really magical, it's pretty straightforward.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defmethod expand-to-foreign-dyn (value var body (type output-arg))
  (let* ((real-type (real-type type))
         (canonical-type (cffi::canonicalize real-type)))
    `(with-foreign-object (,var :pointer)
       ,@body
       (push ,(expand-from-foreign `(mem-ref ,var ,canonical-type) real-type) ,*values-accumulator*))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We make a pointer, run some code, and then add a translated copy of the value being pointed at to the list of values to be returned.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defmethod expand-to-foreign-dyn (value var body (type place))
  (let* ((real-type (real-type type))
         (canonical-type (cffi::canonicalize real-type)))
    (expand-to-foreign-dyn
     value var
     `(,(call-next-method var value `((setf (mem-ref ,value ,canonical-type) ,var) ,@body) type))
     real-type)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;PLACE types are only slightly more interesting.  First, we convert the Lisp value given into a foreign value.  Then, it's pretty much the same as for RETURN values, with the exception of pointing our pointer at the foreign value we just made.&lt;/p&gt;

&lt;p&gt;Also note that we end up swapping VALUE and VAR for the pointer.  This is because the gensymed symbol is already in use for the converted foreign value.  (A second gensym may have been preferable, but this should be safe.)&lt;/p&gt;

&lt;p&gt;%CHOOSE-SYMBOL takes this into account, for when we generate the call to CFFI's C function wrapper.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defun %choose-symbol (arg)
  (typecase (fourth arg)
    (return (second arg))
    (place (first arg))
    (t (second arg))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And that's pretty much it.  (If I left anything out, you can find it in &lt;a href="http://repo.kepibu.org/burgled-batteries/cffi-output-args.lisp" rel="nofollow"&gt;cffi-output-args.lisp&lt;/a&gt; from burgled-batteries.)  After that
&lt;pre&gt;&lt;code&gt;(defcfun* "foo" :void ((a :int) (b (return :boolean)) (c (place :boolean))))&lt;/code&gt;&lt;/pre&gt;
Gives us a function #'FOO, with arguments A and C, which returns (values nil B C).&lt;/p&gt;

&lt;p&gt;An arguably better implementation would either have it return (values B C), or have it return (values B) and modify C (the latter necessitating a macro, of course).  I'll leave those as exercises for the reader.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:39882</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/39882.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=39882"/>
    <title>CFFI Tricks: Creating a Lisp Version of a Missing C Function</title>
    <published>2011-10-13T14:17:05Z</published>
    <updated>2011-10-17T19:44:35Z</updated>
    <category term="cffi"/>
    <category term="burgled-batteries"/>
    <category term="lisp"/>
    <content type="html">&lt;p&gt;Working on burgled-batteries, I found that a non-trivial portion of Python's C API isn't actually exported functions, but preprocessor macros disguised as functions.  In the interests of continuing to work if they go back and forth on any given function, I thought it would be a good idea to automatically detect if the function exists, and use an alternative Lisp implementation if it didn't.&lt;/p&gt;

&lt;p&gt;Now, the thing about replacing C code with Lisp code is that I want the Lisp code to run as if it were C.  In other words, for all of the type-translation of CFFI to have already occurred by the time the Lisp code has been called, and to also occur on the return value.  CFFI, naturally, does not anticipate this use-case.  Fortunately, Lisp is not a bondage-and-discipline language; also fortunately, CFFI's internals are perfectly aligned for this particular, ah, "creative restructuring".&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(let* ((realfn (symbol-function 'cffi::defcfun-helper-forms))
       (lisp-args ...)
       (alt-body ...)
       (ourfn (make-defpyfun-helper-forms lisp-args alt-body decl))
       (doc+decl ...))
  ;; We temporarily replace cffi::defcfun-helper-forms and call
  ;; cffi::%defcfun to create the defun so we can ensure the body
  ;; of our alternate function runs having been given pointers as
  ;; if it were C.
  (unwind-protect
       (progn
         (setf (symbol-function 'cffi::defcfun-helper-forms) ourfn)
         (cffi::%defcfun lisp-name c-name return-type c-args nil doc+decl))
    (setf (symbol-function 'cffi::defcfun-helper-forms) realfn)))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you're not familiar with CFFI's internals, #'cffi::%defcfun is the function which produces the macroexpansion for DEFCFUN.  Quite handy that it was already split out for us to call.  #'cffi::defcfun-helper-forms is the function #'%defcfun uses to determine what form to use to
call a C function.  Fate smiles upon us: #'%defcfun produces the type translation code, and wraps it around the form returned by #'defcfun-helper-forms.  Since we want to run code in place of calling a C function, all we have to do is get D-H-F to spit out the code we want to run.&lt;/p&gt;

&lt;p&gt;So we replace D-H-F with a call to our own function (produced by #'make-defpyfun-helper-forms) and let #'%defcfun do its thing none the wiser.&lt;/p&gt;

&lt;p&gt;#'make-defpyfun-helper-forms isn't particularly complicated.  It binds the gensym'd variables from CFFI back into the user-provided variables, and includes any relevant user-specified declarations.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defun make-defpyfun-helper-forms (wrapped-args wrapped-forms declarations)
  "When called, produces a function which is intended to take the place of
#'CFFI::DEFCFUN-HELPER-FORMS within a CFFI:DEFCFUN expansion.  This is used when
creating an alternate definition for a C function which either doesn't exist in
the currently-included Python library (e.g., because it belongs to a newer
version of Python, or because it's really a preprocessor macro)."
  (lambda (name lisp-name rettype args types options)
    (declare (ignore name lisp-name rettype types options))
    (values '()
            `(let ,(mapcar #'cl:list wrapped-args args)
               ,@(%filter-declarations declarations :for wrapped-args)
               ,@wrapped-forms))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It's somewhat awkward to write C-equivalent code within Lisp; largely because it's necessary to keep in mind that the return value must &lt;em&gt;also&lt;/em&gt; be a C value (e.g., 1 and 0 for true and false, rather than t and nil).  But it also means library users have less to worry about, because some of the minor differences between Python versions can be papered over.&lt;/p&gt;

&lt;p&gt;Lots of scary internal machinations allow us to provide a (hopefully) straightforward interface to create Lisp-side reimplementations of C code:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defcvar ("Py_Py3kWarningFlag" *err.warn-py3k* :read-only T) :boolean)
(defpyfun "PyErr_WarnPy3k" 0-on-success ((message :string) (stacklevel :int))
  (:implementation
   (if *err.warn-py3k* (err.warn-ex +exc.deprecation-warning+ message stacklevel) 0)))
...
(defpyfun "PyErr_NewExceptionWithDoc" object ((name :string) (doc :string) (base object) (dict dict))
  (:implementation
   (declare (ignore doc))
   (err.new-exception* name base dict)))&lt;/code&gt;&lt;/pre&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:39435</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/39435.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=39435"/>
    <title>Preview: Burgled-Batteries, Yet Another Python-Lisp Bridge</title>
    <published>2011-09-27T09:52:06Z</published>
    <updated>2011-11-05T06:41:03Z</updated>
    <category term="python"/>
    <category term="programming"/>
    <category term="lisp"/>
    <content type="html">&lt;blockquote style="white-space: pre;"&gt;&lt;code&gt;(push :burgled-batteries.guess-not-grovel *features*)&lt;/code&gt; ; optional; avoids the groveller
&lt;code&gt;(asdf:load-system "burgled-batteries")
(in-package #:burgled-batteries)
(run "1+1")&lt;/code&gt; ; ⇒ 2
&lt;code&gt;(run "[1, 2, 3]")&lt;/code&gt; ; ⇒ #(1 2 3)
&lt;code&gt;(run "(1, 2, 3)")&lt;/code&gt; ; ⇒ (1 2 3)
&lt;code&gt;(run "dict(a=1, b=2, c=3)")&lt;/code&gt; ; ⇒ #&amp;lt;HASH-TABLE&amp;gt;
&lt;code&gt;(alexandria:hash-table-alist *)&lt;/code&gt;
 ; ⇒ (("b" . 2) ("c" . 3) ("a" . 1))

&lt;code&gt;(import "feedparser")
(defpyfun "feedparser.parse" (url))
(documentation 'feedparser.parse 'function)&lt;/code&gt;
; ⇒ "Parse a feed from a URL, file, stream, or string"
&lt;code&gt;(feedparser.parse "http://pinterface.livejournal.com/data/atom")&lt;/code&gt;
 ; ⇒ #&amp;lt;HASH-TABLE&amp;gt;
&lt;code&gt;(gethash "title" (first (gethash "entries" *)))&lt;/code&gt;
 ; ⇒ "Preview: Burgled-Batteries, Yet Another Python-Lisp Bridge"
&lt;/blockquote&gt;

&lt;p&gt;To answer the most obvious question: CL-Python seems to require more resources than I can give it, Python-on-Lisp is incomplete and poorly integrated (also: I'll probably steal code from it), and pyffi is ... what I started from.  If you count Python-on-Lisp-ex, this is the &lt;em&gt;fifth&lt;/em&gt; Lisp/Python mashup I know about.  Hopefully, it will be the last. &lt;tt&gt;;)&lt;/tt&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Edit Oct. 11, 2011:&lt;/b&gt; Lots more to do yet, but if anybody is interested in throwing things at it, `&lt;code&gt;darcs get http://repo.kepibu.org/burgled-batteries/&lt;/code&gt;`.  Feel free to e-mail me directly, or ping the &lt;a href="http://lists.kepibu.org/listinfo/burgled-batteries" rel="nofollow"&gt;mailing list&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:39229</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/39229.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=39229"/>
    <title>Parsing robots.txt Files with Common Lisp</title>
    <published>2011-08-31T07:51:50Z</published>
    <updated>2011-09-01T04:34:43Z</updated>
    <category term="web scraping"/>
    <category term="robots.txt"/>
    <category term="lisp"/>
    <content type="html">&lt;p&gt;Do you use Common Lisp?  Do you scrape web pages, and need to deal with the robots.txt file to play nicely?&lt;/p&gt;

&lt;p&gt;Well have I got a deal for you!  For the low, low price of &lt;em&gt;absolutely&lt;/em&gt; &lt;strong&gt;free&lt;/strong&gt; you too can parse robots.txt files with my Common Lisp library &lt;a href="http://web.kepibu.org/code/lisp/machina-policy/" rel="nofollow"&gt;machina-policy&lt;/a&gt;&lt;sup&gt;1&lt;/sup&gt;.  See the &lt;a href="http://web.kepibu.org/code/lisp/machina-policy/readme.html" rel="nofollow"&gt;readme&lt;/a&gt; for a brief overview.&lt;/p&gt;

&lt;p&gt;Don't forget to &lt;a href="http://lists.kepibu.org/listinfo/machina-policy" rel="nofollow"&gt;join the mailing list&lt;/a&gt; to offer ideas, submit bugs, and make requests for improvement.&lt;/p&gt;

&lt;p&gt;For more web-scraping fun, you might try some libraries with which I am completely unaffiliated and haven't yet tried: &lt;a href="http://www.cliki.net/cl-web-crawler" rel="nofollow"&gt;cl-web-crawler&lt;/a&gt;, &lt;a href="http://www.cliki.net/cl-kappa" rel="nofollow"&gt;cl-kappa&lt;/a&gt;, and &lt;a href="http://www.cliki.net/CSS-Selectors" rel="nofollow"&gt;css-selectors&lt;/a&gt;; or my own &lt;a href="http://web.kepibu.org/code/lisp/Oh,%20Ducks!/" rel="nofollow"&gt;Oh, Ducks!&lt;/a&gt;.&lt;/p&gt;

&lt;ol style="font-size: smaller;"&gt;&lt;li&gt;&lt;tt&gt;machina-policy&lt;/tt&gt; was very briefly named &lt;tt&gt;robots.txt&lt;/tt&gt;.  How &lt;em&gt;not&lt;/em&gt; to name a library, ladies and gentlemen.&lt;/li&gt;&lt;/ol&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:38928</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/38928.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=38928"/>
    <title>kepibu.org: Now with Project Mailing Lists!</title>
    <published>2011-08-21T02:46:32Z</published>
    <updated>2011-08-21T02:46:32Z</updated>
    <category term="mailing lists"/>
    <category term="lisp"/>
    <content type="html">&lt;p&gt;As you may be aware, because it's primarily what I post about, I host a small number of libraries on my personal site.  In the unlikely event you are interested in any of those libraries, &lt;a href="http://lists.kepibu.org/" rel="nofollow"&gt;most of them now have mailing lists&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Well, in theory.  I'm pretty new at administering mailman, and it's entirely possible I missed something or other.&lt;/p&gt;

&lt;p&gt;I hate mailing lists, actually—netnews is a much better interface—but an NNTP server is a bit harder to set up, so that's on the "FUTURE" list for now.&lt;/p&gt;

&lt;p&gt;I expect the combined traffic of all the lists to be pretty low: over the past several years, I have received two e-mails &lt;em&gt;total&lt;/em&gt; about the small number of libraries I maintain.&lt;/p&gt;

&lt;p&gt;Anyway, now you can publicly berate me and my code, amongst an audience of similarly-interested parties.  No longer must you withhold your lamentations merely because nobody else could applaud you!&lt;/p&gt;

&lt;p&gt;Compliments and questions are okay, too. &lt;tt&gt;;)&lt;/tt&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:pinterface:38715</id>
    <link rel="alternate" type="text/html" href="http://pinterface.livejournal.com/38715.html"/>
    <link rel="self" type="text/xml" href="http://pinterface.livejournal.com/data/atom/?itemid=38715"/>
    <title>Finding the Cause: Hunting Down a Spike in IO Usage</title>
    <published>2011-08-11T05:24:11Z</published>
    <updated>2011-08-11T05:24:11Z</updated>
    <category term="apache"/>
    <category term="work"/>
    <category term="sysadmin"/>
    <category term="webservers"/>
    <content type="html">&lt;p&gt;A little over a week ago, my VPS started a significant jump in IO usage.  This had cascading effects, spiking context switches and interrupts, load average, and a very unwelcome pinching of memory availability.  (I noticed these other things first, actually—it wasn't until I hit the IO graph that I figured out how I could track down the problem.)&lt;/p&gt;

&lt;p&gt;A little iotop and some luck on timing, and I discovered the culprit: htcacheclean.  In other words, the periodic drop in performance was caused by mod_disk_cache, something I implemented to &lt;em&gt;improve&lt;/em&gt; performance.  Vexing!&lt;/p&gt;

&lt;p&gt;So I did some investigating into what exactly my caching solution was doing.&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;cd /var/cache/apache2/mod_disk_cache/&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;I started by seeing how many files it was caching.&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;find . -name '*.data' -print | wc -l&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Over 5000 files.  By very rough count, I have ~170 pages, which I expect to be cached four times each (ASCII or UTF-8, compressed or not-compressed).  That's a little over 7 times as many files as I'd expect.  Clearly, something is amiss.&lt;/p&gt;

&lt;p&gt;First, I suspected the problem was duplication.  Maybe the same things are getting cached multiple times.&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;find . -name '*.data' -exec sha1sum {} + | \
  awk '{print $1}' | sort | uniq -c | awk '{print $1}' | \
  sort | uniq -c | sort&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Provides me with a listing of how many pages share the same sha1sum, sorted by duplicates.  4310 files have unique sha1s, 30 sha1s are shared across five or more files.  So duplication is clearly not worth worrying about right now.&lt;/p&gt;

&lt;p&gt;Next, I checked the pages being cached.&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;find . -name '*.header' -exec \
 grep -hosaE '([a-z0-9.-]+:80/[^?]*)' {} + | \
 sort | uniq -c | sort&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Most pages are cached once.  Several dozen are cached up to 37 times.  That's excessive, but here's the real shocker: two pages are cached several thousand times each (one 1300 times, another 3600).&lt;/p&gt;

&lt;p&gt;What's so special about these pages?  Query arguments.  Search boxes.  In other words, I probably shouldn't be caching them anyway, because they're only going to be seen once.&lt;/p&gt;

&lt;p&gt;So I stopped.&lt;/p&gt;

&lt;p&gt;I then turned my eye to another site on the same server, that happens to implement its own caching layer, and turned off mod_disk_cache for that site.  Testing before and after revealed: mod_disk_cache made no statistical difference in
speed for that site.  So it can stay disabled.&lt;/p&gt;

&lt;p&gt;I also disabled it for some smaller, very low-traffic sites I host, because it was essentially irrelevant for those sites.  Leaving only one site still using mod_disk_cache.&lt;/p&gt;

&lt;p&gt;One site remaining, I started checking if that site really needed it.  Inside the application's internal caching layer, I noticed a comment mentioning that mod_cache fails to cache URLs ending in "/" (in other words, anywhere DirectoryIndex applies).  Man, I had forgotten about that!  A little URL checking confirms: yup, not caching those pages.  Those pages, as it happen, are roughly every page I care about being really fast, which means mod_cache isn't caching
anything I value.  Turning it off and testing again reveals... well, it isn't slowing anything down by being in the middle, but it also isn't making things faster.&lt;/p&gt;

&lt;p&gt;So no more mod_cache.  For me at least, it just isn't worthwhile.  And that means no more htcacheclean, which means my I/O can return to its nice, normal, near-zero level.  As can everything else affected by htcacheclean's periodic runs.&lt;/p&gt;

&lt;p&gt;That's one fewer thing running on my server.  And a lesson learned: if you've &lt;a href="http://pinterface.livejournal.com/37050.html#oubcom-speedup-section-6" rel="nofollow"&gt;already noted something doesn't help performance&lt;/a&gt;, disable the things that don't help so they don't later make it worse.  Whoops!&lt;/p&gt;</content>
  </entry>
</feed>
