<?xml version="1.0" encoding="UTF-8" ?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc=" http://purl.org/dc/elements/1.1/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>briancarper.net (λ)</title><link>http://briancarper.net</link><description>Some guy's blog about programming and Linux and cows.</description><item><title>Vim: Find lines longer than current line</title><link>http://briancarper.net/blog/592/vim-find-lines-longer-than-current-line</link><guid>http://briancarper.net/blog/592/vim-find-lines-longer-than-current-line</guid><pubDate>Thu, 21 Jun 2012 10:29:14 -0700</pubDate><description>&lt;p&gt;Vim isn't just for editing source code.  It's also a pretty good data editor.  &lt;/p&gt;

&lt;p&gt;Sometimes I'm editing dirty fixed-width data files, and some lines are incorrectly a bit too long because one or two fields overflowed.  It's easy to search for lines that are too long, once you know how long lines should be.  Say your lines should be 1000 characters; search like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/^.\{1001}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now all the longer lines are highlighted (assuming &lt;code&gt;:set hls&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;That's tedious to type though.  Put your cursor on a non-overflowing line and call this function, and Vim will find all the lines that are too long, and move you to the first one:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function! FindLongerLines()
    let @/ = '^.\{' . col('$') . '}'
    silent! norm n$
endfunction
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That mess about manually setting &lt;code&gt;@/&lt;/code&gt; is because of this somewhat unfortunate fact (from &lt;code&gt;:help :function&lt;/code&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        The last used search pattern and the redo command &quot;.&quot;
        will not be changed by the function.  This also
        implies that the effect of |:nohlsearch| is undone
        when the function returns.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That is, using something like &lt;code&gt;norm /&lt;/code&gt; inside functions doesn't affect the last-remembered search once the function returns, but that's exactly what we want to happen.&lt;/p&gt;</description></item><item><title>Happy Day Against DRM</title><link>http://briancarper.net/blog/591/happy-day-against-drm</link><guid>http://briancarper.net/blog/591/happy-day-against-drm</guid><pubDate>Fri, 04 May 2012 13:23:52 -0700</pubDate><description>&lt;p&gt;Books are &lt;a href=&quot;http://oreil.ly/Against-DRM&quot;&gt;50% off at O'Reilly&lt;/a&gt; today, using code &lt;code&gt;DRMFREE&lt;/code&gt;.  (This includes my book, &lt;a href=&quot;http://shop.oreilly.com/product/0636920013754.do?code=DRMFREE&quot;&gt;Clojure Programming&lt;/a&gt;, by the way...)  I'm a bit late with this, given the offer expires in 9 hours, but there's still time.&lt;/p&gt;

&lt;p&gt;Whether you want to buy books today or not, it's worth pointing out that today is &lt;a href=&quot;http://www.defectivebydesign.org/dayagainstdrm/&quot;&gt;International Day Against DRM&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.defectivebydesign.org/dayagainstdrm/&quot;&gt;&lt;img src=&quot;/random/day-against-drm.png&quot; alt=&quot;Day Against DRM&quot; title=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;!--more Let's talk brand loyalty and DRM --&gt;

&lt;h1&gt;Brand Loyalty.  Step 1: Make good stuff.&lt;/h1&gt;

&lt;p&gt;My anti-DRM article is quickly going to turn into a pro-O'Reilly Media infomercial, so you've been warned.&lt;/p&gt;

&lt;p&gt;I am not the kind of person to feel any kind of brand loyalty.  I'm the kind of person who deliberately buys a different brand of peanut butter every time I go to the grocery store, to try to screw with the store's customer-tracking database.&lt;/p&gt;

&lt;p&gt;O'Reilly is probably an exception.  I like O'Reilly.  Why is that?&lt;/p&gt;

&lt;p&gt;First, O'Reilly books tend to be pretty good.  At least, I have yet to buy one that wasn't pretty good.&lt;/p&gt;

&lt;p&gt;Allow me to digress.  My college's CS curriculum was based around C++.  Now, I'm the kind of person who thinks that programming is vaguely enjoyable no matter what I'm doing.  Computers are fun.  But for a new programmer, coding in C++ is like an hours-long shouting match with the compiler where your goal is to try to get the compiler errors to shut up.  Producing a working program is an occasional side-effect.  C++ doesn't exactly promote explorative, imaginative programming.&lt;/p&gt;

&lt;p&gt;The first class I had in college where I actually &lt;em&gt;enjoyed&lt;/em&gt; programming was a class that taught Perl.  My textbook was &lt;em&gt;Learning Perl&lt;/em&gt;, aka the Llama Book&lt;sup id=&quot;fnref:nicknames&quot;&gt;&lt;a href=&quot;#fn:nicknames&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.  What a good book.  I still have it.  I remember feeling like I learned more reading that book that I had in two years of slogging through C++ data structures.  And what fun Perl was.  &lt;em&gt;&lt;Insert some nerdy analogy between programming and wizardry here.&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I remember immediately spending a bunch of money I should've saved for food, and getting &lt;em&gt;Programming Perl&lt;/em&gt;, aka the Camel Book&lt;sup id=&quot;fnref:nicknames&quot;&gt;&lt;a href=&quot;#fn:nicknames&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.  So good!  Who knew a book could be witty and fun, and teach you things at the same time.  You can tell when a book is written by someone who knows their stuff, and who enjoys talking about their craft.&lt;/p&gt;

&lt;p&gt;Not sure if it was Perl itself, or the great Perl books, or probably some combination.  But I've been cemented in dynamic, vaguely-Perly, powerful and fun languages since then.  First Ruby, then Clojure.&lt;/p&gt;

&lt;p&gt;I'm also likely to buy an O'Reilly book, given a choice between alternatives.&lt;/p&gt;

&lt;h1&gt;Step 2: Be Humans and give a crap.&lt;/h1&gt;

&lt;p&gt;A second thing that creates brand loyalty is when a company seems to be made of human beings that you can relate to.&lt;/p&gt;

&lt;p&gt;When I heard O'Reilly was writing a Lisp book, and what's more, it was a Clojure book, and what's more,  I could be involved in writing it... I was pretty excited.  &lt;/p&gt;

&lt;p&gt;Our book was written in ASCIIDOC, and lived in an SVN repo hosted at O'Reilly.&lt;sup id=&quot;fnref:gitisbetter&quot;&gt;&lt;a href=&quot;#fn:gitisbetter&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;  We could upload code with a certain string in the SVN commit log, and that'd trigger a rebuild of the ASCIIDOC on O'Reilly's server, which was compiled into PDF, and then we could download the PDF from SVN to see how the final product would look.  Turnaround time was about 10 minutes.  It was a nice, programmer-friendly setup, to be sure.&lt;/p&gt;

&lt;p&gt;Whenever I dealt with people at O'Reilly, I generally got the feeling that I was working with programmers, or people who cared about programming.  There aren't a lot of Clojure gurus there, but there were people who knew why wrapping long lines of could needed to be handled &lt;em&gt;just right&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;It's a great feeling to work with people whose goal is advancing the craft, as opposed to some kind of Death-Star-like entity whose goal is wringing extra pennies out of customers' bones.&lt;/p&gt;

&lt;h1&gt;DRM sucks&lt;/h1&gt;

&lt;p&gt;So does O'Reilly actually give a crap?  Well, fiiiiiiiiinally getting to the point: O'Reilly's stance on DRM is pretty much spot-on.  O'Reilly books are sold without DRM.  DRM is not the way to make good stuff.  DRM is a good sign that you don't give a crap. DRM doesn't advance the craft, but rather does the opposite.&lt;/p&gt;

&lt;p&gt;I leant a guy my copy of K%R a while back.  Now there's one more person in the world with a bit more knowledge of C.  This is a really good thing.  If my copy of K&amp;amp;R was a DRMed ebook that I couldn't lend out, the world would be a tangibly worse place.&lt;/p&gt;

&lt;p&gt;I highly recommend &lt;a href=&quot;http://radar.oreilly.com/2012/05/drm-free-day-forever.html&quot;&gt;this article&lt;/a&gt; by Mike Hendrickson at O'Reilly where he talks about piracy, DRM, and making books.  Also &lt;a href=&quot;http://radar.oreilly.com/2006/08/piracy-is-progressive-taxation.html&quot;&gt;this one&lt;/a&gt; by Tim O'Reilly where he talks about the same.&lt;/p&gt;

&lt;p&gt;Now that my name is on a book, have my opinions about DRM changed?   Not really.  I'd obviously prefer that people pay for my book.  I pay for books.  It's only fair.&lt;/p&gt;

&lt;p&gt;At the same time, I would be really disappointed if my book was sold with DRM all over it, and I'm glad it isn't.&lt;/p&gt;

&lt;p&gt;Treating your customers like thieves &lt;em&gt;a priori&lt;/em&gt; is not the way to build brand loyalty.  Thinking that DRM is going to stop anyone from pirating a book is pretty much delusional.  Using DRM to maintain some kind of iron-fisted control over stuff you're selling to other people is morally sketchy.&lt;/p&gt;

&lt;p&gt;DRM is not the way to advance the craft.  Advancing the craft is the important thing.&lt;/p&gt;

&lt;p&gt;When you make smart decisions like not selling DRMed books, the result could be dorks like me spending an hour or two unprovoked, writing an article about how good your company is.  And yeah, this is surely a bit self-serving because I want to sell my book, but I'd have written this same article two years ago too.&lt;/p&gt;&lt;div class=&quot;footnotes&quot;&gt;&lt;ol&gt;&lt;li id=&quot;fn:nicknames&quot;&gt;&lt;p&gt;One way to tell a good book is if it's widely known by an affectionate nickname or acronym.  K&amp;amp;R?  TAOCP?  SICP?  The Camel Book?  You probably know what I mean right away. &lt;a rev=&quot;footnote&quot; href=&quot;#fnref:nicknames&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li id=&quot;fn:gitisbetter&quot;&gt;&lt;p&gt;Obviously I'd have preferred Git, but I'll take what I can get. &lt;a rev=&quot;footnote&quot; href=&quot;#fnref:gitisbetter&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item><item><title>cursorcolumn / cursorline slowdown</title><link>http://briancarper.net/blog/590/cursorcolumn--cursorline-slowdown</link><guid>http://briancarper.net/blog/590/cursorcolumn--cursorline-slowdown</guid><pubDate>Mon, 30 Apr 2012 15:48:25 -0700</pubDate><description>&lt;p&gt;The &lt;code&gt;cursorcol&lt;/code&gt; and &lt;code&gt;cursorline&lt;/code&gt; options in Vim are great.  Enabling them, and setting up your syntax highlighting correctly, will highlight the line and column that contains the cursor, drawing a sort of &quot;crosshairs&quot;, to let you find the cursor easily.&lt;/p&gt;

&lt;p&gt;This is especially useful when editing non-sourcecode files, like giant fixed-with data files.  Or when you need to keep switching your attention back and forth from Vim to something else; the visual cue to draw your eyes back to the cursor can be useful to prevent a mental page fault.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/vim/cursor-crosshairs.png&quot; alt=&quot;Cursor crosshairs&quot; title=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Great.  However, the help info for &lt;code&gt;cursorcolumn&lt;/code&gt; says this, in part:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    Highlight the screen column of the cursor with CursorColumn
    |hl-CursorColumn|.  Useful to align text.  Will make screen redrawing
    slower.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&quot;Will make screen redrawing slower&quot; is an understatement, unfortunately.  Over the past who-knows-how-long, I've noticed Vim slowing to a crawl when editing certain files, mostly big Ruby files.  Moving the cursor around or scrolling the window became pretty painful.  I could never quite figure out why, but today I got sick of it, and eventually found &lt;a href=&quot;http://vim.1045645.n5.nabble.com/Vim-7-slows-down-when-highlighting-cursor-line-td1148280.html&quot;&gt;an old message on the Vim mailing list&lt;/a&gt; explaining the problem.  &lt;/p&gt;

&lt;p&gt;Apparently when you have &lt;code&gt;cursorcolumn&lt;/code&gt; or &lt;code&gt;cursorline&lt;/code&gt; enabled, the whole screen is redrawn every time you move the cursor.  That explains a lot.  When I disabled these options, editing complex Ruby files once again achieved notepad.exe-level speed.&lt;/p&gt;

&lt;p&gt;I guess there's this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function! CursorPing()
    set cursorline cursorcolumn
    redraw
    sleep 50m
    set nocursorline nocursorcolumn
endfunction

nmap &amp;lt;C-Space&amp;gt; :call CursorPing()&amp;lt;CR&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will flash the cursor crosshairs for 50 milliseconds when I hit &lt;code&gt;CTRL+Space&lt;/code&gt; in normal mode.  Better than nothing.&lt;/p&gt;</description></item><item><title>Split page vertically in CSS (minus pixels)</title><link>http://briancarper.net/blog/589/split-page-vertically-in-css-minus-pixels</link><guid>http://briancarper.net/blog/589/split-page-vertically-in-css-minus-pixels</guid><pubDate>Mon, 23 Apr 2012 21:43:06 -0700</pubDate><description>&lt;p&gt;I was designing an online database application recently.  The layout I wanted was, I thought, fairly simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;N pixel header at the top&lt;/li&gt;
&lt;li&gt;The rest of the page split vertically into two panes&lt;/li&gt;
&lt;li&gt;Each pane should scroll independently&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Super easy to do in CSS, right?  Of course not!  You can't do this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: css&quot;&gt;#header {  height: 50px; }

#panels {  height: 100% - 50px; }

#top, #bottom { overflow: auto; }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is because (of course) you can't do simple arithmetic in CSS. &lt;/p&gt;

&lt;p&gt;I can't think of a reason why it's not supported.  My browser knows the height of the window at any given point in time.  The browser can surely subtract two numbers.  If someone knows of a solid reason why we can't do this in CSS, please clue me in.&lt;/p&gt;

&lt;p&gt;I can think of many reasons why I would want to do it though.  The above use case is just one of them.&lt;/p&gt;

&lt;p&gt;I really dislike resorting to this (which does work, as seen &lt;a href=&quot;/random/layout-good.html&quot;&gt;here&lt;/a&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: css&quot;&gt;#header {  height: 50px; }

#panels {
    position: absolute;
    top: 50px;
    left: 0px;
    right: 0px;
    bottom: 0px;
}

#top, #bottom { overflow: auto; }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Whenever I start using absolute positioning, I know something went off the rails somewhere.&lt;/p&gt;

&lt;p&gt;The worst part isn't that CSS doesn't support this, it's that even if CSS did suddenly support it, I couldn't use it until sometime in 2023 when all the major browsers implemented it and everyone using the old browsers switched or died of old age.&lt;/p&gt;</description></item><item><title>I don't have cancer</title><link>http://briancarper.net/blog/587/i-dont-have-cancer</link><guid>http://briancarper.net/blog/587/i-dont-have-cancer</guid><pubDate>Wed, 04 Apr 2012 14:29:58 -0700</pubDate><description>&lt;p&gt;2011 was an interesting year.  A year of firsts!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I worked on my first book, &lt;a href=&quot;http://www.clojurebook.com/&quot;&gt;Clojure Programming&lt;/a&gt; (soon to be released, in fine bookstores near you).&lt;/li&gt;
&lt;li&gt;I bought my first house.&lt;/li&gt;
&lt;li&gt;The first of my maternal grandparents died.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hmm, kind of took a turn for the worst there.  Then, one fine sunny day in 2011, sitting at my favorite pub, enjoying my favorite beer, I started coughing up blood.  Another first!&lt;/p&gt;

&lt;!--more Read on. --&gt;

&lt;p&gt;More firsts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First Emergency Room visit.&lt;/li&gt;
&lt;li&gt;First bronchoscopy.&lt;/li&gt;
&lt;li&gt;First CT scan.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Coughing up blood&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; is caused by a huge number of things, from nose bleeds to lung cancer to food going down the wrong pipe to cocaine use.  It turns out that 30-year-old non-smokers with no other symptoms tend not to have lung cancer.  That didn't stop me from fearing the worst.&lt;/p&gt;

&lt;h1&gt;Canadian Health Care&lt;/h1&gt;

&lt;p&gt;This was my first chance to experience the Canadian health care system first-hand after immigrating here.  &quot;Free health care&quot; is not entirely accurate, but is very close.  I pay some small amount of money monthly ($30-40 I think) to be included in the government-provided Medical Services Plan (MSP).  Many employers pay this fee for their employees, but mine doesn't.  No big deal.&lt;/p&gt;

&lt;p&gt;Once in this system, every &quot;essential&quot; form of health care is paid for completely by the government.  Emergency room visit, bronchoscopy, blood test, x-ray, visit with my family doctor, visit with my pulmonologist, all of it was 100% paid for.  Show them a government &quot;Care Card&quot; and you're set.&lt;/p&gt;

&lt;p&gt;Prescriptions are not covered.  Things like eyeglasses, non-emergency dentistry, and elective procedures are not covered.  I can get private health insurance to pay for some of those things, but I never bothered, because the cost of that stuff is so low.&lt;/p&gt;

&lt;p&gt;I'd hesitantly call this a step up from the US system of huge numbers of people being uninsured, and of insurance not actually covering all of your medical expenses even if you have it.&lt;/p&gt;

&lt;p&gt;The one bad thing about Canadian health care is the wait times.  It's often a month or longer to get an appointment to see my pulmonologist.  I'm currently scheduled for another medical test... in &lt;em&gt;June&lt;/em&gt;.  This was scheduled about 4 weeks ago.  Thank God I didn't have cancer, or I'd probably have been dead before I got to see a doctor.&lt;/p&gt;

&lt;p&gt;I never went through a similar experience in the US, so I'm not sure what the wait times are like in comparison.  I do remember my father waiting for over a month (in severe pain) to have a surgery performed because his insurance company dragged their feet in approving it, or something like that.  So yeah.  I probably can't complain much.&lt;/p&gt;

&lt;h1&gt;Now what?&lt;/h1&gt;

&lt;p&gt;After months of waiting and months of not knowing, and then having a few cameras shoved into my lungs, it turns out I probably don't have cancer.  So that's pretty good news.  I still don't know what's causing me to sporadically cough up blood, but as more and more &quot;serious&quot; things are ruled out by tests, I find myself in much better spirits.&lt;/p&gt;

&lt;p&gt;2011 will go down in my biography&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; in as the Year of Lost Productivity.  I didn't handle the stress very well, to put it very mildly.  It's unfortunate that the act of worrying about dying and not having time to do things I want to do ended up hindering me from doing many things I wanted to do.&lt;/p&gt;

&lt;p&gt;I sometimes hear about people who actually have terminal illness showing bravery in the face of their illness.  By contrast, it didn't even take terminal illness to essentially blow me out of the water.  Just the real threat of it.  I feel a lot of shame and regret at how poorly I handled myself.  I'm trying to use that regret as motivation.  I have a lot of things I need to accomplish, and who knows, maybe not as much time to accomplish them as I'd like to imagine.&lt;/p&gt;

&lt;p&gt;So I have a lot of plans for this year.  Old projects need to be dusted off and brought up to speed.  Step one is probably kicking some life back into this old blog.&lt;/p&gt;&lt;div class=&quot;footnotes&quot;&gt;&lt;ol&gt;&lt;li id=&quot;fn:2&quot;&gt;&lt;p&gt;Hemoptysis.  From Greek &lt;em&gt;hemo&lt;/em&gt; (blood) + &lt;em&gt;ptýsis&lt;/em&gt; (spitting).  A word I'm now intimately familiar with. &lt;a rev=&quot;footnote&quot; href=&quot;#fnref:2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li id=&quot;fn:1&quot;&gt;&lt;p&gt;I'm not actually writing a biography. &lt;a rev=&quot;footnote&quot; href=&quot;#fnref:1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item><item><title>Shuffle lines in Vim</title><link>http://briancarper.net/blog/580/shuffle-lines-in-vim</link><guid>http://briancarper.net/blog/580/shuffle-lines-in-vim</guid><pubDate>Thu, 07 Jul 2011 14:07:41 -0700</pubDate><description>&lt;p&gt;In a pinch, I needed to randomize the order of a few thousand lines of plain text.  In Linux you can just pipe the file through &lt;code&gt;sort&lt;/code&gt;, even right inside Vim:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:%!sort -R
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But I was stuck on Windows.  And I don't know how to randomize a file in native Vim script.  But doing it in Ruby is pretty easy, and luckily, Vim has awesome Ruby support.  Tne minutes' work and a few peeks at &lt;code&gt;:h ruby&lt;/code&gt; and we have a successful, working kludge:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function! ShuffleLines()
ruby &amp;lt;&amp;lt; EOF
    buf = VIM::Buffer.current
    firstnum =  VIM::evaluate('a:firstline')
    lastnum = VIM::evaluate('a:lastline')
    lines = []
    firstnum.upto(lastnum) do |lnum|
      lines &amp;lt;&amp;lt; buf[lnum]
    end
    lines.shuffle!
    firstnum.upto(lastnum) do |lnum|
      buf[lnum] = lines[lnum-firstnum]
    end
EOF
endfunction
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;2011-07-07 23:32 - Edited to remove a superfluous line.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;2011-07-09 21:33 - Wrong parameter for &lt;code&gt;sort&lt;/code&gt;, oops.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Keyword Arguments: Ruby, Clojure, Common Lisp</title><link>http://briancarper.net/blog/579/keyword-arguments-ruby-clojure-common-lisp</link><guid>http://briancarper.net/blog/579/keyword-arguments-ruby-clojure-common-lisp</guid><pubDate>Fri, 24 Jun 2011 17:22:48 -0700</pubDate><description>&lt;p&gt;And suddenly I return to blogging, rising from the ashes like some kind of zombie phoenix.  Turns out &lt;a href=&quot;http://oreilly.com/catalog/0636920013754/&quot;&gt;writing a book&lt;/a&gt; is a good absorber of time, like some sort of heavy-duty temporal paper towel.  Now that I've gotten the terrible similes out of my system, let's talk about keyword arguments, one of my favorite features in any language that supports them.&lt;/p&gt;

&lt;p&gt;Ruby, Clojure, and Common Lisp are all languages I enjoy to some degree, and they all have keyword arguments.  Let's explore how keyword args differ in those languages.&lt;/p&gt;

&lt;!--more Read about keyword arguments. --&gt;

&lt;h1&gt;Why keyword arguments?&lt;/h1&gt;

&lt;p&gt;Why are keyword arguments good?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You can omit arguments.&lt;/li&gt;
&lt;li&gt;You can supply arguments in an arbitrary order.&lt;/li&gt;
&lt;li&gt;Arguments are labeled, so you know what argument means what. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Positional arguments require mentally lining up the 7th argument in your function call with the 7th argument in the function signature, and so on.  Keyword arguments become more and more attractive the more arguments you have in your function signature.&lt;/p&gt;

&lt;p&gt;Keyword arguments trade a bit of verbosity for added explicitness, clarity and reduced mental burden.  (Kind of like Lisps do overall.  Fancy that.)&lt;/p&gt;

&lt;h1&gt;Ruby&lt;/h1&gt;

&lt;p&gt;Ruby doesn't have special support for keyword arguments.  But Ruby likes its hashes, so you can just pass one in as an argument to a function.  As some syntax sugar, if you pass a &quot;flat&quot; list of &lt;code&gt;:key =&amp;gt; val&lt;/code&gt; pairs, Ruby slurps them all together and stuffs them into a hash for you.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: ruby&quot;&gt;def foo(arg)
  p arg
end

foo({:x =&amp;gt; 123})                  # =&amp;gt; {:x=&amp;gt;123}
foo(:x =&amp;gt; 123)                    # =&amp;gt; {:x=&amp;gt;123}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With even more added sugar, you can leave off the parens in Ruby function calls.  So this is pretty common in Ruby:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: ruby&quot;&gt;foo :x =&amp;gt; 123                     # =&amp;gt; {:x=&amp;gt;123}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;How nice and punctuation-less.  But then things get ugly.  What about this?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: ruby&quot;&gt;foo {:x =&amp;gt; 123}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That won't even compile.  Ruby thinks &lt;code&gt;{:x =&amp;gt; 123}&lt;/code&gt; is a code block, and a bare key/value pair isn't valid syntax as the first thing in a code block.  You need the parens.  A bit unfortunate, but it gets worse...&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: ruby&quot;&gt;def bar(arg1,arg2)
  puts &quot;#{arg1} #{arg2}&quot;
end

bar :x =&amp;gt; 123, :y =&amp;gt; 456          # Runtime error
bar {:x =&amp;gt; 123}, {:y =&amp;gt; 456}      # Won't compile
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the first example, all of the key/value pairs are slurped into one hash and end up in &lt;code&gt;arg1&lt;/code&gt;.  There's nothing left for &lt;code&gt;arg2&lt;/code&gt;, so you get a &quot;wrong number of arguments&quot; exception.  The second example won't even compile, of course, because again Ruby thinks &lt;code&gt;{:x =&amp;gt; 123}&lt;/code&gt; must be a code block with invalid syntax.&lt;/p&gt;

&lt;p&gt;It gets worse if you change the argument list for &lt;code&gt;bar&lt;/code&gt; slightly...&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: ruby&quot;&gt;def bar2(arg1 = {}, arg2 = {})
  puts &quot;#{arg1} #{arg2}&quot;
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This way, you don't even have to supply any arguments.  This is nice, if all of your argument are optional.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: ruby&quot;&gt;bar2    # =&amp;gt; {} {}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now suppose you want &lt;code&gt;arg1&lt;/code&gt; to be &lt;code&gt;{:x =&amp;gt; 123}&lt;/code&gt;, and &lt;code&gt;arg2&lt;/code&gt; to be &lt;code&gt;{:y =&amp;gt; 456}&lt;/code&gt;.  You might naively try this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: ruby&quot;&gt;bar2 :x =&amp;gt; 123, :y =&amp;gt; 456         # =&amp;gt; {:x=&amp;gt;123, :y=&amp;gt;456} {}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Oops, it all got dumped into &lt;code&gt;arg1&lt;/code&gt;, and now instead of a missing argument error, &lt;code&gt;arg2&lt;/code&gt; silently ends up with a default, empty hash.  You have to explicitly pass in an empty value for &lt;code&gt;arg1&lt;/code&gt; so that everything is slurped into &lt;code&gt;arg2&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: ruby&quot;&gt;bar2 {}, :x =&amp;gt; 123, :y =&amp;gt; 456     # =&amp;gt; WRONG!  Ruby thinks {} is a code block again.

bar2({}, :x =&amp;gt; 123, :y =&amp;gt; 456)    # =&amp;gt; {} {:x=&amp;gt;123, :y=&amp;gt;456}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So much for syntax sugar.  You might think you'd be unlikely to find this kind of thing in the wild, but in Ruby on Rails for example, there are quite a few functions whose argument lists look exactly like this.  One signature for &lt;code&gt;link_to&lt;/code&gt; is:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: ruby&quot;&gt;link_to(body, url_options = {}, html_options = {})
&lt;/code&gt;&lt;/pre&gt;

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

&lt;pre&gt;&lt;code class=&quot;brush: ruby&quot;&gt;link_to &quot;foo&quot;, :controller =&amp;gt; :x                          # OK
link_to &quot;foo&quot;, :controller =&amp;gt; :x, :class =&amp;gt; &quot;css_class&quot;   # WRONG! 
link_to &quot;foo&quot;, {:controller =&amp;gt; :x}, :class =&amp;gt; &quot;css_class&quot; # OK
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What about support for default arguments?  We might want to say that if you didn't pass in an &lt;code&gt;:x&lt;/code&gt; argument, we want it to have some default value.  You might think this would work:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: ruby&quot;&gt;def baz(x = {:x =&amp;gt; 123})
   p x
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But you would be sadly mistaken.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: ruby&quot;&gt;baz                               # =&amp;gt; {:x=&amp;gt;123}
baz :y =&amp;gt; 456                     # =&amp;gt; {:y=&amp;gt;456} ... oops
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ruby doesn't merge your keyword arguments into the map in the parameter list.  It uses that map if you don't supply any arguments, otherwise your map replaces the default entirely.  So to get default arguments, you need something like&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: ruby&quot;&gt;def baz2(args = {})
  args = {:x =&amp;gt; 123}.merge(args)
  p args
end

baz2                              # =&amp;gt; {:x=&amp;gt;123}
baz2 :x =&amp;gt; 555                    # =&amp;gt; {:x=&amp;gt;555}
baz2 :y =&amp;gt; 456                    # =&amp;gt; {:x=&amp;gt;123, :y=&amp;gt;456}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Kind of messy, but that's OK.&lt;/p&gt;

&lt;p&gt;One last subtle ambiguity in Ruby is determining whether someone passed a &lt;code&gt;nil&lt;/code&gt; argument for a keyword explicitly, or omitted a keyword entirely.  It might make a difference in some circumstances.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: ruby&quot;&gt;def quux(args={})
  p args.include? :x
  args = {:x =&amp;gt; nil}.merge(args)
  p args
end

quux                              # true, {:x=&amp;gt;nil}
quux :x =&amp;gt; nil                    # false, {:x=&amp;gt;nil}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Pretty messy, but such is life.&lt;/p&gt;

&lt;h1&gt;Clojure&lt;/h1&gt;

&lt;p&gt;Part of the fun of Lisps is lack of ambiguity.  Everything is spelled out in all its parenthesized glory.  In Clojure, when you call a function like &lt;code&gt;(foo :x 123)&lt;/code&gt;, Clojure requires you to specify what you want to happen with those arguments.&lt;/p&gt;

&lt;p&gt;It used to be that Clojure didn't have much support for keyword args at all.  Clojure did have support for allowing variable numbers of arguments to functions though.  So in the beginning, people used to slurp all of their arguments together into a list, and then turn it into a map inside the function.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: clojure&quot;&gt;user&amp;gt; (defn foo [&amp;amp; args]
        (let [args (apply hash-map args)]
          (prn args)))
#'user/foo
user&amp;gt; (foo)
{}
user&amp;gt; (foo :x 123)
{:x 123}
user&amp;gt; (foo :x 123 :y 456)
{:y 456, :x 123}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That worked.  It still works today.  But nowadays there's a better way.  Why not slurp your arguments directly into a hash-map?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: clojure&quot;&gt;user&amp;gt; (defn foo [&amp;amp; {:as args}]
        (prn args))
#'user/foo
user&amp;gt; (foo)
nil
user&amp;gt; (foo :x 123)
{:x 123}
user&amp;gt; (foo :x 123 :y 456)
{:y 456, :x 123}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is an example of &lt;em&gt;destructuring&lt;/em&gt;.  In this case, all of our arguments are slurped into a list (thanks to &lt;code&gt;&amp;amp;&lt;/code&gt;), then this list is matched against our destructuring pattern, in this case &lt;code&gt;{:as args}&lt;/code&gt;.  &lt;code&gt;:as&lt;/code&gt; says to take everything in the list, turn it into a map and give the resulting map the name &lt;code&gt;args&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This isn't a special feature of &lt;code&gt;defn&lt;/code&gt;.  Destructuring works anywhere you're setting up bindings, for example in &lt;code&gt;let&lt;/code&gt;, &lt;code&gt;for&lt;/code&gt;, &lt;code&gt;doseq&lt;/code&gt; etc.  Like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;user&amp;gt; (let [{:as args} (list :x 123 :y 456)] args)
{:y 456, :x 123}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It just so happens that &lt;code&gt;&amp;amp;&lt;/code&gt; creates the list for you, out of the arguments you pass.&lt;/p&gt;

&lt;p&gt;Destructuring does lots more than that though.  We can immediately pull out the values for keywords we care about, so they'll be bound to names in our function body.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: clojure&quot;&gt;user&amp;gt; (defn foo [&amp;amp; {:keys [x y z]}]
        (prn x y z))
#'user/foo

user&amp;gt; (foo :z 123 :x 456)
456 nil 123
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It's certainly a bit more verbose than Ruby in the function signature, but it lacks ambiguity and it saves you some repetition in the function body. &lt;/p&gt;

&lt;p&gt;Clojure's approach also has the benefit of specifying directly in the function signature which keywords you're expecting.  In a smart editor, like Emacs, you get an indicator of what kinds of keywords you should be passing in.   See at the bottom?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/clojure/function-signature.png&quot; alt=&quot;Emacs function signature display&quot; title=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is also available at the Clojure REPL via the &lt;code&gt;doc&lt;/code&gt; function.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: clojure&quot;&gt;user&amp;gt; (doc foo)
-------------------------
user/foo
([&amp;amp; {:keys [a b c]}])
  nil
nil
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There's no better documentation than live, built-in documentation.  There's nothing more distracting when programming than context shifts, and having to dig into a web browser to check a function signature is a huge mental page fault.&lt;/p&gt;

&lt;p&gt;What about default values?  Sure.  You can use &lt;code&gt;:or&lt;/code&gt; to specify defaults for some or all of your keywords.  This works much more like I'd expect, compared to Ruby.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: clojure&quot;&gt;user&amp;gt; (defn foo [&amp;amp; {:keys [x y z] :or {x 1 y 2 z 3}}]
        (prn x y z))
#'user/foo

user&amp;gt; (foo :y 555)
1 555 3
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What about determining whether the user passed &lt;code&gt;nil&lt;/code&gt; for a keyword or whether they omitted the keyword entirely?  For that, you have to resort to testing the argument map for the existence of the key, which isn't fun, but at least it's possible.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: clojure&quot;&gt;user&amp;gt; (defn foo [&amp;amp; {:keys [x y z] 
                    :or {x 1 y 2 z 3}
                    :as args}]
        (prn x y z)
        (prn args)
        (doseq [k [:x :y :z]]
          (println &quot;Contains&quot; k &quot;=&amp;gt;&quot; (contains? args k))))
#'user/foo

user&amp;gt; (foo :x 1 :y 2)
1 2 3
{:x 1, :y 2}
Contains :x =&amp;gt; true
Contains :y =&amp;gt; true
Contains :z =&amp;gt; false
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Why do I keep mentioning this?  See Common Lisp below.&lt;/p&gt;

&lt;p&gt;In any case, our parameter list is becoming huge and unweildy.  The first time I saw sample Clojure code like this, I almost did a spit-take.  But after a bit of getting used to, I'm finding that this syntax is pretty comfortable.&lt;/p&gt;

&lt;p&gt;The simplest case may not be as concise as Ruby, but aside from lack of ambiguity, the benefit of Clojure's approach is being able to safely do powerful (and borderline insane) things, like nested destructuring.  And this works everywhere you're setting up a binding.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: clojure&quot;&gt;(defn ow-my-eyes [a &amp;amp; {[b {:keys [x y]}
                        &amp;amp; {[g h] :r
                           :keys [p q]
                           :or {q 123}}]
                       :x}]
  (prn a b g h p q x y))



user&amp;gt; (ow-my-eyes 444 :x [1 {:x 555 :y 666} :p 3 :r [888 999]])
444 1 888 999 3 123 555 666
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you wrote code like that in real life, you'd likely be defenestrated, but at least you know you can do it.  And destructuring in Clojure could likely be extended even further in the future, if someone came up with a use case for something that isn't supported.&lt;/p&gt;

&lt;p&gt;Official documentation for all of this is &lt;a href=&quot;http://clojure.org/special_forms&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;Common Lisp&lt;/h1&gt;

&lt;p&gt;When it comes to keyword arguments, Common Lisp supports mostly everything that Clojure does, and some things it doesn't.  CL was likely a big inspiration for Clojure's destructuring.  I highly recommend reading Practical Common Lisp to learn more about CL &lt;a href=&quot;http://www.gigamonkeys.com/book/functions.html&quot;&gt;keyword arguments&lt;/a&gt; and &lt;a href=&quot;http://www.gigamonkeys.com/book/beyond-lists-other-uses-for-cons-cells.html&quot;&gt;list destructuring&lt;/a&gt;.  (Read the rest of the book while you're at it.)&lt;/p&gt;

&lt;p&gt;Keyword arguments in CL look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; (defun foo (&amp;amp;key x (y 123) (z 456 z-supplied-p))
    (pprint (list x y z z-supplied-p)))
FOO

&amp;gt; (foo)
(NIL 123 456 NIL)

&amp;gt; (foo :z nil)             ; note, z-supplied-p tells us whether z was omitted or not
(NIL 123 NIL T)

&amp;gt; (foo :z 555 :x 666 :y 777)
(666 777 555 T)

&amp;gt; (foo :x 123)
(123 123 456 NIL)

&amp;gt; (foo :x 555)
(555 123 456 NIL)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Yeah, there's direct support for distinguishing supplied keys with nil values, and un-supplied keys.  That's pretty nice.&lt;/p&gt;

&lt;p&gt;Common Lisp also supports insane things like having keyword arguments' default values be a function of other arguments in the parameter list.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; (defun bar (&amp;amp;key (x 123) (y (+ x 1000)))
    (pprint (list x y)))
BAR

&amp;gt; (bar)
(123 1123)

&amp;gt; (bar :x 5)
(5 1005)

&amp;gt; (bar :x 5 :y 6)
(5 6)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Clojure destructuring can't do this by default, so you'd have to resort to a &lt;code&gt;let&lt;/code&gt; in the function body.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defn bar [&amp;amp; {:keys [x y] :or {x 123}}]
  (let [y (or y (+ x 1000))]
    (prn x y)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There's nothing stopping Clojure's destructuring from being patched to support this, of course.  But this isn't a feature I've ever found myself wanting particularly badly.&lt;/p&gt;

&lt;p&gt;As for how to destructure CL keyword arguments into a vector or hash-map, CL doesn't directly support doing it in function parameter lists like Clojure does.  (Though there's nothing stopping someone from throwing together a reader macro to let CL do this, of course.)  This isn't really surprising, because CL loves its cons cells, while Clojure embraces maps (and vectors and sets etc.), offering them default reader syntax and lots of other built-in support.&lt;/p&gt;

&lt;p&gt;So there you have it.  Keyword arguments.  Use them.  Love them.&lt;/p&gt;

&lt;p&gt;Lessons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sugar can be bad for your health.&lt;/li&gt;
&lt;li&gt;Ambiguous, bad.  Explicit, good.&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>org-mode is awesome</title><link>http://briancarper.net/blog/577/org-mode-is-awesome</link><guid>http://briancarper.net/blog/577/org-mode-is-awesome</guid><pubDate>Thu, 20 Jan 2011 16:14:44 -0800</pubDate><description>&lt;p&gt;I've seen &lt;a href=&quot;http://orgmode.org/&quot;&gt;org-mode&lt;/a&gt; for Emacs mentioned very frequently around the interwebs, so it went into my mental queue of topics to learn.  It finally bubbled to the top this week, so I took a look.&lt;/p&gt;

&lt;h1&gt;Organizer?  Nah.&lt;/h1&gt;

&lt;p&gt;As an organizer/calendar, well, I doubt I'll need it.  Enforced use of MS Outlook is mandated by work.  My Post-it-notes-all-over-my-desk method of organization will also continue to serve me well.&lt;/p&gt;

&lt;p&gt;There are some nice agenda-related shortcuts that are probably worth using though, like typing &lt;code&gt;C-c .&lt;/code&gt; to enter a datestamp, like &lt;code&gt;&amp;lt;2011-01-20 Thu&amp;gt;&lt;/code&gt;.  Then you can increment or decrement it one year/month/day at a time via &lt;code&gt;S-up&lt;/code&gt; and &lt;code&gt;S-down&lt;/code&gt;.  I like this.&lt;/p&gt;

&lt;h1&gt;Plaintext editor?  Yes!&lt;/h1&gt;

&lt;p&gt;As a plaintext outline and table editor... wow.  org-mode rocks.  Do you know how many hours of my life could have been saved by having a good ASCII table/bullet-list editor?  org-mode lines everything up and keeps it all nice and neat for you.&lt;/p&gt;

&lt;p&gt;You can also make plaintext check boxes and check/uncheck them.  And you can insert hyperlinks and footnotes, and click them to open web pages or jump back and forth between footnote and reference.&lt;/p&gt;

&lt;p&gt;There are ways to collapse and expand outlines, search for items and only display those items, and so on.  The &lt;a href=&quot;http://orgmode.org/guide/index.html&quot;&gt;documentation&lt;/a&gt; for org-mode is very clear and took me less than an hour to read through.  All-in-all a pleasant experience.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;* Agenda
** Things to learn
1. [X] Clojure
2. [X] org-mode (see [fn:diagram1])
3. [ ] Haskell
4. [ ] Japanese
   1. [X] Hiragana
   2. [X] Katakana
   3. [ ] Kanji
5. [ ] The true meaning of friendship

* Footnotes
[fn:diagram1]

| Task                              | Annoyance (1-10) |
|-----------------------------------+------------------|
| Making ASCII tables by hand       |              9.5 |
| Making ASCII bullet lists by hand |              7.2 |
| Using org-mode                    |              0.4 |
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It looks nice plastered into my blog, but you don't get a real idea of how many cool things you can do with it until you open it in Emacs and start shuffling items around, bumping them up/down a level in headlines, creating properly-numbered bullet items with one key, and seeing the columns in the table auto-resize as you type.&lt;/p&gt;

&lt;p&gt;I also highly recommend putting &lt;code&gt;(setq org-startup-indented t)&lt;/code&gt; into &lt;code&gt;.emacs&lt;/code&gt; to make everything look pretty on-screen.  It still saves as the simple plaintext above, but it looks like this in Emacs:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/emacs/org-mode.png&quot; alt=&quot;org-mode&quot; title=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I can definitely see using org-mode for TODO files in some of my projects.  (You can mark entries as TODO (just by typing &lt;code&gt;TODO&lt;/code&gt; in front), and then toggle between TODO/DONE via &lt;code&gt;C-c C-t&lt;/code&gt;.)   I can also see using it as a general-purpose note-taker.&lt;/p&gt;

&lt;p&gt;org-mode also has a &lt;a href=&quot;http://mobileorg.ncogni.to/doc/&quot;&gt;mobile version&lt;/a&gt; for iPhone and Android, synced via WebDAV or Dropbox, so you can org-mode on your phone while you're driving to the grocery store&lt;sup id=&quot;fnref:dontdothis&quot;&gt;&lt;a href=&quot;#fn:dontdothis&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.  Again I don't really need this, but there it is.&lt;/p&gt;

&lt;h1&gt;The joy of plaintext&lt;/h1&gt;

&lt;p&gt;Plaintext is awesome.&lt;/p&gt;

&lt;p&gt;It's the universal file format.  It's readable and writeable by scripting langauges, terminals, text editors, IDEs, word processors, web browsers, even lowly humans.&lt;/p&gt;

&lt;p&gt;Plaintext's one shortcoming is its lack of structure.  It's just a bunch of letters.  It doesn't have a color, it doesn't have a style, it doesn't line up into columns without a lot of effort.  There's nothing stopping you from opening a parenthesized list and forgetting the closing paren.&lt;/p&gt;

&lt;p&gt;Computers don't care about these problems, but humans are bad at producting plaintext by hand, and bad at editing it once it's produced.  Our clumsy, stumpy fingers and inconsistent, chaotic brains can't handle the freedom.&lt;/p&gt;

&lt;p&gt;Emacs (and Vim) are awesome because they let you do magical things to plaintext.  They enforce structure.  They provide shortcuts so you can get your plainext right the first time.  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;[ ]&lt;/code&gt; is just two braces and a space, but org-mode lets me hit &lt;code&gt;C-c C-c&lt;/code&gt; and turn the space into an &lt;code&gt;X&lt;/code&gt;.  This may seem banal, hardly worth caring about, but add to this shortcut thousands upon thousands of others.  Things like org-mode, or &lt;a href=&quot;http://www.emacswiki.org/emacs/ParEdit&quot;&gt;paredit&lt;/a&gt;, or all of Vim's built-in magic... it all adds up to something wonderful.&lt;/p&gt;

&lt;p&gt;And best of all, you always still have the option of manually keyboarding over and typing that &lt;code&gt;X&lt;/code&gt; between the braces yourself.  It's still just plaintext underneath.  So you end up with the best of both worlds.&lt;/p&gt;&lt;div class=&quot;footnotes&quot;&gt;&lt;ol&gt;&lt;li id=&quot;fn:dontdothis&quot;&gt;&lt;p&gt;I do not recommend using org-mode while driving, for public safety reasons. &lt;a rev=&quot;footnote&quot; href=&quot;#fnref:dontdothis&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item><item><title>2010 in review</title><link>http://briancarper.net/blog/574/2010-in-review</link><guid>http://briancarper.net/blog/574/2010-in-review</guid><pubDate>Wed, 05 Jan 2011 10:10:03 -0800</pubDate><description>&lt;p&gt;Another year down the drain.  A good year, in the end.&lt;/p&gt;

&lt;h1&gt;2010 Geek Achievements&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Wrote some code...
&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/briancarper/cow-blog&quot;&gt;cow-blog&lt;/a&gt; - The engine running this blog.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/briancarper/oyako&quot;&gt;oyako&lt;/a&gt; - Clojure ORM library.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/briancarper/gaka&quot;&gt;gaka&lt;/a&gt; - CSS compiler for Clojure&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Finished a huge project for work, my first AJAX-y web app (in Rails).  That was fun, albeit stressful.&lt;/li&gt;
&lt;li&gt;Learned a lot of git.&lt;/li&gt;
&lt;li&gt;Learned a lot of Clojure.  &lt;/li&gt;
&lt;li&gt;Learned a lot of Emacs.&lt;/li&gt;
&lt;li&gt;Learned a lot of Javascript.&lt;/li&gt;
&lt;li&gt;Learned a lot of  PostgreSQL.  It's good to be free of MySQL.&lt;/li&gt;
&lt;li&gt;Switched to ZSH.  This was a good switch.&lt;/li&gt;
&lt;li&gt;Tried to learn a lot of Japanese, but kind of fizzled out at the end of the year.&lt;/li&gt;
&lt;li&gt;Alllllllmost got a Clojure gold badge on &lt;a href=&quot;http://stackoverflow.com/tags/clojure/topusers&quot;&gt;Stack Overflow&lt;/a&gt;.  I'll get it soon though.  Not losing any sleep over it either way.&lt;/li&gt;
&lt;li&gt;Read a lot of books.  The best: probably Feynman's books of anecdotes.&lt;/li&gt;
&lt;li&gt;Blogged a bit.  Got an article in &lt;a href=&quot;http://hackermonthly.com/issue-3.html&quot;&gt;Hacker Monthly&lt;/a&gt;.  Was flamed repeatedly.  Learned a lot in the process.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;2010 Non-Geek Achievements&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Immigrated to Canada.  A good move, without a doubt.&lt;/li&gt;
&lt;li&gt;Lost 25ish lbs. :)&lt;/li&gt;
&lt;li&gt;Learned how to cook better.&lt;/li&gt;
&lt;li&gt;My most important achievement from 2010 is actually non-geek: I finally obtained a bit of an offline social life.  This is not an easy task for one such as myself.&lt;/li&gt;
&lt;li&gt;Continued to learn to appreciate good beer.  Longwood Dunkelweizen, mmm.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;2010 Failures&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Did not blog enough.&lt;sup id=&quot;fnref:sociallife&quot;&gt;&lt;a href=&quot;#fn:sociallife&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Did not write enough code.&lt;sup id=&quot;fnref:sociallife&quot;&gt;&lt;a href=&quot;#fn:sociallife&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Missed the &lt;a href=&quot;http://clojure-conj.org/&quot;&gt;first Clojure Conj&lt;/a&gt;.  Maybe next year.&lt;/li&gt;
&lt;li&gt;Re-gained 10ish lbs. :( &lt;sup id=&quot;fnref:fat&quot;&gt;&lt;a href=&quot;#fn:fat&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;Plans for 2011&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Re-lose 25ish pounds.  I'd like to reach the weight I had in college.&lt;/li&gt;
&lt;li&gt;Finish my rewrite of oyako.  I have ambitious plans for it, if I can just find the time.&lt;/li&gt;
&lt;li&gt;Finish my rewrite of cow-blog to match oyako.&lt;/li&gt;
&lt;li&gt;Keep working on the RPG my wife and I are creating (in Clojure).&lt;/li&gt;
&lt;li&gt;Attend the next Clojure Conj, I hope.&lt;/li&gt;
&lt;li&gt;Learn more Clojure.&lt;/li&gt;
&lt;li&gt;Learn Haskell?  Trying and failing to learn Haskell has become somewhat of a tradition, no sense stopping now.&lt;/li&gt;
&lt;li&gt;Learn all 2000+ jouyou kanji by the end of the year.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Supar sekrit projekt.&lt;/em&gt;&lt;/strong&gt;  But I haven't signed the contract for it yet so I won't talk about it until I do.&lt;/li&gt;
&lt;li&gt;Maintain social life at acceptable levels.&lt;/li&gt;
&lt;li&gt;Buy a house.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I feel like I have solid plans for completing each of these things.  Blogging more often and finishing oyako are high on my list of priorities.  I expect 2011 to be my most productive year to date.&lt;/p&gt;&lt;div class=&quot;footnotes&quot;&gt;&lt;ol&gt;&lt;li id=&quot;fn:sociallife&quot;&gt;&lt;p&gt;See also, non-geek achievement #4, &quot;Obtained social life&quot;. &lt;a rev=&quot;footnote&quot; href=&quot;#fnref:sociallife&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li id=&quot;fn:fat&quot;&gt;&lt;p&gt;See also non-geek achievement #3, &quot;Learned how to cook better&quot;. &lt;a rev=&quot;footnote&quot; href=&quot;#fnref:fat&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item><item><title>Vim undo tree visualization</title><link>http://briancarper.net/blog/573/vim-undo-tree-visualization</link><guid>http://briancarper.net/blog/573/vim-undo-tree-visualization</guid><pubDate>Mon, 18 Oct 2010 15:21:16 -0700</pubDate><description>&lt;p&gt;I wrote &lt;a href=&quot;http://briancarper.net/blog/568/emacs-undo-trees&quot;&gt;previously&lt;/a&gt; about an awsome plugin to give Emacs Vim-style undo trees.&lt;/p&gt;

&lt;p&gt;Vim's undo trees are the best thing since sliced bread, but the interface for browsing through the tree is not pleasant.  The &lt;a href=&quot;http://www.dr-qubit.org/undo-tree/undo-tree.el&quot;&gt;Emacs undo-tree library&lt;/a&gt; has a way to visualize the tree and move through it with your keyboard, which solves this problem.&lt;/p&gt;

&lt;p&gt;But now, thanks to Steve Losh, &lt;a href=&quot;http://bitbucket.org/sjl/gundo.vim/src&quot;&gt;Vim has an undo-tree visualizer too&lt;/a&gt;.  Delicious.  Though it's still beta and promises to eat your babies, it seems to work pretty well.  I think the diff view of the changes for the undo is a really good idea.&lt;/p&gt;

&lt;p&gt;Thus continues the eternal Vim/Emacs arms race.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/vim/vim-undo-tree.png&quot; alt=&quot;Vim undo tree&quot; title=&quot;&quot; /&gt;&lt;/p&gt;</description></item><item><title>Productivity Booster</title><link>http://briancarper.net/blog/572/productivity-booster</link><guid>http://briancarper.net/blog/572/productivity-booster</guid><pubDate>Fri, 08 Oct 2010 15:09:40 -0700</pubDate><description>&lt;p&gt;I came up with a great way to increase my productivity recently.  You need a locally-running Apache server for this to work most effectively.&lt;/p&gt;

&lt;p&gt;First you need to set up a redirect for 404 requests to localhost.  On my system I determined that &lt;code&gt;DocumentRoot&lt;/code&gt; is &lt;code&gt;/srv/http&lt;/code&gt;, so I set this up in &lt;code&gt;/etc/httpd/conf/httpd.conf&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: xml&quot;&gt;&amp;lt;Directory &quot;/srv/http&quot;&amp;gt;
    AllowOverride All
&amp;lt;/Directory&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next I edited &lt;code&gt;/srv/http/.htaccess&lt;/code&gt; to redirect 404's to a main index page:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ErrorDocument 404 /index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then I created &lt;code&gt;/srv/http/index.html&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: html&quot;&gt;&amp;lt;html&amp;gt;
    &amp;lt;head&amp;gt;
        &amp;lt;title&amp;gt;GET BACK TO WORK, YOU HOBO&amp;lt;/title&amp;gt;
        &amp;lt;style type=&quot;text/css&quot;&amp;gt;
            html {
                background: #f00;
            }
            h1 {
                color: #0f0;
                font-family: sans-serif;
                text-align: center;
                margin-top: 100px;
                font-size: 64pt;
            }
        &amp;lt;/style&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
        &amp;lt;h1&amp;gt;GET BACK TO WORK, YOU HOBO&amp;lt;/h1&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Almost done; the final step is to edit &lt;code&gt;/etc/hosts&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;127.0.0.1 reddit.com www.reddit.com slashdot.org news.ycombinator.com
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;/random/get-back-to-work.png&quot;&gt;Now I see this.&lt;/a&gt;  Image hidden behind a link to spare the eyes of my readers.&lt;/p&gt;

&lt;p&gt;If this doesn't work, you could try making the background color flash quickly between red and green, or add a background MIDI and some animated GIFs.&lt;/p&gt;</description></item><item><title>iPad?  More like iAd.  Vertisements.</title><link>http://briancarper.net/blog/571/ipad--more-like-iad--vertisements</link><guid>http://briancarper.net/blog/571/ipad--more-like-iad--vertisements</guid><pubDate>Thu, 16 Sep 2010 18:43:35 -0700</pubDate><description>&lt;p&gt;Via &lt;a href=&quot;http://apple.slashdot.org/story/10/09/16/2248248/iPad-Getting-a-Subscription-Infrastructure&quot;&gt;Slashdot&lt;/a&gt;, it seems soon you may be able to subscribe to newspapers on the iPad in the near future.  &lt;/p&gt;

&lt;p&gt;Sure.  Why pay $10 for a paper copy of something when you can pay the same $10 for a likely-DRM'ed copy that can only be read on a $500 portable computer?&lt;/p&gt;

&lt;p&gt;In all honesty though, instant delivery, lack of clutter, &quot;take it anywhere&quot;, being able to archive issues indefinitely, text search... those features might be worth the money, if it was a really good newspaper/magazine.&lt;/p&gt;

&lt;p&gt;But wait, there's more.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The Cupertino company has agreed to provide an opt-in function for subscribers to allow Apple to share with publishers their information, which includes vital data that news organizations use to attract advertisers, industry sources say.&lt;/p&gt;
  
  &lt;p&gt;...&lt;/p&gt;
  
  &lt;p&gt;While the leap into the digital tablet market comes with short-term problems for newspapers, the iPad and future tablets will provide a new digital palette for publications to create sophisticated and lucrative ads, said Needham &amp;amp; Co. analyst Charles Wolf.&lt;/p&gt;
  
  &lt;p&gt;&quot;I would say it's a risk, but I would argue it's a short-term risk,&quot; Wolf said. &quot;If you can put animation and multimedia into ads, that will greatly enhance reader views. I am certain of that.&quot;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So as I understand it, first I buy a $500 gadget.  Then I pay for a newspaper subscription.  Then a bunch of companies want me to give them personal information about myself, so they can share it amongst themselves.  And then I have to view ads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Animated&lt;/em&gt;&lt;/strong&gt; ads.&lt;/p&gt;

&lt;p&gt;The only thing better would be if the iPad also woke you up at 4AM and tried to sell you life insurance.  Maybe Apple would let me install a free ad-blocker script for my news reader though.  It is my hardware, after all... pfffft, yeah, I could't keep going with a straight face.&lt;/p&gt;

&lt;p&gt;And thus my desire to get an iPad, kind-of sort-of building over the past couple of months, once again flatlines.&lt;/p&gt;</description></item><item><title>Git info in your ZSH Prompt</title><link>http://briancarper.net/blog/570/git-info-in-your-zsh-prompt</link><guid>http://briancarper.net/blog/570/git-info-in-your-zsh-prompt</guid><pubDate>Fri, 10 Sep 2010 13:31:37 -0700</pubDate><description>&lt;p&gt;Recently I discovered &lt;a href=&quot;http://zsh.sourceforge.net/Doc/Release/User-Contributions.html#SEC273&quot;&gt;vcs_info&lt;/a&gt; recently.  This nicely replaces the horrible hack I was using previously to show current Git status.  vcs_info works with VCSes besides Git, and it handles some of the magic and keeps your &lt;code&gt;.zshrc&lt;/code&gt; clean, so those are nice benefits.&lt;/p&gt;

&lt;p&gt;I used some Unicode to display colored circles.  Green if there are staged changes, yellow if there are unstaged changes, and red if there are new untracked-yet-unignored files.  Below is a picture.&lt;/p&gt;

&lt;p&gt;I like this because I'm constantly forgetting to &lt;code&gt;git add&lt;/code&gt; newly-created files.  Then I have to add them and amend my commit, and so on.  I like a prompt that reminds me that new files showed up that need to be added or ignored.&lt;/p&gt;

&lt;p&gt;Code:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: bash&quot;&gt;autoload -Uz vcs_info

zstyle ':vcs_info:*' stagedstr '%F{28}●'
zstyle ':vcs_info:*' unstagedstr '%F{11}●'
zstyle ':vcs_info:*' check-for-changes true
zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat '%b%F{1}:%F{11}%r'
zstyle ':vcs_info:*' enable git svn
precmd () {
    if [[ -z $(git ls-files --other --exclude-standard 2&amp;gt; /dev/null) ]] {
        zstyle ':vcs_info:*' formats ' [%F{green}%b%c%u%F{blue}]'
    } else {
        zstyle ':vcs_info:*' formats ' [%F{green}%b%c%u%F{red}●%F{blue}]'
    }

    vcs_info
}

setopt prompt_subst
PROMPT='%F{blue}%n@%m %c${vcs_info_msg_0_}%F{blue} %(?/%F{blue}/%F{red})%% %{$reset_color%}'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Picture:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/random/zsh-git.png&quot; alt=&quot;ZSH and Git&quot; title=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h1&gt;Limitations&lt;/h1&gt;

&lt;p&gt;As you can see in the screenshot, when you have a brand new Git repo (no commits yet), vcs_info fails to show you that there are files staged.  It works OK after you have at least one commit though.&lt;/p&gt;

&lt;p&gt;vcs_info doesn't (yet?) handle showing untracked files.  So I hacked a function to support it.&lt;/p&gt;

&lt;p&gt;Finding a good Unicode symbol that displays nicely in monospace font was annoying.  If I ever change fonts, I'll likely have to pick a new symbol.  It also doesn't display too well in a real tty.  Or over SSH when using Putty.  So I may have to scrap the stoplights and use plus-signs or something.  Sigh.&lt;/p&gt;</description></item><item><title>Vim :ruby and :rubydo scope</title><link>http://briancarper.net/blog/569/vim-ruby-and-rubydo-scope</link><guid>http://briancarper.net/blog/569/vim-ruby-and-rubydo-scope</guid><pubDate>Tue, 31 Aug 2010 10:40:51 -0700</pubDate><description>&lt;p&gt;Note to self.  In old Vim (tested in 7.2.320), I could do this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:ruby x='foo'
:rubydo $_=x
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now every line in the file says &lt;code&gt;foo&lt;/code&gt;.  But in Vim 7.3 I get an error:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;NameError: undefined local variable or method `x' for main:Object
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The scoping rules for Ruby in Vim must have changed somewhere along the line.  I was abusing this feature to do some handy things, so this is sad.&lt;/p&gt;

&lt;p&gt;A workaround is to use global variables in Ruby instead.  So this still works:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:ruby $x='foo'
:rubydo $_=$x
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Phew.&lt;/p&gt;</description></item><item><title>Emacs undo trees</title><link>http://briancarper.net/blog/568/emacs-undo-trees</link><guid>http://briancarper.net/blog/568/emacs-undo-trees</guid><pubDate>Tue, 17 Aug 2010 14:06:33 -0700</pubDate><description>&lt;p&gt;I've said it before: &lt;a href=&quot;/blog/361/emacs-undo-is-horrible&quot;&gt;undo in Emacs is horrible&lt;/a&gt;.  On the other hand, &lt;a href=&quot;http://stackoverflow.com/questions/1088864/how-is-vims-undo-tree-used&quot;&gt;undo in Vim is awesome&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But this is true no longer.  Now there are &lt;strong&gt;&lt;em&gt;&lt;a href=&quot;http://www.dr-qubit.org/undo-tree/undo-tree.el&quot;&gt;undo trees for Emacs!&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;  Yes, this news is so important I had to italicize and bold it.  It's like Emacs has been punching me in the face for years, and today I got it to stop.  I never thought I'd see the day.&lt;/p&gt;

&lt;p&gt;And it works great too.  You can even view the tree visually and navigate it with the cursor keys, which is a step up on what Vim offers out of the box.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/emacs/emacs-undo-trees.png&quot; alt=&quot;Emacs undo trees&quot; title=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In other news, Vim 7.3 is out and it now has &lt;a href=&quot;https://groups.google.com/group/vim_announce/browse_thread/thread/66c02efd1523554b&quot;&gt;persistent undo&lt;/a&gt; across reloads.  It's like an arms race, and gleeful hackers reap the benefits.&lt;/p&gt;</description></item><item><title>Let's draw some pixels</title><link>http://briancarper.net/blog/566/lets-draw-some-pixels</link><guid>http://briancarper.net/blog/566/lets-draw-some-pixels</guid><pubDate>Tue, 10 Aug 2010 11:19:42 -0700</pubDate><description>&lt;p&gt;I've been getting into &lt;a href=&quot;http://en.wikipedia.org/wiki/Pixel_art&quot;&gt;pixel art&lt;/a&gt; a lot lately.  It appeals to me on a lot of levels.&lt;/p&gt;

&lt;p&gt;The coder in me likes it because it's so precise.  Every pixel is placed just so.  The color palette is limited to a dozen colors.  Building a drawing out of such limited means reminds me of building programs out of primitives.  There are design patterns in pixel art: dithering, manual anti-aliasing.  There are abstractions that work and abstractions that don't.  There's a lot of goofing around with RGB values and transparency settings; it's perhaps the most deeply computer-based art form you could come up with, and as a deeply computer-based human, I really like it.&lt;/p&gt;

&lt;p&gt;The gamer in me is still partly stuck in the early 90's, so it's a huge injection of nostalgia to look at pixel art.  NES- and SNES-era games had a charm that is unmatched by anything since.  And I don't think that's &lt;em&gt;entirely&lt;/em&gt; nostalgia talking; I still play old games and they're still so much fun.  And the art in a lot of those games was just darned good.  If you stop and look at it really carefully, and start to get an understanding of how it was made, you can't help but be impressed.  &lt;/p&gt;

&lt;p&gt;The &quot;artist&quot; in me (if there is such a thing in my brain somewhere) is blown away by some of the things good pixel artists can produce.  Go look at &lt;a href=&quot;http://www.foolstown.com/&quot;&gt;foolstown.com&lt;/a&gt; and try not to slobber.  Some of this stuff just looks amazing.  Not &quot;good for a pixel drawing&quot;, but good on a level anyone could appreciate.&lt;/p&gt;

&lt;p&gt;Pixel doodles are also good practice for the RPG my wife and I are still ever-so-slowly creating.  Creating art and music for a game are turning out to be much harder work than programming it.&lt;/p&gt;

&lt;p&gt;In any case, I drew a cow standing beside a tree.  And I made a new &lt;a href=&quot;/page/565/pixel-art&quot;&gt;pixel art page&lt;/a&gt; to house my admittedly still-amateurish drawings.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/pixel/cow-tree.png&quot; alt=&quot;Cow Tree&quot; title=&quot;&quot; /&gt;&lt;/p&gt;</description></item><item><title>Review: What Do You Care What Other People Think?</title><link>http://briancarper.net/blog/564/review-what-do-you-care-what-other-people-think</link><guid>http://briancarper.net/blog/564/review-what-do-you-care-what-other-people-think</guid><pubDate>Fri, 06 Aug 2010 22:12:01 -0700</pubDate><description>&lt;p&gt;I recently reviewed &lt;em&gt;&lt;a href=&quot;http://briancarper.net/blog/559/review-surely-youre-joking-mr-feynman&quot;&gt;Surely You're Joking, Mr. Feynman!&lt;/a&gt;&lt;/em&gt;.  It was good enough that I had to get the sequel.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What Do You Care What Other People Think?&lt;/em&gt; is another collection of stories and anecdotes written by and/or about Richard Feynman.  A bit in contrast to the first book, rather than a chronological series of anecdotes, this book focuses on a couple of main topics.&lt;/p&gt;

&lt;p&gt;Feynman discusses his first wife in some detail.  Of particular interest, he describes his and his wife's brutal devotion to honesty in their relationship, even in the face of highly unpleasant truths (terminal disease, in this case).  It's the honesty of a scientist, carried into &quot;everyday&quot; life.  This was bittersweet for me to read, because the story has a sad ending.&lt;/p&gt;

&lt;p&gt;There is also a short series of letters from Feynman to others, where he discusses the silliness of pomp and circumstance, e.g. his foibles and breaches of protocol when meeting some king or other.  As someone who hates ceremony, I got a huge kick out of these.&lt;/p&gt;

&lt;p&gt;A large part of the book is devoted to discussing the &lt;a href=&quot;http://en.wikipedia.org/wiki/Feynman#Challenger_disaster&quot;&gt;Presidential Commission&lt;/a&gt; which investigated the cause of the Challenger shuttle disaster.  Feynman's full report is included in the book as well.&lt;/p&gt;

&lt;p&gt;As someone interested in astronomy and space flight (and who isn't interested in those?) I found this fascinating.  There's a lot of behind-the-scenes stuff.  Engineers are painted in a good light, managers and politicians not so much.  (Software engineers come out looking especially good, which made me feel (unjustifiably) good about myself by proxy.)  There are some diagrams and a lot of technical discussion of the shuttle.  Not so much that it drowns the narrative, but enough that I'm probably going to spend the next week reading Wikipedia on the subject now. &lt;/p&gt;

&lt;p&gt;Feynman explains his simple methods at getting to the truth in the investigation.  Go talk to the guys who put things together.  Get your hands on some O-ring rubber and test its resistance to temperature yourself in a glass of ice water.  Cut to the heart of the matter.  It's good stuff.&lt;/p&gt;

&lt;p&gt;Ultimately, as you know if you've read the report, Feynman rips NASA apart, showing that they were fooling themselves into believing the shuttle was safer than it really was.  The last sentence of the report says everything: &quot;&lt;strong&gt;&lt;em&gt;Nature cannot be fooled.&lt;/em&gt;&lt;/strong&gt;&quot;&lt;/p&gt;

&lt;p&gt;The last section of the book discusses the value of science.  More specifically, Feynman discusses the value of doubt.  I very much liked how the chapter ends:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;It is our responsibility as scientists , knowing the great progress which comes from a satisfactory philosophy of ignorance, the great progress which is the fruit of freedom of thought, to proclaim the value of this freedom; to teach how doubt is not to be feared but welcomed and discussed; and to demand this freedom as our duty to all coming generations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If there's one trait I had to pick to separate good people from bad, it would be the ability to admit being wrong.  And if I had to separate the good from the excellent, it would be not just the ability to admit being wrong, but the eagerness to be proved wrong.&lt;/p&gt;

&lt;p&gt;There's a certain kind of devotion to the truth that not many people achieve, and maybe not many people even want to achieve.  There's comfort in thinking that you &lt;em&gt;know&lt;/em&gt; things.  It's very tempting.  I think it's probably partly why most people are religious.  I suspect it's a big reason why so many people are so stubbornly wrong about so many things in general.  I suspect this comfort is an enormous source of suffering in the world.&lt;/p&gt;

&lt;p&gt;But there's another kind of comfort that people miss out on.  It's the comfort of knowing that although you're probably wrong about a lot of things, you're trying your hardest to be right.  You pay the price of being aware of your own state of ignorance, but you can rest a bit easier knowing that you're maybe, hopefully, inching towards the truth.  I never heard the word &quot;freedom&quot; used to describe this feeling before, as Feynman does above, but it fits.&lt;/p&gt;

&lt;p&gt;That's why I like reading about Feynman and reading Feynman's words.  He seemed to live this philosophy as well as anyone could hope to.&lt;/p&gt;</description></item><item><title>X automation with xte</title><link>http://briancarper.net/blog/563/x-automation-with-xte</link><guid>http://briancarper.net/blog/563/x-automation-with-xte</guid><pubDate>Fri, 06 Aug 2010 13:03:01 -0700</pubDate><description>&lt;p&gt;I learned today (via a &lt;a href=&quot;http://hanschen.org/2009/10/13/mouse-shortcuts-with-xbindkeys/&quot;&gt;great blog post&lt;/a&gt;) about &lt;code&gt;xte&lt;/code&gt;.  This program lets you simulate X Windows mouse and keyboard events from the commandline.  How much more awesome can you get?  &lt;/p&gt;

&lt;p&gt;Hans illustrates how to integrate &lt;code&gt;xbindkeys&lt;/code&gt; and &lt;code&gt;xte&lt;/code&gt; to make KDE4 effects activate.  I wanted the KDE4 &quot;Desktop Grid&quot; to appear when I press a mouse button (because my &lt;a href=&quot;http://briancarper.net/blog/558/review-logitech-performance-mx&quot;&gt;new mouse&lt;/a&gt; has a lot of buttons to spare), so this is exactly what I was looking for.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;xte&lt;/code&gt; is the kind of glue that makes Linux awesome.  KDE lets you set global keyboard shortcuts for lots of things.  &lt;code&gt;xbindkeys&lt;/code&gt; lets you assign shell commands to mouse buttons.  And &lt;code&gt;xte&lt;/code&gt; ties the two together.  Possibly none of the programmers on these three tools knew about the others, but they interact perfectly to let you do anything you want.&lt;/p&gt;

&lt;p&gt;You may be thinking, &quot;&lt;em&gt;If you want to work with KDE from the commandline, why not use DBUS?&lt;/em&gt;&quot;  That's what I tried to do first.  But I can't for the life of me figure it out.  There's &lt;a href=&quot;http://osdir.com/ml/kde-devel/2010-04/msg00195.html&quot;&gt;some indication&lt;/a&gt; that we might be able to do this somday, like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;qdbus org.kde.kglobalaccel /component/kwin org.kde.kglobalaccel.Component.invokeShortcut ShowDesktopGrid
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or maybe it's already in the latest version of KDE and I haven't upgraded yet.  Either way.&lt;/p&gt;

&lt;p&gt;By the way: could DBUS possibly have a more verbose or cryptic interface?  I was hunting through the available DBUS commands looking for something that would show the Desktop Grid, and I ended up having to scan through lists of crap like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;~ % qdbus org.kde.kwin /KWin                         
method Q_NOREPLY void org.kde.KWin.cascadeDesktop()
method void org.kde.KWin.circulateDesktopApplications()
method bool org.kde.KWin.compositingActive()
signal void org.kde.KWin.compositingToggled(bool active)
method int org.kde.KWin.currentDesktop()
method QList&amp;lt;int&amp;gt; org.kde.KWin.decorationSupportedColors()
method void org.kde.KWin.doNotManage(QString name)
method Q_NOREPLY void org.kde.KWin.killWindow()
method QStringList org.kde.KWin.listOfEffects()
method void org.kde.KWin.loadEffect(QString name)
method QStringList org.kde.KWin.loadedEffects()
method void org.kde.KWin.nextDesktop()
method void org.kde.KWin.previousDesktop()
method Q_NOREPLY void org.kde.KWin.reconfigure()
method void org.kde.KWin.reconfigureEffect(QString name)
method void org.kde.KWin.refresh()
signal void org.kde.KWin.reinitCompositing()
signal void org.kde.KWin.reloadConfig()
method bool org.kde.KWin.setCurrentDesktop(int desktop)
method void org.kde.KWin.showWindowMenuAt(qlonglong winId, int x, int y)
method Q_NOREPLY void org.kde.KWin.toggleCompositing()
method void org.kde.KWin.toggleEffect(QString name)
method Q_NOREPLY void org.kde.KWin.unclutterDesktop()
method void org.kde.KWin.unloadEffect(QString name)
method bool org.kde.KWin.waitForCompositingSetup()
method QDBusVariant org.freedesktop.DBus.Properties.Get(QString interface_name, QString property_name)
method QVariantMap org.freedesktop.DBus.Properties.GetAll(QString interface_name)
method void org.freedesktop.DBus.Properties.Set(QString interface_name, QString property_name, QDBusVariant value)
method QString org.freedesktop.DBus.Introspectable.Introspect()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is line noise to me.&lt;/p&gt;</description></item><item><title>gaka 0.2.0</title><link>http://briancarper.net/blog/562/gaka-020</link><guid>http://briancarper.net/blog/562/gaka-020</guid><pubDate>Thu, 29 Jul 2010 13:59:22 -0700</pubDate><description>&lt;p&gt;Per &lt;a href=&quot;http://briancarper.net/blog/543/introducing-gaka&quot;&gt;many commenters' suggestions&lt;/a&gt; and thanks to code from &lt;a href=&quot;http://github.com/purcell/&quot;&gt;Steve Purcell&lt;/a&gt;, you can now use maps for CSS attributes in &lt;a href=&quot;http://github.com/briancarper/gaka&quot;&gt;gaka&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: clojure&quot;&gt;user&amp;gt; (println (gaka/css [:a {:color :red}]))
a {
  color: red;}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This looks more like vanilla CSS thanks to the curlies, which is nice.   You just have to keep in mind that your key/value pairs could end up being printed in random order, and order is significant&lt;sup id=&quot;fnref:css&quot;&gt;&lt;a href=&quot;#fn:css&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; in CSS.&lt;/p&gt;

&lt;p&gt;It just so happens that maps are implemented in Clojure right now such that if they only have a few entries (16 key/value pairs), the order will be preserved, because you get a &lt;code&gt;PersistentArrayMap&lt;/code&gt; instead of a &lt;code&gt;PersistentHashMap&lt;/code&gt;.  But it's &lt;em&gt;highly dangerous&lt;/em&gt; to rely on such a thing.  It could change at any time in the future.&lt;/p&gt;

&lt;p&gt;In any case, you can also mix and match maps, lists and &quot;flat&quot; keyvals.  They'll all be flattened  That can help preserve attribute order in those cases where you need to.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: clojure&quot;&gt;user&amp;gt; (println (gaka/css [:a :color &quot;red&quot; {:padding 0} (list :margin 0)]))
a {
  color: red;
  padding: 0;
  margin: 0;}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I've also enhanced &quot;mixins&quot; a bit further.  You can now mixin entire tags as well as attributes.  Or a combination of both.  Say you want a mixin that means &quot;&lt;em&gt;Make my element have no padding, and make links within the element be red&lt;/em&gt;&quot;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: clojure&quot;&gt;user&amp;gt; (println (gaka/css [:div.foo mixin :margin 0]
                         [:div.bar mixin]))
div.foo {
  padding: 0;
  margin: 0;}

  div.foo a {
    color: red;}

div.bar {
  padding: 0;}

  div.bar a {
    color: red;}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can get gaka from &lt;a href=&quot;http://github.com/briancarper/gaka&quot;&gt;github&lt;/a&gt; or &lt;a href=&quot;http://clojars.org/gaka&quot;&gt;Clojars&lt;/a&gt;.&lt;/p&gt;&lt;div class=&quot;footnotes&quot;&gt;&lt;ol&gt;&lt;li id=&quot;fn:css&quot;&gt;&lt;p&gt;Order is only significant in cases where you're doing things like &lt;code&gt;padding: 0; padding-left: 1px&lt;/code&gt;.  This is arguably bad CSS style, but it's valid, and it's also possible you'll have this kind of thing if you're generating CSS procedurally.  But most of the time, order is not significant.  e.g. it doesn't matter if you set text color first and background color second, or vice versa.  So maybe this isn't so much of a problem in practice. &lt;a rev=&quot;footnote&quot; href=&quot;#fnref:css&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item><item><title>Footnotes</title><link>http://briancarper.net/blog/560/footnotes</link><guid>http://briancarper.net/blog/560/footnotes</guid><pubDate>Tue, 27 Jul 2010 12:30:57 -0700</pubDate><description>&lt;p&gt;Did you ever notice how footnotes make your writing seem more important&lt;sup id=&quot;fnref:important&quot;&gt;&lt;a href=&quot;#fn:important&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; somehow?&lt;/p&gt;

&lt;p&gt;Maybe one reason is that &quot;real&quot; books use footnotes.  At a glance, it looks like I have references&lt;sup id=&quot;fnref:refs&quot;&gt;&lt;a href=&quot;#fn:refs&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; backing up everything I say.  In reality, I don't, but the connotation carries through somehow&lt;sup id=&quot;fnref:telepathy&quot;&gt;&lt;a href=&quot;#fn:telepathy&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;.  Now my blog seems scholarly and authoritative.&lt;/p&gt;

&lt;p&gt;And if you're like me, you can't resist clicking footnotes to see what they refer to&lt;sup id=&quot;fnref:clickme&quot;&gt;&lt;a href=&quot;#fn:clickme&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;.  According to my estimates, by utilizing footnotes, in one fell swoop I have decreased my readers' average reading efficiency by 73%.&lt;/p&gt;

&lt;p&gt;In any case, I've added experimental, rudimentary support for footnotes to &lt;a href=&quot;http://github.com/briancarper/cow-blog&quot;&gt;cow-blog&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;I'm loosely copying the syntax from &lt;a href=&quot;http://michelf.com/projects/php-markdown/extra/&quot;&gt;Markdown Extra&lt;/a&gt; for this.  Markdown is great, except when it isn't.  The standard doesn't have support for some useful extensions.  I use &lt;a href=&quot;http://attacklab.net/showdown/&quot;&gt;Showdown&lt;/a&gt; for Markdown support, and I'm probably going to work on adding more features of Markdown Extra to Showdown in the near future.&lt;/p&gt;

&lt;p&gt;I just dread actually doing it.  Showdown (like Markdown itself) is implemented as a series of hackish regex transformations of blobs of text.  It's not a proper grammar.  Implementing more of Markdown Extra means more regex blobbing.  It's brittle and fragile and even getting incomplete support for footnotes was less than enjoyable.  But at the same time I find myself wanting to do things that Markdown can't so, so I may have to bite the bullet.&lt;/p&gt;

&lt;p&gt;(If there's a Showdown Extra out there already, drop me a URL.  It'd be most appreciated.  But I couldn't find one.)&lt;/p&gt;&lt;div class=&quot;footnotes&quot;&gt;&lt;ol&gt;&lt;li id=&quot;fn:important&quot;&gt;&lt;p&gt;In reality nothing I say is important. &lt;a rev=&quot;footnote&quot; href=&quot;#fnref:important&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li id=&quot;fn:refs&quot;&gt;&lt;p&gt;Does my inner dialog count as a reference? &lt;a rev=&quot;footnote&quot; href=&quot;#fnref:refs&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li id=&quot;fn:telepathy&quot;&gt;&lt;p&gt;Via telepathy. &lt;a rev=&quot;footnote&quot; href=&quot;#fnref:telepathy&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li id=&quot;fn:clickme&quot;&gt;&lt;p&gt;See? &lt;a rev=&quot;footnote&quot; href=&quot;#fnref:clickme&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item><item><title>Review: Surely You're Joking, Mr. Feynman!</title><link>http://briancarper.net/blog/559/review-surely-youre-joking-mr-feynman</link><guid>http://briancarper.net/blog/559/review-surely-youre-joking-mr-feynman</guid><pubDate>Mon, 26 Jul 2010 16:19:21 -0700</pubDate><description>&lt;p&gt;I'm probably the last person on earth to read &lt;em&gt;&quot;Surely You're Joking, Mr. Feynman!&quot;&lt;/em&gt;, a collection of stories and anecdotes from the life of Richard Feynman.  But better late than never.&lt;/p&gt;

&lt;p&gt;I'll keep this short.  Feynman was the kind of nerd every nerd wishes he was, in one way or another.  He was socially awkward.  He was blunt and tactless.  He felt out of place much of the time.  And it was surprising to see how often Feynman expressed feelings of inadequacy.  He wrote about being highly intimidated when talking in front of big names in physics, and jealous of the math abilities of some other people.&lt;/p&gt;

&lt;p&gt;But none of that stopped him from having an exciting life.  In fact he turned these traits to his advantage.  He had romantic success, often via very highly unconventional means (e.g. walking up to girls and asking them for sex outright; they often said yes).  His bluntness was seen as an admirable trait: where others might be intimidated by a famous physicist, Feynman would give his honest opinion, and that was often appreciated.&lt;/p&gt;

&lt;p&gt;And Feynman went far outside his comfort zone.  He did a stint in biology, even though he knew nothing of biology at the time.  He went to Brazil and joined a samba band.  He sold drawings and paintings for a while.  He played drums for a ballet.&lt;/p&gt;

&lt;p&gt;I picked up at least three lessons from this book.  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Try new things, even if you suck at them.  Life is boring if you stick to what you're good at.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Be intellectually honest.  Brutally so.  It's the only way to do good science, and arguably the only way to live a good life.  I've always believed this, and Feynman hammers the point home well.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Even the best and brightest of us feel insecure at times.  You shouldn't let it stop you.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On top of all of that, reading of Feynman's time at Los Alamos working on The Bomb was a fascinating piece of history.  I highly recommend this book.  &lt;/p&gt;

&lt;p&gt;And watch as much of &lt;a href=&quot;http://www.youtube.com/results?search_query=feynman&quot;&gt;Feynman on Youtube&lt;/a&gt; as you can find.  It never ceases to be fascinating.&lt;/p&gt;</description></item><item><title>Review: Logitech Performance MX</title><link>http://briancarper.net/blog/558/review-logitech-performance-mx</link><guid>http://briancarper.net/blog/558/review-logitech-performance-mx</guid><pubDate>Mon, 26 Jul 2010 13:51:27 -0700</pubDate><description>&lt;p&gt;I have a long list of companies I won't buy from, due to horrible customer service experiences or shoddy merchandise.  On the other hand, my &quot;Must buy from this company&quot; list is awfully short.  &lt;/p&gt;

&lt;p&gt;Logitech is one company I'm generally OK buying from.  (For now...)  I go through computer mouses&lt;sup id=&quot;fnref:mouses&quot;&gt;&lt;a href=&quot;#fn:mouses&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; pretty fast, so I end up buying a new one every 4-5 years.  Logitech hasn't failed me thus far.&lt;/p&gt;

&lt;p&gt;In my opinion, the most important parts of your computer are the ones you interact with: Keyboard, mouse, monitor.  I'd rather have a slow computer with a good mouse and keyboard than a fast computer with cheap peripherals.  I already have a &lt;a href=&quot;http://briancarper.net/blog/447/unicomp-customizer-keyboard-review&quot;&gt;wonderful keyboard&lt;/a&gt;, and I like to have a nice mouse to match.&lt;/p&gt;

&lt;p&gt;My latest mouse is the &lt;a href=&quot;http://www.logitech.com/en-us/mice-pointers/mice/devices/5845&quot;&gt;Logitech Performance MX&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/random/performance-mx.png&quot; alt=&quot;Logitech Performance MX&quot; title=&quot;&quot; /&gt;&lt;/p&gt;

&lt;!--more Read the whole review --&gt;

&lt;p&gt;How much can you really improve upon the concept of a mouse?  It's a round thing you slide around and click.  Well, if you believe the marketing on the box, it seems there are at least three areas for improvement:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add more buttons.&lt;/li&gt;
&lt;li&gt;Make it work on more surfaces.&lt;/li&gt;
&lt;li&gt;Gimmicks.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of the above features matter much to me.  What I care about:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is it comfortable to use all day?&lt;/li&gt;
&lt;li&gt;Is it going to last me 4 or 5 years?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's hit each of these points.&lt;/p&gt;

&lt;h1&gt;More buttons&lt;/h1&gt;

&lt;p&gt;The Performance MX has a lot of buttons.  If you believe &lt;code&gt;xev&lt;/code&gt;, there are somewhere between 10 and 13 (counting the scroll wheel etc.).  &lt;/p&gt;

&lt;p&gt;I don't need all of these.  I like to have a thumb button for middle-clicking, but this mouse has four of them.  What am I going to use all of the extras for?  Maybe I'll have one open Emacs.&lt;/p&gt;

&lt;p&gt;The browser forward and back thumb buttons work out-of-the-box in Linux, which surprised me.  I'm used to having to dork around with &lt;code&gt;xmodmap&lt;/code&gt; or &lt;code&gt;xbindkeys&lt;/code&gt;.  Linux has come a long way.  &lt;/p&gt;

&lt;p&gt;Then there's a thumb button that's supposed to open Expose on OS X or your app-switcher of choice in your OS.  It's in a place that's impossible to press consistently with your thumb, unless you're a contortionist.  And it does nothing in Linux by default.  Similarly there's a vanishingly small &quot;zoom&quot; button near your thumb.  I can't even find this button without looking at the mouse, because it's too small.&lt;/p&gt;

&lt;p&gt;There's also horizontal scroll, if you can manage to tilt the wheel to either side.  My fingers lack the dexterity to do this easily, and the button is awfully stiff, so I'll never use this.&lt;/p&gt;

&lt;p&gt;But hey, better too many buttons than too few.&lt;/p&gt;

&lt;h1&gt;Surfaces&lt;/h1&gt;

&lt;p&gt;The marketers wrote &quot;This mouse works on glass!&quot; all over the box, so this must be a selling point of the mouse.  But my Logitech G500 also worked on glass, once I upgraded the firmware (via Logitech's own website), so I'm not sure why this feature is being pushed so hard.&lt;/p&gt;

&lt;h1&gt;Gimmicks&lt;/h1&gt;

&lt;p&gt;On the Performance MX, you can click this little switch and disengage part of the mechanism that makes the scroll wheel &quot;click&quot;.  This lets you spin the wheel hard and it'll spin freely forever until you stop it manually, or until its inertia runs out.&lt;/p&gt;

&lt;p&gt;Do I really need, and I quote, &lt;strong&gt;hyper-fast scrolling&lt;/strong&gt;?  The scroll speed of my mouse wheel has never struck me as a productivity bottleneck.  Now that I've played with it, sure, it's mildly interesting.  If you scroll at just the right speed, you can go all the way from the top of a Reddit thread to the bottom, while still skimming the text.  But I don't need this feature.&lt;/p&gt;

&lt;p&gt;But the levels to which marketroids will stoop to hype up a product never ceases to amaze me.  The name itself is ridiculous.  &lt;em&gt;Performance MX.&lt;/em&gt;  Who comes up with this?&lt;/p&gt;

&lt;h1&gt;Comfort&lt;/h1&gt;

&lt;p&gt;My previous mouse was a G500, and it was really quite big.  A bit too big.  (And there were these removable weights you could use to adjust the weight of the mouse (the &quot;gimmick&quot; feature of that mouse), which were worthless.)&lt;/p&gt;

&lt;p&gt;The MX is bigger, but it has more curves and that helps my hand sit on it better.  There's a very large thumb rest, which I like.  If you have small hands, you might have problems with this mouse.  I like the feel so far.&lt;/p&gt;

&lt;h1&gt;Will it last?&lt;/h1&gt;

&lt;p&gt;This mouse feels very solid.  It has a nice heft to it.    It has metal bits (or sturdy metal-like plastic) in places other mouses have cheap plastic and rubber.&lt;/p&gt;

&lt;p&gt;The wheel on my G500 wore down very fast.  I was some kind of rubbery plastic, which became rounded off, nicked and worn-down a lot over the years.   The wheel on the MX feels like some kind of metal, with nice ridges on the top to provide friction.  I'm a bit concerned that the wheel disengagement switch might wear down over time though.  The more moving parts, the more opportunity for something to break.&lt;/p&gt;

&lt;p&gt;The pads on the bottom are huge: a good 1 inch x 1/8 inch.  I love this.  Using this on my Icemat mouse pad is very comfy.  It slides effortlessly, but leaves me with plenty of control.&lt;/p&gt;

&lt;h1&gt;Battery&lt;/h1&gt;

&lt;p&gt;I normally prefer corded mouses.  This one is rechargeable.  Most rechargeable mouses I've used had some kind of stupid dock you had to jam the mouse into.  Not only does it take up desk space, it also wears holes into your mouse over time from being inserted and removed from the dock.  The battery connectors also wear down fast, and then it doesn't charge right unless you fiddle with it.&lt;/p&gt;

&lt;p&gt;The MX can be charged while you use it, via a USB cable, which is a really good idea.  It comes with a short cable, and a long extender cable if you need it.  The cable looks like it has a non-standard connector though, which is a bad idea.  Why not use mini-USB?&lt;/p&gt;

&lt;p&gt;The charger cable is awfully heavy though.  I wouldn't want to use this thing while it's plugged in for more than a short time.&lt;/p&gt;

&lt;p&gt;I don't know what the battery life is like, because it hasn't run out yet, after a couple days.  That's good enough for me.&lt;/p&gt;

&lt;h1&gt;Price&lt;/h1&gt;

&lt;p&gt;$120.  That's a lot.  But taken over 4-5 years, it's not that bad.&lt;/p&gt;

&lt;p&gt;And the surgery I'd have to have done on my hands after crippling them via a cheap mouse over the next 40 years would be way more than $120.&lt;/p&gt;

&lt;h1&gt;Should you buy this?&lt;/h1&gt;

&lt;p&gt;Sure.  I like this mouse so far.  It works, and it feels like it'll last a while.  Props to Logitech for making good products.&lt;/p&gt;&lt;div class=&quot;footnotes&quot;&gt;&lt;ol&gt;&lt;li id=&quot;fn:mouses&quot;&gt;&lt;p&gt;Yes, &lt;a href=&quot;http://en.wikipedia.org/wiki/Mouse_%2528computing%2529#Naming&quot;&gt;mouses&lt;/a&gt;. &lt;a rev=&quot;footnote&quot; href=&quot;#fnref:mouses&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item><item><title>Clojure syntax highlighting via SyntaxHighlighter</title><link>http://briancarper.net/blog/556/clojure-syntax-highlighting-via-syntaxhighlighter</link><guid>http://briancarper.net/blog/556/clojure-syntax-highlighting-via-syntaxhighlighter</guid><pubDate>Wed, 21 Jul 2010 15:17:42 -0700</pubDate><description>&lt;p&gt;How do you syntax-highlight Clojure code for display on a website?   The best way I can find is &lt;a href=&quot;http://alexgorbatchev.com/SyntaxHighlighter/&quot;&gt;SyntaxHighlighter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Daniel Gómez wrote a &lt;a href=&quot;http://www.deepbluelambda.org/programs/sh-clojure/new-clojure-brush-for-syntaxhighlighter&quot;&gt;brush&lt;/a&gt; to give SyntaxHighlighter Clojure support.  I &lt;a href=&quot;http://github.com/briancarper/cow-blog/blob/master/public/js/brushes/shBrushClojure.js&quot;&gt;tweaked it&lt;/a&gt; a bit myself and integrated it into cow-blog.  I also converted my &lt;a href=&quot;http://github.com/briancarper/dotfiles/blob/master/.vim/colors/gentooish.vim&quot;&gt;favorite color scheme&lt;/a&gt; to a &lt;a href=&quot;http://github.com/briancarper/cow-blog/blob/master/public/css/shThemeCow.css&quot;&gt;SyntaxHighlighter theme&lt;/a&gt;.  So when I write this code:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: clojure&quot;&gt;(defn- ip
  &quot;Given a request, return the IP.  Looks for an x-forwarded-for
  header, falls back to :remote-addr on the request.&quot;
  [request]
  (or (get-in request [:headers &quot;x-forwarded-for&quot;])
      (request :remote-addr)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/clojure/syntax-highlight.png&quot; alt=&quot;Syntax highlighting example&quot; title=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;...unless you're reading this via RSS, or in a browser without Javascript enabled, in which case you'll see plain, depressing black and white.  But that's one nice thing about SyntaxHighlighter.  It degrades nicely.&lt;/p&gt;

&lt;p&gt;One bad thing about SyntaxHighlighter is that it doesn't play nicely with Markdown.  Or rather, Markdown isn't powerful enough to let you specify the class of any markdown-generated HTML tags.  If you want the &lt;code&gt;&amp;lt;pre class=&quot;brush: clojure&quot;&amp;gt;&lt;/code&gt; that SyntaxHighlighter requires, you have to write out the HTML by hand.  But I hacked Showdown a bit to let me specify classes more easily, so I can avoid having to do that.&lt;/p&gt;

&lt;p&gt;The code for all of this is &lt;a href=&quot;http://github.com/briancarper/cow-blog&quot;&gt;on github&lt;/a&gt; with the rest of my blog.&lt;/p&gt;</description></item><item><title>ANTLR via Clojure</title><link>http://briancarper.net/blog/554/antlr-via-clojure</link><guid>http://briancarper.net/blog/554/antlr-via-clojure</guid><pubDate>Fri, 16 Jul 2010 17:41:04 -0700</pubDate><description>&lt;p&gt;&lt;a href=&quot;http://www.antlr.org/&quot;&gt;ANTLR&lt;/a&gt; is a parser-generator for Java.  Can you use it from Clojure?  Sure.  Would you want to?  Maybe.&lt;/p&gt;

&lt;p&gt;Here's how to do it, start to finish.&lt;/p&gt;

&lt;p&gt;For the impatient among you, all of the code below is on &lt;a href=&quot;http://github.com/briancarper/clojure-antlr-example&quot;&gt;github&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git clone git://github.com/briancarper/clojure-antlr-example.git
&lt;/code&gt;&lt;/pre&gt;

&lt;!--more Grammars, grammars, everywhere --&gt;

&lt;h1&gt;Setup&lt;/h1&gt;

&lt;p&gt;I'm going to use leiningen for this project.  Let's make a new project called &lt;code&gt;antlr-example&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ lein new antlr-example
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now edit &lt;code&gt;project.clj&lt;/code&gt; to tell lein to fetch ANTLR (and Swank, since I use Emacs).  ANTLR is available in Maven Central, so leiningen can grab it for us.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defproject antlr-example &quot;1.0.0-SNAPSHOT&quot;
  :description &quot;ANTLR Clojure example&quot;
  :dependencies [[org.clojure/clojure &quot;1.2.0-beta1&quot;]
                 [org.clojure/clojure-contrib &quot;1.2.0-beta1&quot;]
                 [org.antlr/antlr &quot;3.2&quot;]]
  :dev-dependencies [[swank-clojure &quot;1.3.0-SNAPSHOT&quot;]])
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then a simple &lt;code&gt;lein deps&lt;/code&gt; will download all of the jars and all of ANTLR's dependencies for you.  Handy.  You end up with this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;antlr-example
├── classes
├── lib
│   ├── antlr-2.7.7.jar
│   ├── antlr-3.2.jar
│   ├── antlr-runtime-3.2.jar
│   ├── clojure-1.2.0-beta1.jar
│   ├── clojure-contrib-1.2.0-beta1.jar
│   ├── stringtemplate-3.2.jar
│   └── swank-clojure-1.3.0-20100502.112537-1.jar
├── project.clj
├── README
├── src
│   └── antlr_example
│       └── core.clj
└── test
    └── antlr_example
        └── core_test.clj
&lt;/code&gt;&lt;/pre&gt;

&lt;h1&gt;Interactive development?  Kind of...&lt;/h1&gt;

&lt;p&gt;One weakness of ANTLR via Clojure is that development is no longer REPL-based.  The ANTLR workflow is essentially a Java workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write a grammar&lt;/li&gt;
&lt;li&gt;Compile the grammar into Java source code&lt;/li&gt;
&lt;li&gt;Compile the Java source into Java .class files&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Until and unless someone writes a Clojure backend for ANTLR, so that ANTLR can directly produce Clojure source code (and it seems like it should be possible to do so), you're back to a write/compile/debug cycle.  Joy!&lt;/p&gt;

&lt;p&gt;This also means restarting your REPL every time you alter and recompile your grammar.&lt;/p&gt;

&lt;p&gt;But the good thing is that there's &lt;a href=&quot;http://antlr.org/works/index.html&quot;&gt;ANTLR Works&lt;/a&gt;, a free GUI for writing ANTLR grammars.  ANTLR Works has an interactive interpreter, which is nice, and it has a compiler/debugger, which is better.  These let you test your grammar as you write it, by trying inputs and seeing the resulting AST in graphical form, which is as good as you could hope for.  This is actually even a bit nicer than a plaintext REPL.  &lt;/p&gt;

&lt;p&gt;Plus, it has a nice editor for ANTLR code.  Emacs was freaking out over the indentation on a few grammars I tried.&lt;/p&gt;

&lt;p&gt;So a decent workflow might be to write and debug your grammar in ANTLR Works, then fire up Clojure afterwards to consume the parser.&lt;/p&gt;

&lt;h1&gt;A simple grammar&lt;/h1&gt;

&lt;p&gt;We're going to use a classic textbook example, simple arithmetic expressions, as a proof of concept.&lt;/p&gt;

&lt;p&gt;For Java (hence Clojure) to find this code, it has to be named properly and it has to be put into the proper directory on &lt;code&gt;CLASSPATH&lt;/code&gt;.  I'm going to create the grammar file &lt;code&gt;src/antlr_example/Expr.g&lt;/code&gt;.  (My grammar file, Java source, and Clojure source will all be jumbled together in &lt;code&gt;src&lt;/code&gt;.   You can easily do it differently if this offends your sensibilities.)&lt;/p&gt;

&lt;p&gt;The first line in the grammar names the grammar (and the classes we'll consume from Clojure):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;grammar Expr;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Clojure being a s-exp based language, it might be nice to have ANTLR generate an AST.  ANTLR has good support for this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;options {
    output=AST;
    ASTLabelType=CommonTree;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Helper tokens for the grammar:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;tokens {
    PLUS = '+';
    MINUS = '-';
    MULT = '*';
    DIV = '/';
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These next lines are important.  We want to generate classes &lt;code&gt;antlr_example.ExprLexer&lt;/code&gt; and &lt;code&gt;antlr_example.ExprParser&lt;/code&gt;, so we have to set our code up in the proper package, &lt;code&gt;antlr_example&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;This code includes both a parser and lexer, so you have to set the package for both in ANTLR.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@header        {package antlr_example;}
@lexer::header {package antlr_example;}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And then the grammar itself, which is simple:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;expr: term ((PLUS | MINUS)^ term)* ;
term: factor ((MULT | DIV)^ factor)* ;
factor: INT ;

INT :   '0'..'9'+ ;
WS  :   ( ' ' | '\t' | '\r' | '\n')+ {$channel=HIDDEN;} ;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;One thing to note is &lt;code&gt;(PLUS | MINUS)^&lt;/code&gt;; the &lt;code&gt;^&lt;/code&gt; here tells ANTLR to treat &lt;code&gt;(PLUS | MINUS)&lt;/code&gt; as the parent of the node created for this rule.  This means the &lt;code&gt;term&lt;/code&gt; on either side will be children of this node.  We do the same for &lt;code&gt;MULT&lt;/code&gt; and &lt;code&gt;DIV&lt;/code&gt;.  This will give us a nice tree.  Otherwise you end up with a flat list of tokens.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{$channel=HIDDEN;}&lt;/code&gt; for the whitespace rule tells ANTLR to ignore whitespace, also useful.&lt;/p&gt;

&lt;p&gt;If you use ANTLR Works with this grammar, on the input &lt;code&gt;1 + 2 * 3 + 4&lt;/code&gt;, you can see that it works OK.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/random/antlr.png&quot; alt=&quot;ANTLR&quot; title=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That was an awful lot of boilerplate and setup and ugly syntax though.  See how much Clojure spoils you?  But for a simple grammar, it's not that much code.&lt;/p&gt;

&lt;p&gt;For a longer or more complex grammar, you might end up having to embed inline Java code into your ANTLR grammar.  But again, that's not the end of the world.&lt;/p&gt;

&lt;h1&gt;Compile everything&lt;/h1&gt;

&lt;p&gt;Once you write your grammar (presumably in ANTLR Works), you can generate the Java code and compile it thusly (run from your project's base directory):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ java -cp 'lib/*' org.antlr.Tool src/antlr_example/Expr.g
$ javac -cp 'lib/*' -d classes src/antlr_example/Expr{Lexer,Parser}.java
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The first command should generate &lt;code&gt;src/antlr_example/ExprLexer.java&lt;/code&gt; and &lt;code&gt;src/antlr_example/ExprParser.java&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The second command should spew tons of class files into &lt;code&gt;classes/&lt;/code&gt;.  Leiningen and other tools generally include &lt;code&gt;classes/&lt;/code&gt; on your &lt;code&gt;CLASSPATH&lt;/code&gt;, so that's a good place for them.  Again putting them here is a fairly arbitrary decision on my part.  You can put the source and class files anywhere, as long as the class files end up on your &lt;code&gt;CLASSPATH&lt;/code&gt; when you start Clojure.&lt;/p&gt;

&lt;p&gt;If you're really so lazy that you can't run these two commands, you could use ANTLR Works' built-in commands for compiling your grammar.  The only way I could find to invoke it was by starting a Debug session, which compiled my code as a side-effect.  And it spews files into places I don't want them, so I like the command line version better.&lt;/p&gt;

&lt;p&gt;You could probably also set up a leiningen task for this if you're re-running these commands a lot, or configure your build tool of choice to do the same.  I didn't bother.&lt;/p&gt;

&lt;p&gt;Now (re)start your REPL and let's write some Clojure.&lt;/p&gt;

&lt;h1&gt;Clojure code&lt;/h1&gt;

&lt;p&gt;It's pretty easy to consume an ANTLR parser from Clojure.  I'm putting the code below into &lt;code&gt;src/antlr_example/core.clj&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;First import the classes.  You probably need some ANTLR helper classes to set up the parser; you also need the classes you just generated.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(ns antlr-example.core
  (:import (org.antlr.runtime ANTLRStringStream
                              CommonTokenStream)
           (antlr_example ExprLexer ExprParser)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here's a function to parse a string using our new parser class:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defn parse-expr [s]
  (let [lexer (ExprLexer. (ANTLRStringStream. s))
        tokens (CommonTokenStream. lexer)
        parser (ExprParser. tokens)]
    (.expr parser)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;.expr&lt;/code&gt; is the name of the top-level rule we want to invoke from our grammar.  The rest is boilerplate; just plug in the proper class names.&lt;/p&gt;

&lt;p&gt;So let's see what we've got.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;user&amp;gt; (in-ns 'antlr-example.core)
#&amp;lt;Namespace antlr-example.core&amp;gt;
antlr-example.core&amp;gt; (parse-expr &quot;1 + 2 * 3 + 4&quot;)
#&amp;lt;expr_return antlr_example.ExprParser$expr_return@3755e508&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Er, OK.  A good way to inspect Java objects is via &lt;code&gt;bean&lt;/code&gt;, so let's view the guts of this object:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;antlr-example.core&amp;gt; (bean *1)
{:tree #&amp;lt;CommonTree +&amp;gt;,
 :template nil,
 :stop #&amp;lt;CommonToken [@12,12:12='4',&amp;lt;8&amp;gt;,1:12]&amp;gt;,
 :start #&amp;lt;CommonToken [@0,0:0='1',&amp;lt;8&amp;gt;,1:0]&amp;gt;,
 :class antlr_example.ExprParser$expr_return}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I see.  We set up our grammar above to generate an AST, so &lt;code&gt;:tree&lt;/code&gt; on the bean will give us that.  This translates to &lt;code&gt;.getTree&lt;/code&gt; on the Java object.  So we can edit our function to call this for us, since we always want to have the tree.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defn parse-expr [s]
  (let [lexer (ExprLexer. (ANTLRStringStream. s))
        tokens (CommonTokenStream. lexer)
        parser (ExprParser. tokens)]
    (.getTree (.expr parser))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;antlr-example.core&amp;gt; (parse-expr &quot;1 + 2 * 3 + 4&quot;)
#&amp;lt;CommonTree +&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;OK, it appears we have one node of the tree, the root node.  Let's peak inside:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;antlr-example.core&amp;gt; (bean *1)
{:children #&amp;lt;ArrayList [+, 4]&amp;gt;,
 :childIndex -1,
 :parent nil,
 :text &quot;+&quot;,
 :nil false,
 :token #&amp;lt;CommonToken [@10,10:10='+',&amp;lt;4&amp;gt;,1:10]&amp;gt;,
 :class org.antlr.runtime.tree.CommonTree,
 :ancestors nil,
 :tokenStartIndex 0,
 :type 4,
 :childCount 2,
 :charPositionInLine 10,
 :tokenStopIndex 12,
 :line 1}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Looks like our children are in &lt;code&gt;:children&lt;/code&gt; on the bean, which translates to &lt;code&gt;.getChildren&lt;/code&gt; on the Java object.  And we have &lt;code&gt;.getChildCount&lt;/code&gt; to count the children, and &lt;code&gt;.getText&lt;/code&gt; to get the text of the current node.  (We could've learned all of this by reading the javadocs for ANTLR too, but what fun is that?)&lt;/p&gt;

&lt;p&gt;Since we're dealing with a tree, we can use &lt;code&gt;tree-seq&lt;/code&gt; in Clojure to get a flat list of all the tokens in our text.  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;tree-seq&lt;/code&gt; takes three arguments.  First a function that returns true if the node has children, false otherwise.  Second a function that returns the children for a node that has children.  Third the root node of our tree.&lt;/p&gt;

&lt;p&gt;That'll give us a seq of tree nodes.  So finally we call &lt;code&gt;.getText&lt;/code&gt; on all the resulting nodes in the list, to turn node objects into strings.&lt;/p&gt;

&lt;p&gt;Easy enough:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defn node-seq [x]
  (map #(.getText %)
   (tree-seq #(not (zero? (.getChildCount %)))
             #(.getChildren %)
             x)))

antlr-example.core&amp;gt; (node-seq (parse-expr &quot;1 + 2 * 3 + 4&quot;))
(&quot;+&quot; &quot;+&quot; &quot;1&quot; &quot;*&quot; &quot;2&quot; &quot;3&quot; &quot;4&quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But that's no good.  We lost our tree structure.  &lt;/p&gt;

&lt;p&gt;We'd rather have something like nested vectors or lists.  It's easy enough to roll something by hand.  This should do it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defn AST [node]
  (if (zero? (.getChildCount node))
    (.getText node)
    (let [children (map AST (.getChildren node))
          txt (.getText node)]
      (if txt
        (cons txt children)
        children))))

antlr-example.core&amp;gt; (AST (parse-expr &quot;1 + 2 * 3 + 4&quot;))
(&quot;+&quot; (&quot;+&quot; &quot;1&quot; (&quot;*&quot; &quot;2&quot; &quot;3&quot;)) &quot;4&quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That's better, but it's a list of strings.  These strings all happen to be literal representations of Clojure objects, so a call to &lt;code&gt;read-string&lt;/code&gt; in the proper places should give us something we can work with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defn AST [node]
  (if (zero? (.getChildCount node))
    (read-string (.getText node))
    (let [children (map AST (.getChildren node))
          txt (read-string (.getText node))]
      (if txt
        (apply list txt children)
        children))))

antlr-example.core&amp;gt; (AST (parse-expr &quot;1 + 2 * 3 + 4&quot;))
(+ (+ 1 (* 2 3)) 4)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Hey look, now we have something we can evaluate.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;antlr-example.core&amp;gt; (eval *1)
11
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Yeah I kind of planned that ahead.  If you had a more complex grammar, you might not get away with something quite this easy.&lt;/p&gt;

&lt;h1&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;The advantage of ANTLR is that it's mature, widely used, actively developed, and well-documented.  (There's a whole book about ANTLR, &lt;em&gt;The Definitive ANTLR Reference&lt;/em&gt; by Terence Parr.)  There's also a lot of tooling available for it, not just ANTLR Works, but plugins for other Java IDEs.&lt;/p&gt;

&lt;p&gt;The disadvantage is that it's a Java library, and as always, there will be some friction when consuming it from Clojure.  But it's not that bad.&lt;/p&gt;

&lt;p&gt;For pure-Clojure parser generator alternatives, there are &lt;a href=&quot;http://github.com/joshua-choi/fnparse&quot;&gt;fnparse&lt;/a&gt; and &lt;a href=&quot;http://github.com/cypher/clojure-pg&quot;&gt;clojure-pg&lt;/a&gt;, neither of which I've tried much.&lt;/p&gt;</description></item><item><title>Clementine: A triumph of Free Software</title><link>http://briancarper.net/blog/553/clementine-a-triumph-of-free-software</link><guid>http://briancarper.net/blog/553/clementine-a-triumph-of-free-software</guid><pubDate>Tue, 13 Jul 2010 11:48:51 -0700</pubDate><description>&lt;p&gt;Ages ago, in the long-forgotten days of 2008, there was Amarok 1.4.  And it was good.  Then KDE4 came along and Amarok was rewritten, reshaped, becoming something... different.  Something unsettling.  Something &lt;a href=&quot;http://briancarper.net/blog/463/songbird-vs-amarok-how-not-to-design-a-gui&quot;&gt;not&lt;/a&gt; &lt;a href=&quot;http://briancarper.net/blog/516/exaile-the-best-amarok-since-amarok-14&quot;&gt;altogether&lt;/a&gt; &lt;a href=&quot;http://briancarper.net/blog/494/amarok-22-disber-grogth-grocks&quot;&gt;pleasant&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Fear not.  Today we have &lt;a href=&quot;http://www.clementine-player.org/&quot;&gt;Clementine&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/random/clementine-0.4.png&quot;&gt;&lt;img src=&quot;/random/thumbs/clementine-0.4.png&quot; alt=&quot;Clementine&quot; title=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I consider Clementine a triumph of Free Software.  A great project fell off the rails, so someone else picked up the pieces, forked it and kept the spirit alive.&lt;/p&gt;

&lt;!--more Gushing praise follows--&gt;

&lt;h1&gt;Features present&lt;/h1&gt;

&lt;p&gt;Clementine embodies everything good about Amarok 1.4, in a shiny Qt4 package.  The layout is eminently pleasant to use.  It uses the classic &quot;spreadsheet&quot; playlist view that saw so much success in Amarok 1.4.  If you care about cramming as much information about your music as possible onto the screen, this is as good as it gets.  It's boring, and that's a good thing.  It gets the job done.&lt;/p&gt;

&lt;p&gt;Like Amaork, 1.4, in Clementine you can very quickly drill into your music collection, filter it, view recently added tracks, group songs by artist or album or year or genre or a combination of those things.  Clementine also handles all of the edge cases correctly: it lists albums with Various Artists exactly how I'd want (exactly like Amarok 1.4).  It correctly handles songs with non-Latin tag text.&lt;/p&gt;

&lt;p&gt;Clementine detects additions and changes to my music collection instantly, without the massive scan-lags on startup that plague some other music players.  Clementine doesn't bat an eye at my 7,000 song collection.  There's no MySQL integration, but I don't need it.  Clementine's SQLite backend supposedly handles 300k songs without much problem, which is good enough for me.&lt;/p&gt;

&lt;p&gt;Clementine has Last.FM integration.  It has three different styles of desktop notification.  It has visualizations.  It handles USB devices.  It understands reply gain.  It has cross-fading.  It has an equalizer.  It has a transcoder.  It has a cover manager.&lt;/p&gt;

&lt;p&gt;I'm tired of listing features.  Let's just say it has every &lt;em&gt;useful&lt;/em&gt; feature you'd ever want.  And if you don't need a feature, it stays out of your way.&lt;/p&gt;

&lt;p&gt;And for a program under such active development, it's rock solid.  I have yet to see a crash.  And speaking of active development, if you follow the activity in Clementine's SVN repo, you will find that this program is updated almost daily.  How the devs find the time, I don't know, but I'm grateful.  This program has gone from non-existent to awesome in record time.&lt;/p&gt;

&lt;p&gt;Clementine can use gstreamer, so it even works cross-platform.  I fired it up on Windows 7 the other day and I was amazed at how good it looked and felt.  It supposedly also works on OS X.&lt;/p&gt;

&lt;p&gt;Clementine doesn't cook your breakfast for you, but that might be in the works.&lt;/p&gt;

&lt;h1&gt;How to make a good UI&lt;/h1&gt;

&lt;p&gt;A perfect example of the polish of Clementine's UI: Tagging.  How do you tag a whole album worth of music at once?  You can select some songs and right click and go into a dialog, like most music players allow.  &lt;/p&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Edit a tag for a single song (inline) by clicking the field.  Let's say you edit &lt;em&gt;Artist&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Select multiple songs in your playlist.  (Click and drag, CTRL-click, Shift-click, CTRL-A, whatever.)&lt;/li&gt;
&lt;li&gt;Right click the &lt;em&gt;Artist&lt;/em&gt; tag in the song you edited, select &lt;em&gt;Set Artist to &quot;XXXXX&quot;&lt;/em&gt;, and now all the songs you selected will be updated.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/random/clementine-0.4_2.png&quot; alt=&quot;Clementine&quot; title=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is the kind of UI innovation that I like.  It's simple, it's useful, and it's predictable.  You can get things done without going through dialog windows, without a million clicks, without spending a minute scratching your head figuring things out.&lt;/p&gt;

&lt;p&gt;(Meanwhile Amarok 2 is busy getting rid of the Stop button and making the volume control circular.)&lt;/p&gt;

&lt;h1&gt;Features missing&lt;/h1&gt;

&lt;p&gt;Admittedly, Clementine is missing a couple of features I wouldn't mind having.  You can't skin or theme Clementine.  You can't rate songs.  You can't display song lyrics.  You can't &quot;queue&quot; songs.  But oh well.  I can live without these features because the rest of the program is so darned good.   For all I know, these features might pop up next week.  I wouldn't be surprised.&lt;/p&gt;

&lt;p&gt;The Clementine devs seem to be very friendly and responsive to feature requests and feedback, which is also great.&lt;/p&gt;

&lt;p&gt;Clementine is also missing a few features/bloat that I'm glad to see NOT ported from Amarok.  Wikipedia integration?  Good riddance.&lt;/p&gt;

&lt;h1&gt;I would pay money for this program.&lt;/h1&gt;

&lt;p&gt;In November 2009 I had &lt;a href=&quot;http://briancarper.net/blog/494/amarok-22-disber-grogth-grocks&quot;&gt;this to say&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;(Anyone out there reading this, if you port Amarok 1.4 to Qt4 intact, I will pay you. Seriously. I will pay you money.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The offer still stands.  I will pay money for Clementine.  I'm &lt;a href=&quot;http://groups.google.com/group/clementine-player/browse_frm/thread/e04fc078e80724f0/7b32edc7ece2f762&quot;&gt;still waiting&lt;/a&gt; for a Donate link so I can do so.  (Clementine devs, are you reading this?)&lt;/p&gt;

&lt;p&gt;Why do I care about this so much?  Because I have music playing whenever I'm using this computer, and when you add up work plus free time, I'm at this computer 8-10 hours per day.  Music keeps me sane during multi-hour debug sessions.  Music is an integral part of my life, and a music app is an integral part of playing music.&lt;/p&gt;

&lt;p&gt;It's very important to me that the programs and tools I use all day are comfortable.  Otherwise I become cranky.  If you were a carpenter, would you want to use a hammer with a wobbly handle all day?  I'm a programmer, and I want to use comfortable computer programs.&lt;/p&gt;

&lt;p&gt;Clementine is very comfortable.&lt;/p&gt;</description></item></channel></rss>
