<?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>Clojure, SLIME, ODBC, SQL Server</title><link>http://briancarper.net/blog/clojure-slime-odbc-sql-server</link><guid>http://briancarper.net/blog/clojure-slime-odbc-sql-server</guid><pubDate>Fri, 26 Jun 2009 11:27:22 -0700</pubDate><description>&lt;p&gt;I had a lot of trouble connecting to an MS SQL Server at work via Clojure.  Java 6 comes with a JDBC-ODBC bridge which worked fine from a Clojure REPL at a command prompt, or from inferior-lisp in Emacs, but in SLIME it would hang every time I tried to connect and I'd have to kill Java.  Couldn't for the life of me figure out why.&lt;/p&gt;

&lt;p&gt;I got it to work eventually by using Microsoft's own JDBC driver, which you can download &lt;a href=&quot;http://msdn.microsoft.com/en-us/data/aa937724.aspx&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you put the downloaded .jar file on your &lt;code&gt;CLASSPATH&lt;/code&gt; (in my case, &lt;code&gt;sqljdbc4.jar&lt;/code&gt;) you can connect like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;user&amp;gt; (def db {:classname &quot;com.microsoft.sqlserver.jdbc.SQLServerDriver&quot;
               :subprotocol &quot;sqlserver&quot;
               :subname &quot;//server_hostname;database=SomeDatabase;user=SomeUser;password=SomePassword&quot;})
#'user/db
user&amp;gt; (use 'clojure.contrib.sql)
nil
user&amp;gt; (with-connection db 
        (with-query-results rs [&quot;SELECT * FROM whatever&quot;] (prn rs)))
... results ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Posted for the sake of Googlebot and for my own future sanity.&lt;/p&gt;</description></item><item><title>Five Things that Mildly Annoy Me in Clojure</title><link>http://briancarper.net/blog/five-things-that-mildly-annoy-me-in-clojure</link><guid>http://briancarper.net/blog/five-things-that-mildly-annoy-me-in-clojure</guid><pubDate>Tue, 16 Jun 2009 21:56:21 -0700</pubDate><description>&lt;p&gt;This &lt;a href=&quot;http://use.perl.org/~brian_d_foy/journal/32556&quot;&gt;infamous blog post&lt;/a&gt; suggests that someone familiar with a language should be able to name five things they hate about it.  &quot;Hate&quot; is a strong word, but I decided to think of five things I find mildyly annoying about Clojure, my favorite language of the moment.&lt;/p&gt;

&lt;h1&gt;Hashing integers&lt;/h1&gt;

&lt;p&gt;Clojure automatically converts integers between &lt;code&gt;Integer&lt;/code&gt;, &lt;code&gt;Long&lt;/code&gt; and &lt;code&gt;BigInteger&lt;/code&gt; as needed to prevent overflow.  This is good.  Integers of the various classes test as equal too.  This is also good.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;user&amp;gt; (= 123 (int 123) (long 123) (bigint 123))
true
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So would you expect this?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;user&amp;gt; (hash-map (int 123) :foo (long 123) :bar (bigint 123) :baz)
{123 :foo, 123 :bar, 123 :baz}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Yes, each of the integer classes, though equal via &lt;code&gt;=&lt;/code&gt;, do not have the same hash value when put into a hash-map.  This is because:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;user&amp;gt; (.equals (int 123) (long 123))
false
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is a wart inherited from the JVM.  See &lt;a href=&quot;http://groups.google.com/group/clojure/browse_thread/thread/da8c396fb1841762/6b6048148287a261?lnk=gst&amp;amp;q=integer+hash#6b6048148287a261&quot;&gt;here&lt;/a&gt; for discussion and explanation.&lt;/p&gt;

&lt;p&gt;What's more, if you print this map and then try to read it back in, the integers will be read as &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;long&lt;/code&gt; or &lt;code&gt;bigint&lt;/code&gt; arbitrarily depending how big they are.  This means you may not get the same class of object back that you output originally.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;user&amp;gt; (def x {(bigint 123) :foo})
#'user/x
user&amp;gt; (= x x)
true
user&amp;gt; (def y (read-string (pr-str x)))
#'user/y
user&amp;gt; (= x y)
false
user&amp;gt; (class (first (keys y)))
java.lang.Integer
user&amp;gt; (class (first (keys x)))
java.math.BigInteger
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This means that if you ever use integers as hash keys, you must be very careful to cast them all to the same integer type manually.&lt;/p&gt;

&lt;h1&gt;Metadata doesn't work on everything&lt;/h1&gt;

&lt;p&gt;Clojure lets you stick arbitrary &lt;a href=&quot;http://clojure.org/metadata&quot;&gt;metadata&lt;/a&gt; on various objects.  This is higly useful; you can decorate objects with information that doesn't affect the value of the object.  However metadata doesn't work everywhere.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;user&amp;gt; (with-meta &quot;foo&quot; {:bar :baz})
java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IObj (NO_SOURCE_FILE:0)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can only stick metadata on certain Clojure objects like Symbols, Vars, Refs, Agents, all of the Clojure collections and so on.  You can't stick metadata on, say, a String or an Integer, because those are closed Java classes and can't be touched.  It would be nice if you could.&lt;/p&gt;

&lt;h1&gt;use vs. require vs. import vs. load vs. ...&lt;/h1&gt;

&lt;p&gt;There are a startling number of ways to import a library into your code in Clojure.  You have to choose from &lt;code&gt;load&lt;/code&gt;, &lt;code&gt;import&lt;/code&gt;, &lt;code&gt;require&lt;/code&gt;, &lt;code&gt;use&lt;/code&gt;, &lt;code&gt;refer&lt;/code&gt;, and so on.  Some work on Java classes, some work on Clojure libs.  Some of them import symbols into your namespace, some of them don't.  Some of them take strings as arguments, some take symbols, some take quoted lists of symbols, some take quoted lists of symbols with sub-lists of arguments.  And all of these can be and usually are weirdly inlined into a namespace declaration, with a completely different list-quoting style.&lt;/p&gt;

&lt;p&gt;So in Ruby you can do this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;require 'util'
require 'config'
require 'whatever'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Whether it's a gem, or a Ruby source file sitting locally, it all works the same as long as the load path is set up right.&lt;/p&gt;

&lt;p&gt;But in Clojure, you do this (actual code from an IMAP library I wrote):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(ns qt4-mailtray.mail
  (:import (java.util Properties)
           (javax.mail Session Store Folder Message Flags Flags$Flag FetchProfile FetchProfile$Item)
           (javax.mail.internet InternetAddress))
  (:use clojure.contrib.str-utils))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This can quickly become unwieldy, especially if you start using the &lt;code&gt;:as&lt;/code&gt; or &lt;code&gt;:only&lt;/code&gt; or &lt;code&gt;:rename&lt;/code&gt; arguments.  It's made worse by Java's insane API's full of a billion classes that you need to import to do simple things.  (And those things with dollar signs are mangled Java inner class names.)  Clojure also lacks the ability to import a whole package worth of classes at once using &lt;code&gt;java.io.*&lt;/code&gt; syntax, so you must name all of the classes explicitly.&lt;/p&gt;

&lt;h1&gt;every? vs some.&lt;/h1&gt;

&lt;p&gt;This is such a trite pet-peeve that it's barely worth mentioning, but it seems to be brought up repeatedly and endlessly on the Clojure mailing list so at least I'm not the only one bugged by it.&lt;/p&gt;

&lt;p&gt;Clojure has a function &lt;code&gt;(every? pred coll)&lt;/code&gt; which tests whether every item in a collection tests true via some predicate.  To test whether every item in a collection tests false, we have &lt;code&gt;not-any?&lt;/code&gt;.  And we have a &lt;code&gt;not-every?&lt;/code&gt; which tests whether any item tests false.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;user&amp;gt; (every? even? [2 4 6])
true
user&amp;gt; (not-every? even? [2 4 6])
false
user&amp;gt; (not-any? even? [2 4 6])
false
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now what would you expect a function to be called which tests whether any item in a collection tests true via some predicate?  If you said &lt;code&gt;any?&lt;/code&gt; you are wrong!  It's &lt;code&gt;some&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Note that &lt;code&gt;some&lt;/code&gt; isn't a predicate (hence no question mark in the name); it doesn't return true or false, as above, but rather returns the result of running &lt;code&gt;pred&lt;/code&gt; on an item in &lt;code&gt;coll&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;user&amp;gt; (some identity [nil 1 2 3])
1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;any?&lt;/code&gt; is pretty easy to write so it doesn't matter that much.  Probably many people have an identical function sitting in some &lt;code&gt;utils.clj&lt;/code&gt; file on their systems.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defn any? [pred coll]
  (when (seq coll)
    (if (pred (first coll))
      true
      (recur pred (next coll)))))
&lt;/code&gt;&lt;/pre&gt;

&lt;h1&gt;Stack trace madness&lt;/h1&gt;

&lt;p&gt;Give this function:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defn foo []
  (throw (Exception. &quot;BARFED&quot;)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What does the stack trace look like in SLIME when you call &lt;code&gt;foo&lt;/code&gt;?  Like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;java.lang.Exception: BARFED (NO_SOURCE_FILE:0)
  [Thrown class clojure.lang.Compiler$CompilerException]

Restarts:
 0: [ABORT] Return to SLIME's top level.
 1: [CAUSE] Throw cause of this exception

Backtrace:
  2: swank.commands.basic$eval_region__729.invoke(basic.clj:36)
  3: swank.commands.basic$listener_eval__738.invoke(basic.clj:50)
  4: clojure.lang.Var.invoke(Var.java:346)
  5: user$eval__1506.invoke(NO_SOURCE_FILE)
  6: clojure.lang.Compiler.eval(Compiler.java:4580)
  7: clojure.core$eval__4016.invoke(core.clj:1728)
  8: swank.core$eval_in_emacs_package__336.invoke(core.clj:55)
  9: swank.core$eval_for_emacs__413.invoke(core.clj:123)
 10: clojure.lang.Var.invoke(Var.java:354)
 11: clojure.lang.AFn.applyToHelper(AFn.java:179)
 12: clojure.lang.Var.applyTo(Var.java:463)
 13: clojure.core$apply__3269.doInvoke(core.clj:390)
 14: clojure.lang.RestFn.invoke(RestFn.java:428)
 15: swank.core$eval_from_control__339.invoke(core.clj:62)
 16: swank.core$eval_loop__342.invoke(core.clj:67)
 17: swank.core$spawn_repl_thread__474$fn__505$fn__507.invoke(core.clj:173)
 18: clojure.lang.AFn.applyToHelper(AFn.java:171)
 19: clojure.lang.AFn.applyTo(AFn.java:164)
 20: clojure.core$apply__3269.doInvoke(core.clj:390)
 21: clojure.lang.RestFn.invoke(RestFn.java:428)
 22: swank.core$spawn_repl_thread__474$fn__505.doInvoke(core.clj:170)
 23: clojure.lang.RestFn.invoke(RestFn.java:402)
 24: clojure.lang.AFn.run(AFn.java:37)
 25: java.lang.Thread.run(Thread.java:619)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Yeouch.  Now imagine that the above error is coming not from a simple function, but from some random line among hundreds of lines of source code.&lt;/p&gt;

&lt;p&gt;Stack traces in Clojure will often tell you little to nothing about what is causing the error, or more importantly, where it's coming from in your code.  Clojure functions are translated into Java classes when they're run through the JVM.  Often can't even see the name of the function that's throwing the error; names are mangled into things like &lt;code&gt;user$eval__1473.invoke&lt;/code&gt;, which is really really confusing when you use anonymous functions.&lt;/p&gt;

&lt;p&gt;Per &lt;a href=&quot;http://w01fe.com/blog/2008/12/debugging-clojure-with-slime/&quot;&gt;Jason Wolfe and Randall Schulz&lt;/a&gt; sometimes you can get a better stack trace if you dig a bit deeper:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;user&amp;gt; (.printStackTrace (.getCause *e))

java.lang.Exception: BARFED
    at user$foo__1503.invoke(NO_SOURCE_FILE:1)
    at user$eval__1509.invoke(NO_SOURCE_FILE:1)
    at clojure.lang.Compiler.eval(Compiler.java:4580)
    at clojure.core$eval__4016.invoke(core.clj:1728)
    at swank.commands.basic$eval_region__729.invoke(basic.clj:36)
    at swank.commands.basic$listener_eval__738.invoke(basic.clj:50)
    at clojure.lang.Var.invoke(Var.java:346)
    at user$eval__1506.invoke(NO_SOURCE_FILE)
    at clojure.lang.Compiler.eval(Compiler.java:4580)
    at clojure.core$eval__4016.invoke(core.clj:1728)
    at swank.core$eval_in_emacs_package__336.invoke(core.clj:55)
    at swank.core$eval_for_emacs__413.invoke(core.clj:123)
    at clojure.lang.Var.invoke(Var.java:354)
    at clojure.lang.AFn.applyToHelper(AFn.java:179)
    at clojure.lang.Var.applyTo(Var.java:463)
    at clojure.core$apply__3269.doInvoke(core.clj:390)
    at clojure.lang.RestFn.invoke(RestFn.java:428)
    at swank.core$eval_from_control__339.invoke(core.clj:62)
    at swank.core$eval_loop__342.invoke(core.clj:67)
    at swank.core$spawn_repl_thread__474$fn__505$fn__507.invoke(core.clj:173)
    at clojure.lang.AFn.applyToHelper(AFn.java:171)
    at clojure.lang.AFn.applyTo(AFn.java:164)
    at clojure.core$apply__3269.doInvoke(core.clj:390)
    at clojure.lang.RestFn.invoke(RestFn.java:428)
    at swank.core$spawn_repl_thread__474$fn__505.doInvoke(core.clj:170)
    at clojure.lang.RestFn.invoke(RestFn.java:402)
    at clojure.lang.AFn.run(AFn.java:37)
    at java.lang.Thread.run(Thread.java:619)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This one at least mentions &lt;code&gt;foo&lt;/code&gt; by name but you're still going to have a headache after a few hours of those stack traces.&lt;/p&gt;

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

&lt;p&gt;So that's five things.  You will notice a common theme.  Most of these issues are inherited from the JVM.  This is to be expected, I suppose.  There's no way you can wrap one language in another without a few compromises.&lt;/p&gt;

&lt;p&gt;But these things aren't show-stoppers.  They are minor annoyances compared to the benefits you get from using the JVM, i.e. the good performance, tons of libraries, cross-platformness, and so on.  Clojure is fun enough to work with and wart-less enough that it took me well over two weeks to write this post.&lt;/p&gt;

&lt;p&gt;(If you were expecting me to mention &lt;code&gt;loop&lt;/code&gt;/&lt;code&gt;recur&lt;/code&gt; and the lack of native TCO in the JVM, you were PAINFULLY WRONG.  No one who uses Clojure loses sleep over native TCO.  It's largely a non-issue that's endlessly repeated by people looking for an excuse to pass up Clojure in favor of $their_pet_language.  To each his own, but I have never found myself caring the slightest about &lt;code&gt;loop&lt;/code&gt;/&lt;code&gt;recur&lt;/code&gt;.)&lt;/p&gt;</description></item><item><title>ABLE</title><link>http://briancarper.net/blog/able</link><guid>http://briancarper.net/blog/able</guid><pubDate>Thu, 04 Jun 2009 10:48:58 -0700</pubDate><description>&lt;p&gt;I learned recently of &lt;a href=&quot;http://phil.nullable.eu/&quot;&gt;ABLE&lt;/a&gt;, which is a minimalistic GUI editor + REPL for Common Lisp.  You download it and run it and there you go, Common Lisp with lots of included libraries, no Emacs trial-by-fire necessary.&lt;/p&gt;

&lt;p&gt;This is a really great idea in my opinion.  I wish I'd had this a year or two ago.  Common Lisp has too many barriers for newbies to get started.  Anything that removes a few of them can only benefit the Lisp world.&lt;/p&gt;</description></item><item><title>I paid for music</title><link>http://briancarper.net/blog/i-paid-for-music</link><guid>http://briancarper.net/blog/i-paid-for-music</guid><pubDate>Sun, 24 May 2009 20:06:32 -0700</pubDate><description>&lt;p&gt;As a general rule, I don't pay for music.  The main reason of course is that the music industry are a bunch of thugs.  If you don't know that already, you've been living under a rock for the past few decades.  I won't even buy music for other people as a gift if I can help it.&lt;/p&gt;

&lt;p&gt;Recently however I did buy music, specifically &lt;a href=&quot;http://www.jonathancoulton.com/&quot;&gt;Jonathan Coulton&lt;/a&gt;'s latest DVD.  JoCo releases his music under Creative Commons, which is awesome, and when you buy it (from &lt;a href=&quot;http://secure.whatarerecords.com/index.php?main_page=index&amp;amp;cPath=45_99&quot;&gt;What Are Records&lt;/a&gt;) you get MP3s that are not infested with DRM, which is also awesome.  When you buy that particular DVD, you get a DVD of the concert, a music CD of the same concert, AND you can immediately download MP3s of said concert while you wait for the DVD in the mail.  All for $20.  Well worth it for such quality music.&lt;/p&gt;

&lt;p&gt;I first heard most of JoCo's music via shaky concert recordings on Youtube and via MP3s acquired &quot;elsewhere&quot; (nearly all of which are free downloads on Joco's website though); otherwise I'd never even have known he existed.  And yet I ended up giving him my money, happily and willingly, and probably will again.  Amazing how things turn out.&lt;/p&gt;

&lt;p&gt;The other music I bought recently is &lt;a href=&quot;http://www.stephenlynch.com/&quot;&gt;Stephen Lynch&lt;/a&gt;.  Again I heard most of his music first on Youtube.  Again I gleefully spent money on his &lt;a href=&quot;http://secure.whatarerecords.com/index.php?main_page=index&amp;amp;cPath=45_48&quot;&gt;latest CD&lt;/a&gt; because it's good music and because it's DRM-less and thug-less entertainment and a good portion of that money is going to the artists.&lt;/p&gt;

&lt;p&gt;Most of the music I like comes from Japan or various corners of Europe.  Amazon sells a few (very few) Japanese music CDs, for between $50 and $90 each (plus shipping).  Do you know how much it costs to ship a stream of bytes from Japan to the US via the intertubes?  Hint, it's not $90.  How does a stream of bytes increase $90 in value when it's written onto a piece of plastic?&lt;/p&gt;

&lt;p&gt;These are strange times.  There's such disparity between what the average person believes is right and wrong on the internet and what the law says is lawful and unlawful.  This kind of disparity can't last forever.  My high school history teacher said that in America at least, a law that is opposed by the majority of citizens in the country never lasts long; I think that's true.  And it's as it should be.  In a few decades, we're going to look back at how things were in the 90's and 00's and laugh.&lt;/p&gt;</description></item><item><title>More Clojure Mandelbrot Goodness</title><link>http://briancarper.net/blog/more-clojure-mandelbrot-goodness</link><guid>http://briancarper.net/blog/more-clojure-mandelbrot-goodness</guid><pubDate>Wed, 20 May 2009 23:39:23 -0700</pubDate><description>&lt;p&gt;After my &lt;a href=&quot;http://briancarper.net/clojure/mandelbrot-swing.clj&quot;&gt;brief stint&lt;/a&gt; in the world of fractal geometry and Clojure, I decided to make a real Mandelbrot set viewer.  The resulting source code is &lt;a href=&quot;http://briancarper.net/clojure/mandelbrot-swing.clj&quot;&gt;here&lt;/a&gt;.  Here's a simple output (click for bigger version):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://briancarper.net/clojure/mandelbrot/mandelbrot-smooth.png&quot;&gt; &lt;img src=&quot;/clojure/mandelbrot/thumbs/mandelbrot-smooth.png&quot; alt=&quot;/clojure/mandelbrot/thumbs/mandelbrot-smooth.png&quot; title=&quot;&quot; /&gt; &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's a pretty naive implementation, barely 100 lines of code, but even with my brute-force approach, given a liberal sprinkling of type hints it runs fast enough.  Programming Swing from Clojure couldn't be easier (though I doubt programming Swing from any language is ever really enjoyable, it's a painful bunch of libraries).&lt;/p&gt;

&lt;p&gt;There's a discussion of &lt;a href=&quot;http://en.wikipedia.org/wiki/Mandelbrot_set#For_programmers&quot;&gt;different coloring algorithms&lt;/a&gt; on Wikipedia, but even after reading that, getting this thing to look good was difficult.  I don't know enough math for it.  I ended up cheating and I colored a couple of them in the GIMP, so I could use them as desktop wallpapers.  &lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://briancarper.net/clojure/mandelbrot/mandelbrot-rainbow.png&quot;&gt; &lt;img src=&quot;/clojure/mandelbrot/thumbs/mandelbrot-rainbow.png&quot; alt=&quot;/clojure/mandelbrot/thumbs/mandelbrot-rainbow.png&quot; title=&quot;&quot; /&gt; &lt;/a&gt; 
&lt;a href=&quot;http://briancarper.net/clojure/mandelbrot/mandelbrot-rainbow-2.png&quot;&gt; &lt;img src=&quot;/clojure/mandelbrot/thumbs/mandelbrot-rainbow-2.png&quot; alt=&quot;/clojure/mandelbrot/thumbs/mandelbrot-rainbow-2.png&quot; title=&quot;&quot; /&gt; &lt;/a&gt;  &lt;a href=&quot;http://briancarper.net/clojure/mandelbrot/mandelbrot-rainbow-3.png&quot;&gt; &lt;img src=&quot;/clojure/mandelbrot/thumbs/mandelbrot-rainbow-3.png&quot; alt=&quot;/clojure/mandelbrot/thumbs/mandelbrot-rainbow-3.png&quot; title=&quot;&quot; /&gt; &lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://briancarper.net/clojure/mandelbrot/mandelbrot-rainbow-4.png&quot;&gt; &lt;img src=&quot;/clojure/mandelbrot/thumbs/mandelbrot-rainbow-4.png&quot; alt=&quot;/clojure/mandelbrot/thumbs/mandelbrot-rainbow-4.png&quot; title=&quot;&quot; /&gt; &lt;/a&gt; &lt;a href=&quot;http://briancarper.net/clojure/mandelbrot/mandelbrot-rainbow-5.png&quot;&gt; &lt;img src=&quot;/clojure/mandelbrot/thumbs/mandelbrot-rainbow-5.png&quot; alt=&quot;/clojure/mandelbrot/thumbs/mandelbrot-rainbow-5.png&quot; title=&quot;&quot; /&gt; &lt;/a&gt; &lt;/p&gt;

&lt;p&gt;There are some more PNGS &lt;a href=&quot;http://briancarper.net/page/clojure&quot;&gt;over here&lt;/a&gt; including one that's 16000x16000 (producing it almost melted my CPU last night).&lt;/p&gt;</description></item><item><title>Who needs a DB?</title><link>http://briancarper.net/blog/who-needs-a-db</link><guid>http://briancarper.net/blog/who-needs-a-db</guid><pubDate>Wed, 20 May 2009 22:53:03 -0700</pubDate><description>&lt;p&gt;My blog is still working, in spite of my best efforts to crash it.  So that's good.  But lately I've been thinking that an SQL database is a lot of overkill just to run a little blog like this.&lt;/p&gt;

&lt;p&gt;My blog only has around 450 posts total (over the course of many years), and about an equal number of user comments (thanks to all commenters!).  Why do I need a full-blown database for that?  All of my posts plus comments plus all meta-data is only 2 MB as a flat text file, 700k gzipped.&lt;/p&gt;

&lt;p&gt;By far the most complicated part of my blog engine is the part that stuffs data into the database and gets it back out again in a sane manner (translating Clojure data to SQL values, and back again; splitting up my Clojure data structures into rows for different tables, and then re-combining values joined from multiple tables into one data structure).  Eliminating that mess would be nice.  &lt;/p&gt;

&lt;p&gt;Inevitably I ended up with some logic in the database too: enforcing uniqueness of primary keys, marking some fields as NOT NULL, giving default values and so on.  But a lot of other logic was in my Clojure code, e.g. higher-level semantic checking, and some things I wanted to set as default values were impossible to implement in SQL.  &lt;/p&gt;

&lt;p&gt;Wouldn't it be nice for all the logic to be in Clojure?  And the data store on disk to be a simple dump of a Clojure data structure?  I can (and did) write a few macros to give me SQL-like field declaration and data validation, for uniqueness of IDs and data types etc.  For my limited needs it works OK.  &lt;/p&gt;

&lt;p&gt;The next question is what format to use for dumping to disk.  Happily Clojure is Lisp, so dumping it as a huge s-exp via &lt;code&gt;pr-str&lt;/code&gt; works fine, and reading it back in later via &lt;code&gt;read-string&lt;/code&gt; is trivial.&lt;/p&gt;

&lt;p&gt;Some Java data types can't be printed readably by default, for example &lt;code&gt;java.util.Date&lt;/code&gt;s, which print like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#&amp;lt;Date Wed May 20 22:39:00 PDT 2009&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;#&amp;lt;&amp;gt;&lt;/code&gt; reader macro deliberately throws an error if you try to read that back in, because the reader isn't smart enough to craft Date objects from strings by default.  But Clojure is extensible; you can specify a readable-print method for any data type like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defmethod clojure.core/print-method java.util.Date [o w]
  (.write w (str &quot;#=&quot; `(java.util.Date. ~(.getTime o)))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now dates print as &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#=(java.util.Date. 1242884415044)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and if you try to read that via &lt;code&gt;read-string&lt;/code&gt;, it'll create a Date object like you'd expect.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;user&amp;gt; (def x (read-string &quot;#=(java.util.Date. 1242884415044)&quot;))
#'user/x
user&amp;gt; (class x)
java.util.Date
user&amp;gt; (str x)
&quot;Wed May 20 22:40:15 PDT 2009&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Storing data in a plain file has another benefit of letting me grep my data from a command line, or even edit the data in a text editor and re-load it into the blog (God help me if that's ever necessary).&lt;/p&gt;

&lt;p&gt;Having multiple threads banging on a single file on disk is a horrible idea, but Clojure refs and agents and transactions handle that easily.  But I do have to work out how not to lose all my data in case the server crashes in the middle of a file update.  (I've lost data (in a recoverable way) due to a server crash in the middle of a MySQL update too, so this is a problem for everyone.)  Perhaps I'll keep a running history of my data, each update being a new timestamped file, so old files can't possibly be corrupted.  Or use the old write-to-tmp-file-and-rename-to-real-file routine.  Or heck, I could keep my data in Git and use Git commands from Clojure.  It'd be nice to have a history of edits.&lt;/p&gt;

&lt;p&gt;If this idea works out I'll upload code for everything to github, as usual.&lt;/p&gt;</description></item><item><title>Clojure: ASCII Mandelbrot Set</title><link>http://briancarper.net/blog/clojure-ascii-mandelbrot-set</link><guid>http://briancarper.net/blog/clojure-ascii-mandelbrot-set</guid><pubDate>Tue, 12 May 2009 18:46:01 -0700</pubDate><description>&lt;p&gt;Did you know there's this neat &lt;a href=&quot;http://www.lispforum.com/index.php&quot;&gt;Lisp message board&lt;/a&gt; where from time to time someone posts a &lt;a href=&quot;http://www.lispforum.com/viewtopic.php?f=32&amp;amp;t=334&quot;&gt;short problem&lt;/a&gt; similar in spirit to the infamous &lt;a href=&quot;http://www.rubyquiz.com/&quot;&gt;RubyQuiz&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;Not a lot of people have participated so far, hopefully that changes.  I participated this time; the problem is to render the Mandelbrot Set in ASCII. Here's my &lt;a href=&quot;http://briancarper.net/clojure/mandelbrot.clj&quot;&gt;Clojure version&lt;/a&gt; (based loosely on &lt;a href=&quot;http://bc.tech.coop/blog/040811.html&quot;&gt;this one&lt;/a&gt;).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(ns mandelbrot
  (:refer-clojure :exclude [+ * &amp;lt;])
  (:use (clojure.contrib complex-numbers)
        (clojure.contrib.generic [arithmetic :only [+ *]]
                                 [comparison :only [&amp;lt;]]
                                 [math-functions :only [abs]])))

(defn- mandelbrot-seq [x y]
  (let [z (complex x y)]
    (iterate #(+ z (* % %)) z)))

(defn- mandelbrot-char [x y]
  (loop [c 126
         m (mandelbrot-seq x y)]
    (if (and (&amp;lt; (abs (first m)) 2)
             (&amp;gt; c 32))
      (recur (dec c) (rest m))
      (char c))))

(defn- mandelbrot-line [xs y]
  (apply str (map #(mandelbrot-char % y) xs)))

(defn- m-range [min max num-steps]
  (range min
         max
         (/ (+ (abs min)
               (abs max))
            num-steps)))

(defn mandelbrot [rmin rmax imin imax]
  (let [rows 30
        cols 50
        xs (m-range rmin rmax cols)
        ys (m-range imin imax rows)]
    (dorun (map #(println (mandelbrot-line xs %)) ys))))

(comment
  ;Example run:
  (mandelbrot -2.0 1.0 -1.5 1.5)
&quot;
~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
~~~~~~~~~}}}}}}}}}}}}|||||||||}}}}}}}}}}}}}}}}}}}}
~~~~~~~}}}}}}}}|||||||||||||||||||||}}}}}}}}}}}}}}
~~~~~~}}}}}||||||||||||||{{{{zlxz{{{||||}}}}}}}}}}
~~~~~}}}}|||||||||||||{{{{{zzyxpvlz{{{||||}}}}}}}}
~~~~}}}|||||||||||||{{{{{{zzyxvnpwyzz{{{||||}}}}}}
~~~}}|||||||||||||{{{{{{zzyyws   .vyzzz{{|||||}}}}
~~~}||||||||||||{{{{{zzxwwwvus   muvxyywz{|||||}}}
~~}|||||||||||{{{zzzzyyu= p         oteqpz{|||||}}
~~||||||||||{zzzzzzyyyvtm              oxz{{|||||}
~}|||||{{{zyvwxxxxxxxwrG                vuz{|||||}
~||{{{{{zzzywsMsqRovvs                  pxz{{|||||
~|{{{{{zzzyxsq      pj                  `xz{{|||||
~{{{{yyyxwsrp                           wyz{{|||||
~?:3 3 #                              ovxzz{{|||||
~{{{{yyyxwsrp                           wyz{{|||||
~|{{{{{zzzyxsq      pj                  `xz{{|||||
~||{{{{{zzzywsMsqRovvs                  pxz{{|||||
~}|||||{{{zyvwxxxxxxxwrG                vuz{|||||}
~~||||||||||{zzzzzzyyyvtm              oxz{{|||||}
~~}|||||||||||{{{zzzzyyu= p         oteqpz{|||||}}
~~~}||||||||||||{{{{{zzxwwwvus   muvxyywz{|||||}}}
~~~}}|||||||||||||{{{{{{zzyyws   .vyzzz{{|||||}}}}
~~~~}}}|||||||||||||{{{{{{zzyxvnpwyzz{{{||||}}}}}}
~~~~~}}}}|||||||||||||{{{{{zzyxpvlz{{{||||}}}}}}}}
~~~~~~}}}}}||||||||||||||{{{{zlxz{{{||||}}}}}}}}}}
~~~~~~~}}}}}}}}|||||||||||||||||||||}}}}}}}}}}}}}}
~~~~~~~~~}}}}}}}}}}}}|||||||||}}}}}}}}}}}}}}}}}}}}
~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
&quot;
)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And here's some &lt;a href=&quot;http://www.youtube.com/watch?v=ES-yKOYaXq0&quot;&gt;obligatory Jonathan Coulton&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Microsoft, you still surprise me</title><link>http://briancarper.net/blog/microsoft-you-still-surprise-me</link><guid>http://briancarper.net/blog/microsoft-you-still-surprise-me</guid><pubDate>Mon, 11 May 2009 23:18:21 -0700</pubDate><description>&lt;p&gt;I use Windows XP at work (not by choice) and I've been continually saying &quot;no&quot; when it tried to install SP3.  Why?  No tangible reason other than that decades of experience with Windows has shown me that any time you touch any system files or settings in Windows, crap breaks.  When it comes to Windows, you set things up and then like a teetering house of playing cards, you back away slowly and try not to breathe.&lt;/p&gt;

&lt;p&gt;Which brings us to the other day.  I first noticed something was up when a got a popup dialog on my work machine asking me every 15 minutes whether I wanted to Reboot Now or Reboot Later.  Confused, I clicked &quot;later&quot; but again and again and again this prompt appeared.  After hours of this interrupting my futile attempts at work I relented; I laboriously shut down my half-dozen command prompts and carefully-placed Vim sessions and various server daemons and all the tools I got to look forward to re-opening after &lt;strong&gt;Yet Another Unnecessary Reboot&lt;/strong&gt;, and then I rebooted.&lt;/p&gt;

&lt;p&gt;So then XP left me alone and all was well with the world.  Ha, just kidding, it started doing the same thing again almost immediately.  Reboot Now or Reboot Later?  I hatefully tolerated this for as long as I could but it was a futile battle.  Microsoft won in the end and I rebooted again.&lt;/p&gt;

&lt;p&gt;A few other people at work reported the same thing on their systems, so I thought maybe it was a virus, but I checked a few things and noticed a shiny new SP3 installed on my system (so my initial guess was close).  Somehow SP3 was forced onto my machine, not sure if it was the sysadmins pushing it out or Microsoft's doing, but either way: why was it possible to install a Service Pack on my machine without my even being aware it happened?  I do not consider this a good thing.&lt;/p&gt;

&lt;p&gt;In any case, after the second reboot, strange things happened.  My taskbar settings were all reverted to defaults and I noticed my Address Bar was missing.  The Address Bar is a little URL/file path bar in the taskbar where you can type a file path and open an Explorer window quickly.  One of the very few semi-useful bits of the XP interface.&lt;/p&gt;

&lt;p&gt;But it was gone.  What happened?  A short Google later and I learned that Microsoft removed the feature in SP3 permanently, by design.  Why?  Because of &lt;a href=&quot;http://support.microsoft.com/kb/951448&quot;&gt;anti-monopoly regulatory concerns&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Wow.  So it turns out I wasn't disappointed, and a few dozen cards toppled from the shaky tower as I watched, helpless.  Not the end of the world, but what an annoyance.&lt;/p&gt;

&lt;p&gt;The reason I bothered blogging this is because, hilariously enough, you can still add the Address Bar back in SP3.  As I read somewhere or other, probably &lt;a href=&quot;http://www.systemsabuse.com/2007/12/27/xp-service-pack-3-sp3-where-did-my-toolbars-address-bar-go-missing/&quot;&gt;here&lt;/a&gt;, you simply 1) Drag a &quot;My Computer&quot; icon to the top of the screen to make a useless &quot;My Computer&quot; toolbar, 2) Right click that and add the Address Bar, which is still an option there, 3) Drag that Address Bar to your main taskbar, 4) Remove the useless toolbar from above.  And then you have your Address Bar back.  Oops!&lt;/p&gt;

&lt;p&gt;So, in summary:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Two forced reboots via 20 repeated un-ignorable popup prompts.&lt;/li&gt;
&lt;li&gt;Service Pack installed without my knowledge or consent.&lt;/li&gt;
&lt;li&gt;Useful piece of functionality removed.&lt;/li&gt;
&lt;li&gt;Item 3 caused by a history of monopolistic business practices and the resulting legal fallout.&lt;/li&gt;
&lt;li&gt;Functionality in question removed so incompetently that it can be added back anyways in a matter of seconds.&lt;/li&gt;
&lt;li&gt;Another hour of my life sucked into the black hole of the Microsoft Windows User Experience™, forever lost.&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Git tutorial</title><link>http://briancarper.net/blog/git-tutorial</link><guid>http://briancarper.net/blog/git-tutorial</guid><pubDate>Sat, 09 May 2009 13:55:59 -0700</pubDate><description>&lt;p&gt;Finally I found a good &lt;a href=&quot;http://book.git-scm.com/index.html&quot;&gt;Git tutorial&lt;/a&gt; that starts from the absolute basics and goes steadily through more advanced things.  I highly recommend it.&lt;/p&gt;</description></item><item><title>Crackberry Acquired</title><link>http://briancarper.net/blog/crackberry-acquired</link><guid>http://briancarper.net/blog/crackberry-acquired</guid><pubDate>Thu, 07 May 2009 18:26:26 -0700</pubDate><description>&lt;p&gt;All I ever wanted out of life was to SSH to my computer from a cell phone.  That dream has finally come true.&lt;/p&gt;

&lt;p&gt;Up to this point I have not owned a cell phone.  I bought one a few years back, then I returned it and got a refund because it was pointless.  Communicating with other human beings via spoken voice?  How trite.  My current employer gave me a phone for free but I never used it.&lt;/p&gt;

&lt;p&gt;But nowadays cell phones are pretty much mini computers that happen to be able to make phone calls as a side effect.  I almost got an iPhone, but I am very wary about hype.  Apple's business practices turn me off; the app store is a shystering waiting to happen, their crappy proprietariness makes me puke, their overblown marketing and &quot;image&quot; makes me puke even more.  I don't want an MP3 player in my phone; my &lt;a href=&quot;http://www.cowonamerica.com/products/cowon/d2/&quot;&gt;Cowon D2&lt;/a&gt; is far superior to any silly iPod.  And as I tried the touch screen keyboard, I quickly realized that the Blackberry's physical keys win in that category by a mile.&lt;/p&gt;

&lt;p&gt;So I got a &lt;a href=&quot;http://www.blackberry.com/blackberrybold/&quot;&gt;Blackberry Bold&lt;/a&gt; and I'm pretty happy with it so far.  I have yet to make a single phone call, but I've put it to good use.  I installed all kinds of silly stuff on there, including an &lt;a href=&quot;http://www.xk72.com/midpssh/&quot;&gt;SSH client&lt;/a&gt; so I can do system maintenance while driving.  (Not really, don't worry.)  I can look at Google maps when I get lost, which happens embarrassingly often in my car.  I can look at Slashdot from the sushi restaurant.  I can get the weather updated every 15 minutes, which saves me from rotating my head 25 degrees and looking out the window.&lt;/p&gt;

&lt;p&gt;I still object to certain cell phone things on principle.  Paying $3 for a 15-second song clip as a ring tone for example; the insanity of this is almost physically painful to me.  The Blackberry let me set any old MP3 I wanted as the ring tone though, which is nice.&lt;/p&gt;

&lt;p&gt;Paying for text messages is almost as painful.  How can it cost a quarter to send 160 bytes of text to another phone, when the whole freaking internet costs orders of magnitude less?  How do cell phone companies get away with this?  It's such a racket.  But I can put IM clients on my phone and use email and I have &quot;unlimited&quot; data transfer each month, so that's nice.  (And I really grilled the salesperson about what &quot;unlimited&quot; means.   She said some people go into the gigabytes of transfer each month without consequence, so it looks like I need to find a torrent client now!)&lt;/p&gt;

&lt;p&gt;Maybe one of these days I'll call someone.  What a novel concept.&lt;/p&gt;</description></item><item><title>Vim and Emacs modelines</title><link>http://briancarper.net/blog/vim-and-emacs-modelines</link><guid>http://briancarper.net/blog/vim-and-emacs-modelines</guid><pubDate>Tue, 05 May 2009 18:22:47 -0700</pubDate><description>&lt;p&gt;Both Vim and Emacs have &quot;windows&quot;, resizeable panes inside the main app &quot;frame&quot;.  Windows are a very useful feature (aside from the ill-chosen name; should've been &quot;panes&quot; or something).  I find windows superior to tabs in my opinion; you can easily view more than one file at a time, view two files side-by-side for comparison, and such.  Both Vim and Emacs use the border under the window to show helpful information like the filename and editing mode such; this is called the &quot;status line&quot; or &quot;modeline&quot;.  Again, very handy.&lt;/p&gt;

&lt;p&gt;How do you set a nice custom modeline in Vim?  Here's my config from my .vimrc:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;set statusline=%f\ %2*%m\ %1*%h%r%=[%{&amp;amp;encoding}\ %{&amp;amp;fileformat}\ %{strlen(&amp;amp;ft)?&amp;amp;ft:'none'}\ %{getfperm(@%)}]\ 0x%B\ %12.(%c:%l/%L%)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Yikes!  What a mess.  It's just a big string with a bunch of special codes and literal characters all mixed up.  If you do &lt;code&gt;:h 'statusline'&lt;/code&gt; you can read about all the options.  That string is ugly though.&lt;/p&gt;

&lt;p&gt;Or so I thought, until I witnessed the trainwreck that is Emacs.  The documentation for Emacs' modeline comprises a &lt;a href=&quot;http://www.gnu.org/software/emacs/elisp/html_node/Mode-Line-Format.html&quot;&gt;small encylcopedia&lt;/a&gt;.  The configuration itself is spread across a couple dozen configuration variables.  This is the default value for &lt;strong&gt;just one&lt;/strong&gt; of them:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(#(&quot;%[&quot; 0 2
   (help-echo &quot;Recursive edit, type C-M-c to get out&quot;))
 #(&quot;(&quot; 0 1
   (help-echo &quot;mouse-1: Select (drag to resize)\nmouse-2: Make current window occupy the whole frame\nmouse-3: Remove current window from display&quot;))
 (:propertize
  (&quot;&quot; mode-name)
  help-echo &quot;Major mode\nmouse-1: Display major mode menu\nmouse-2: Show help for major mode\nmouse-3: Toggle minor modes&quot; mouse-face mode-line-highlight local-map
  (keymap
   (mode-line keymap
          (down-mouse-3 keymap
                (abbrev-mode menu-item &quot;Abbrev (Abbrev)&quot; abbrev-mode :help &quot;Automatically expand abbreviations&quot; :button
                     (:toggle . abbrev-mode))
                (auto-fill-mode menu-item &quot;Auto fill (Fill)&quot; auto-fill-mode :help &quot;Automatically insert new lines&quot; :button
                        (:toggle . auto-fill-function))
                (auto-revert-mode menu-item &quot;Auto revert (ARev)&quot; auto-revert-mode :help &quot;Revert the buffer when the file on disk changes&quot; :button
                          (:toggle bound-and-true-p auto-revert-mode))
                (auto-revert-tail-mode menu-item &quot;Auto revert tail (Tail)&quot; auto-revert-tail-mode :help &quot;Revert the tail of the buffer when buffer grows&quot; :enable
                           (buffer-file-name)
                           :button
                           (:toggle bound-and-true-p auto-revert-tail-mode))
                (flyspell-mode menu-item &quot;Flyspell (Fly)&quot; flyspell-mode :help &quot;Spell checking on the fly&quot; :button
                       (:toggle bound-and-true-p flyspell-mode))
                (font-lock-mode menu-item &quot;Font Lock&quot; font-lock-mode :help &quot;Syntax coloring&quot; :button
                        (:toggle . font-lock-mode))
                (glasses-mode menu-item &quot;Glasses (o^o)&quot; glasses-mode :help &quot;Insert virtual separators to make long identifiers easy to read&quot; :button
                      (:toggle bound-and-true-p glasses-mode))
                (hide-ifdef-mode menu-item &quot;Hide ifdef (Ifdef)&quot; hide-ifdef-mode :help &quot;Show/Hide code within #ifdef constructs&quot; :button
                         (:toggle bound-and-true-p hide-ifdef-mode))
                (highlight-changes-mode menu-item &quot;Highlight changes (Chg)&quot; highlight-changes-mode :help &quot;Show changes in the buffer in a distinctive color&quot; :button
                            (:toggle bound-and-true-p highlight-changes-mode))
                (outline-minor-mode menu-item &quot;Outline (Outl)&quot; outline-minor-mode :help &quot;&quot; :button
                        (:toggle bound-and-true-p outline-minor-mode))
                (overwrite-mode menu-item &quot;Overwrite (Ovwrt)&quot; overwrite-mode :help &quot;Overwrite mode: typed characters replace existing text&quot; :button
                        (:toggle . overwrite-mode))
                &quot;Minor Modes&quot;)
          (mouse-2 . describe-mode)
          (down-mouse-1 menu-item &quot;Menu Bar&quot; ignore :filter
                (lambda
                  (_)
                  (mouse-menu-major-mode-map))))))
 (&quot;&quot; mode-line-process)
 (:propertize
  (&quot;&quot; minor-mode-alist)
  mouse-face mode-line-highlight help-echo &quot;Minor mode\nmouse-1: Display minor mode menu\nmouse-2: Show help for minor mode\nmouse-3: Toggle minor modes&quot; local-map
  (keymap
   (header-line keymap
        (down-mouse-3 keymap
                  (abbrev-mode menu-item &quot;Abbrev (Abbrev)&quot; abbrev-mode :help &quot;Automatically expand abbreviations&quot; :button
                       (:toggle . abbrev-mode))
                  (auto-fill-mode menu-item &quot;Auto fill (Fill)&quot; auto-fill-mode :help &quot;Automatically insert new lines&quot; :button
                          (:toggle . auto-fill-function))
                  (auto-revert-mode menu-item &quot;Auto revert (ARev)&quot; auto-revert-mode :help &quot;Revert the buffer when the file on disk changes&quot; :button
                        (:toggle bound-and-true-p auto-revert-mode))
                  (auto-revert-tail-mode menu-item &quot;Auto revert tail (Tail)&quot; auto-revert-tail-mode :help &quot;Revert the tail of the buffer when buffer grows&quot; :enable
                             (buffer-file-name)
                             :button
                             (:toggle bound-and-true-p auto-revert-tail-mode))
                  (flyspell-mode menu-item &quot;Flyspell (Fly)&quot; flyspell-mode :help &quot;Spell checking on the fly&quot; :button
                         (:toggle bound-and-true-p flyspell-mode))
                  (font-lock-mode menu-item &quot;Font Lock&quot; font-lock-mode :help &quot;Syntax coloring&quot; :button
                          (:toggle . font-lock-mode))
                  (glasses-mode menu-item &quot;Glasses (o^o)&quot; glasses-mode :help &quot;Insert virtual separators to make long identifiers easy to read&quot; :button
                        (:toggle bound-and-true-p glasses-mode))
                  (hide-ifdef-mode menu-item &quot;Hide ifdef (Ifdef)&quot; hide-ifdef-mode :help &quot;Show/Hide code within #ifdef constructs&quot; :button
                           (:toggle bound-and-true-p hide-ifdef-mode))
                  (highlight-changes-mode menu-item &quot;Highlight changes (Chg)&quot; highlight-changes-mode :help &quot;Show changes in the buffer in a distinctive color&quot; :button
                              (:toggle bound-and-true-p highlight-changes-mode))
                  (outline-minor-mode menu-item &quot;Outline (Outl)&quot; outline-minor-mode :help &quot;&quot; :button
                          (:toggle bound-and-true-p outline-minor-mode))
                  (overwrite-mode menu-item &quot;Overwrite (Ovwrt)&quot; overwrite-mode :help &quot;Overwrite mode: typed characters replace existing text&quot; :button
                          (:toggle . overwrite-mode))
                  &quot;Minor Modes&quot;))
   (mode-line keymap
          (down-mouse-3 keymap
                (abbrev-mode menu-item &quot;Abbrev (Abbrev)&quot; abbrev-mode :help &quot;Automatically expand abbreviations&quot; :button
                     (:toggle . abbrev-mode))
                (auto-fill-mode menu-item &quot;Auto fill (Fill)&quot; auto-fill-mode :help &quot;Automatically insert new lines&quot; :button
                        (:toggle . auto-fill-function))
                (auto-revert-mode menu-item &quot;Auto revert (ARev)&quot; auto-revert-mode :help &quot;Revert the buffer when the file on disk changes&quot; :button
                          (:toggle bound-and-true-p auto-revert-mode))
                (auto-revert-tail-mode menu-item &quot;Auto revert tail (Tail)&quot; auto-revert-tail-mode :help &quot;Revert the tail of the buffer when buffer grows&quot; :enable
                           (buffer-file-name)
                           :button
                           (:toggle bound-and-true-p auto-revert-tail-mode))
                (flyspell-mode menu-item &quot;Flyspell (Fly)&quot; flyspell-mode :help &quot;Spell checking on the fly&quot; :button
                       (:toggle bound-and-true-p flyspell-mode))
                (font-lock-mode menu-item &quot;Font Lock&quot; font-lock-mode :help &quot;Syntax coloring&quot; :button
                        (:toggle . font-lock-mode))
                (glasses-mode menu-item &quot;Glasses (o^o)&quot; glasses-mode :help &quot;Insert virtual separators to make long identifiers easy to read&quot; :button
                      (:toggle bound-and-true-p glasses-mode))
                (hide-ifdef-mode menu-item &quot;Hide ifdef (Ifdef)&quot; hide-ifdef-mode :help &quot;Show/Hide code within #ifdef constructs&quot; :button
                         (:toggle bound-and-true-p hide-ifdef-mode))
                (highlight-changes-mode menu-item &quot;Highlight changes (Chg)&quot; highlight-changes-mode :help &quot;Show changes in the buffer in a distinctive color&quot; :button
                            (:toggle bound-and-true-p highlight-changes-mode))
                (outline-minor-mode menu-item &quot;Outline (Outl)&quot; outline-minor-mode :help &quot;&quot; :button
                        (:toggle bound-and-true-p outline-minor-mode))
                (overwrite-mode menu-item &quot;Overwrite (Ovwrt)&quot; overwrite-mode :help &quot;Overwrite mode: typed characters replace existing text&quot; :button
                        (:toggle . overwrite-mode))
                &quot;Minor Modes&quot;)
          (mouse-2 . mode-line-minor-mode-help)
          (down-mouse-1 . mouse-minor-mode-menu))))
 #(&quot;%n&quot; 0 2
   (local-map
    (keymap
     (mode-line keymap
        (mouse-2 . mode-line-widen)))
    mouse-face mode-line-highlight help-echo &quot;mouse-2: Remove narrowing from the current buffer&quot;))
 #(&quot;)&quot; 0 1
   (help-echo &quot;mouse-1: Select (drag to resize)\nmouse-2: Make current window occupy the whole frame\nmouse-3: Remove current window from display&quot;))
 #(&quot;%]&quot; 0 2
   (help-echo &quot;Recursive edit, type C-M-c to get out&quot;))
 #(&quot;--&quot; 0 2
   (help-echo &quot;mouse-1: Select (drag to resize)\nmouse-2: Make current window occupy the whole frame\nmouse-3: Remove current window from display&quot;)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What the hell?&lt;/p&gt;

&lt;p&gt;Instead of a string, it's an s-expression, which is better, right?  Well no, it's still just a big construct with &lt;a href=&quot;http://www.gnu.org/software/emacs/elisp/html_node/Mode-Line-Data.html#Mode-Line-Data&quot;&gt;arbitrary meanings assigned to its contents&lt;/a&gt;.  Lists mean one thing, strings mean another thing (and those strings, like Vim's, can contain special escape sequences).  Symbols mean something else, symbols that are keywords mean something else, numbers mean something else, and so on.&lt;/p&gt;

&lt;p&gt;To decipher this I had to learn this mini-language.  And also learn about &quot;text properties&quot; and a bunch of elisp stuff.  It also required knowledge about a bunch of minor modes and how they tie into the modeline, all of which is essentially a bowl of spaghetti code.  And keymaps, and maps to control mouse click events and such.  Eventually I figured out that most of that crap is controlling tooltip text.&lt;/p&gt;

&lt;p&gt;If you do &lt;code&gt;M-x customize-apropos&lt;/code&gt; in Emacs and search for &quot;mode-line&quot;, you'll get a helpful list of all of the configuration values and their values.  (The default values contain literal tab characters, which you can't even type into the customize text fields without &lt;code&gt;C-q&lt;/code&gt;ing, because tab jumps you between fields.  Ughhhhhhh.)&lt;/p&gt;

&lt;p&gt;I gave up even trying to get Emacs to have all the helpful information my Vim modeline has.  Even deleting the default crap to pare this down to something readable took some effort.  This what I ended up with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(mode-line-format (quote (&quot;%e--[&quot; mode-line-buffer-identification &quot;]&quot; (vc-mode vc-mode) &quot;  &quot; mode-line-modes global-mode-string &quot; %-&quot;)))
(mode-line-in-non-selected-windows t)
(mode-line-modes (quote (&quot;%[&quot; &quot;(&quot; (:propertize (&quot;&quot; mode-name)) (&quot;&quot; mode-line-process) (:propertize (&quot;&quot; minor-mode-alist)) &quot;%n&quot; &quot;)&quot; &quot;%]&quot;)))
(mode-line ((((class color) (min-colors 88)) (:background &quot;#333333&quot; :foreground &quot;#bcbcbc&quot; :box (:line-width -1 :color &quot;#333333&quot;)))))
(mode-line-highlight ((((class color) (min-colors 88)) nil)))
(mode-line-inactive ((default (:inherit mode-line)) (((class color) (min-colors 88) (background dark)) (:foreground &quot;#8b8b8b&quot; :weight light))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What does that mean?  Don't ask me, I can no longer read it.  If &lt;code&gt;customize&lt;/code&gt; hadn't produced a lot of that for me, I probably wouldn't have managed.  My favorite part is the four-deep nested list of lists of lists of lists for the colors.&lt;/p&gt;

&lt;p&gt;Verdict?  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Vim's modeline is less powerful than Emacs.  But who cares if you can't even read it to edit it?  Most of Emacs' modeline features are annoying.  (My motivation for editing this to begin with was to turn off all the mouse buttons and mini-menus and crap.)  &lt;/p&gt;

&lt;p&gt;Vim's status line is exactly configurable enough.  I don't want to build a small GUI app in my modeline.  I want it to show certain bits of information about the buffer, that's it.  Vim does this.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;Vim script is less elegant than elisp.   Or is it?  Vim's modeline is a custom DSL for formatting modelines.  It's hard to think of anything more concise.  Concision is a very good thing.  Emacs' version is more general, at the expense of horrid verbosity and unreadability.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Vim's modeline is a string, which means you either write it literally, or you construct it by concatenating lots of other strings.  This is a faux pas, right?  It's like using &lt;code&gt;eval&lt;/code&gt; in Ruby or Perl.  It's fragile and error-prone.  Emacs uses a Lisp, with its macros and quoted lists and &lt;em&gt;code is data&lt;/em&gt; and so on.  &lt;/p&gt;

&lt;p&gt;But who cares?  In this case, a simple string is powerful enough.  I don't need a whole Turing-complete programming language to configure a modeline.  It's massive overkill and you pay a price for it.  The minute a human being is supposed to be keeping track that the second element in the 5-deep nested list means &quot;x&quot;, something has gone horribly wrong.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Vim wins this round.&lt;/p&gt;</description></item><item><title>Clojure 1.0</title><link>http://briancarper.net/blog/clojure-1-0</link><guid>http://briancarper.net/blog/clojure-1-0</guid><pubDate>Mon, 04 May 2009 21:04:37 -0700</pubDate><description>&lt;p&gt;&lt;a href=&quot;http://groups.google.com/group/clojure/browse_thread/thread/1e661d16bd910ddd&quot;&gt;Clojure 1.0&lt;/a&gt; was released today.  For those who care about version numbers, this should be good news.  Clojure has been good and &quot;ready&quot; for a good while in my opinion but it's kind of nice to see it made somewhat official.&lt;/p&gt;

&lt;p&gt;The pace of development and the level of enthusiasm in the Clojure community are something to behold.  Here's hoping it holds up.  The community is knowledgeable and helpful and overall positive and people are churning out an awful lot of useful code.  Kudos to the Clojure devs and contributors, thanks for the wonderfully fun tool and toy to work and play with.&lt;/p&gt;</description></item><item><title>Clojure Reader Macros</title><link>http://briancarper.net/blog/clojure-reader-macros</link><guid>http://briancarper.net/blog/clojure-reader-macros</guid><pubDate>Sat, 18 Apr 2009 17:14:50 -0700</pubDate><description>&lt;p&gt;Unlike Common Lisp, Clojure doesn't support user-defined reader macros.  You can read some of the rationale for why in &lt;a href=&quot;http://clojure-log.n01se.net/date/2008-11-06.html&quot;&gt;this chat log&lt;/a&gt;, among other places.  I think that's probably a good decision; I don't see a lot of need for mangling the reader.  Regular macros get you pretty far already and Clojure has built-in reader support for all the good stuff.&lt;/p&gt;

&lt;p&gt;But how hard would it be to have custom reader macros in Clojure if you wanted them?  Turns out not too hard if you're willing to ruthlessly break encapsulation and rely on implementation details.  Here's one way you could define a dispatch reader macro (i.e. one starting with &lt;code&gt;#&lt;/code&gt; and some specified second character):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defn dispatch-reader-macro [ch fun]
  (let [dm (.get (.getDeclaredField clojure.lang.LispReader &quot;dispatchMacros&quot;) nil)]
    (aset dm (int ch) fun)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Pass in a character and an fn and you get a reader macro.  For a silly example let's make reader syntax to uppercase a literal string.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defn uppercase-string [rdr letter-u]
  (let [c (.read rdr)]
    (if (= c (int \&quot;))
      (.toUpperCase (.invoke
                     (clojure.lang.LispReader$StringReader.)
                     rdr
                     c))
      (throw (Exception. (str &quot;Reader barfed on &quot; (char c)))))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The function is passed a reader and the dispatch character (which you can usually ignore).  I cheat and use Clojure's &lt;code&gt;StringReader&lt;/code&gt; to do the real work.&lt;/p&gt;

&lt;p&gt;Now I can do this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;user&amp;gt; (dispatch-reader-macro \U uppercase-string)
#&amp;lt;user$uppercase_string__1295 user$uppercase_string__1295@9b59a2&amp;gt;

user&amp;gt; #U&quot;Foo bar BAZ&quot;
&quot;FOO BAR BAZ&quot;

user&amp;gt; (println #U&quot;foo\nbar&quot;)
FOO
BAR
nil

user&amp;gt; #U(blarg)
java.lang.Exception: Reader barfed on (

(= &quot;FOO&quot; &quot;foo&quot;)
false

(= &quot;FOO&quot; #U&quot;foo&quot;)
true
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Oh sweet Jesus don't use this in real code, because: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The community will rightly hunt you down with torches and pitchforks.&lt;/li&gt;
&lt;li&gt;Reader macro characters are reserved and may conflict with later changes to the core language. &lt;/li&gt;
&lt;li&gt;These are set globally, not per-namespace.&lt;/li&gt;
&lt;li&gt;And so on.  Just don't.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But I think it's a nice demonstration.  I've read opinions that Clojure isn't a Real Lisp™ because a lot of Clojure is written in Java and isn't extensible in Clojure itself, but that's generally not true.   The reader code for Clojure was all written in Java, but above I modify it from Clojure.  There is no line separating Java-land and Clojure-land.  It's all one big happy family.&lt;/p&gt;</description></item><item><title>Vim regexes are awesome</title><link>http://briancarper.net/blog/vim-regexes-are-awesome</link><guid>http://briancarper.net/blog/vim-regexes-are-awesome</guid><pubDate>Sat, 18 Apr 2009 14:47:54 -0700</pubDate><description>&lt;p&gt;Two years ago I wrote about how &lt;a href=&quot;http://briancarper.net/blog/vim-regexes&quot;&gt;Vim's regexes were no fun&lt;/a&gt; compared to &lt;code&gt;:perldo&lt;/code&gt; and &lt;code&gt;:rubydo&lt;/code&gt;.  Turns out I was wrong, it was just a matter of &lt;a href=&quot;http://briancarper.net/blog/lisp-syntax-doesnt-suck&quot;&gt;not being used to them&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;Vim's regexes are very good.  They have all of the good features of Perl/Ruby regexes, plus some extra features that don't make sense outside of a text editor, but are nonetheless very helpful in Vim.&lt;/p&gt;

&lt;p&gt;Here are a few of the neat things you can do.&lt;/p&gt;

&lt;h1&gt;Very magic&lt;/h1&gt;

&lt;p&gt;Vim regexes are inconsistent when it comes to what needs to be backslash-escaped and what doesn't, which is the one bad thing.  But Vim lets you put &lt;code&gt;\v&lt;/code&gt; to make everything suddenly consistent: everything except letters, numbers and underscores becomes &quot;special&quot; unless backslash-escaped.&lt;/p&gt;

&lt;p&gt;Without &lt;code&gt;\v&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:%s/^\%(foo\)\{1,3}\(.\+\)bar$/\1/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With &lt;code&gt;\v&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:%s/\v^%(foo){1,3}(.+)bar$/\1/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Far easier to read.  Along with &lt;code&gt;\c&lt;/code&gt; to turn on and off case sensitivity, these are good options to make a habit of prepending to regexes when needed.  It eventually becomes second-nature.  See also &lt;code&gt;:h /\v&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;Spanning newlines&lt;/h1&gt;

&lt;p&gt;One thing that &lt;code&gt;:perldo&lt;/code&gt; and &lt;code&gt;:rubydo&lt;/code&gt; can't do is span newlines; you can't combine two lines and you can't break one line into two.&lt;/p&gt;

&lt;p&gt;But Vim's regexes can span newlines if you use &lt;code&gt;\_.&lt;/code&gt; instead of &lt;code&gt;.&lt;/code&gt;.  I find this to be a lot more aesthetically pleasing than Perl's horrible &lt;code&gt;s&lt;/code&gt; and &lt;code&gt;m&lt;/code&gt; modifiers tacked onto the end of a regex.  e.g. this strips &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tags from a text document.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:%s@&amp;lt;body&amp;gt;\v(\_.+)\V&amp;lt;/body&amp;gt;@\1@
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(Note: in real life, never use a regex to parse HTML or XML.  Down that path lies madness.  The above is OK because I'd expect only one &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag to appear in any document.)&lt;/p&gt;

&lt;p&gt;(Note^2: being able to turn on and off magic in the middle of a regex is awfully helpful.)&lt;/p&gt;

&lt;p&gt;(Note^4: You can use arbitrary delimiters like &lt;code&gt;@&lt;/code&gt; for the regex, which is useful if your pattern includes literal &lt;code&gt;/&lt;/code&gt;'s.)&lt;/p&gt;

&lt;p&gt;See also &lt;code&gt;:h \_.&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;&lt;code&gt;\zs&lt;/code&gt;&lt;/h1&gt;

&lt;p&gt;Vim lets you demand that some text match, but ignore that text when it comes to the substitution part.  This is handy for certain specific kinds of regexes.  Normally if you want to match some text and then leave it alone in the substitution, you have to capture it and then put it back manually; &lt;code&gt;\zs&lt;/code&gt; lets you avoid this. &lt;/p&gt;

&lt;p&gt;Say you want to chop some text off the end of a line, but leave the rest of the line alone.  Normally you'd have to do this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:%s/\v^(foobar)(baz)/\1/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to put the &lt;code&gt;foobar&lt;/code&gt; back.  Of course you can also use a zero-width lookbehind assertion:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:%s/\v(^foobar)@&amp;lt;=baz//
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But that's even more line-noise.  This is the easiest way:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:%s/^foobar\zsbaz//
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See &lt;code&gt;:h /\zs&lt;/code&gt;.  (And &lt;code&gt;:h /\@&amp;lt;=&lt;/code&gt; if you're so inclined.)&lt;/p&gt;

&lt;h1&gt;Expressions&lt;/h1&gt;

&lt;p&gt;Using &lt;code&gt;\=&lt;/code&gt;, you can put arbitrary expressions on the right side of a regex substitution.  For example say you have this text:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;~/foo ~/bar
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you do this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:%s/\v(\S+)/\=expand(submatch(1))/g
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You end up with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/home/user/foo /home/user/bar
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Because you can also call your own user-defined functions in the expression part, this can end up being pretty powerful.  For example it can be used to &lt;a href=&quot;http://vim.wikia.com/wiki/Substitute_with_incrementing_numbers&quot;&gt;insert incrementing numbers&lt;/a&gt; into arbitrary places in your text.  See &lt;code&gt;:h sub-replace-\=&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;And so on&lt;/h1&gt;

&lt;p&gt;Read &lt;code&gt;:h regexp&lt;/code&gt; if you haven't already. Tons of other features in there that can make your life easy if you manage to internalize them.  It is difficult to get used to Vim's funky syntax if you're very familiar with Perl/Ruby-style regexes, but I think it's worth it.  Only took me two years!  (OK, more like a couple days of concerted effort after a year-and-a-half delay.)&lt;/p&gt;</description></item><item><title>Unicomp Customizer keyboard review</title><link>http://briancarper.net/blog/unicomp-customizer-keyboard-review</link><guid>http://briancarper.net/blog/unicomp-customizer-keyboard-review</guid><pubDate>Thu, 16 Apr 2009 19:52:39 -0700</pubDate><description>&lt;p&gt;I got my &lt;a href=&quot;http://pckeyboards.stores.yahoo.net/customizer.html&quot;&gt;Unicomp Customizer 105&lt;/a&gt; in the mail today.  This is a keyboard using the same technology as the infamous &lt;a href=&quot;http://en.wikipedia.org/wiki/IBM_Model_M&quot;&gt;IBM keyboards of yore&lt;/a&gt;.  &lt;/p&gt;

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

&lt;p&gt;The Customizer is an enormous blocky hunk of hard black and grey matte plastic.  It is the very antithesis of modern, soft, rounded, Apple-esque fashion.  It has no &quot;multimedia&quot; keys, it doesn't glow in the dark, it doesn't have a built-in USB hub, it looks distinctly 80's-ish, and it costs $70.  Why on earth would anyone want this thing?&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/screenshots/photos/customizer.png&quot;&gt;&lt;img src=&quot;/screenshots/photos/thumbs/customizer.png&quot; alt=&quot;/screenshots/photos/thumbs/customizer.png&quot; title=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A couple of reasons... one is that it's a status symbol of grizzled old hackers.  This keyboard has gotten a lot of good reviews, e.g. &lt;a href=&quot;http://hardware.slashdot.org/article.pl?sid=08/05/29/1334258&quot;&gt;last year on Slashdot&lt;/a&gt;, but I've heard the sentiment repeated elsewhere.  There are stories of people rescuing old IBM keyboards out of dumpsters and selling them on ebay.&lt;/p&gt;

&lt;p&gt;If it was simply a status symbol I would look away without a second glance.  (Which is why I own a &lt;a href=&quot;http://www.cowonamerica.com/products/cowon/d2/&quot;&gt;Cowon D2&lt;/a&gt; and not an iPod.  I like to research my purchases to the point of paranoia.)  &lt;/p&gt;

&lt;p&gt;But the popularity seems to be backed up by real functionality and build quality.  These keyboards have a reputation for being great to type on due to the unique feel of their buckling spring &quot;clicky&quot; keys, and for being indestructible, with some keyboards still in use after two decades.  So I decided why not see for myself?&lt;/p&gt;

&lt;p&gt;A keyboard is the main tool of my livelihood and one of the main tools of most of my hobbies.  It makes sense to try to get the best tool for the job.  The three most important parts of a computer in my opinion are the keyboard, mouse, and monitor.  CPU?  RAM?  Hard disk space? I'll take whatever you give me.  But the things I interact with on a constant basis, I want those things to be comfortable.&lt;/p&gt;

&lt;h1&gt;Clicka clicka clicka&lt;/h1&gt;

&lt;p&gt;Yeah, this thing is clicky.  Even after all the reviews, I was unprepared for just how clicky it is.  You can feel the click of each keypress in your fingers and hear the clicking from 3 miles away.&lt;/p&gt;

&lt;p&gt;I tried pushing a key down slowly to make it click without activating a keypress, and I found it very difficult if not impossible.  You can always tell when you've successfully pressed a key on this keyboard: if it clicked, you did; if it didn't click, you didn't.&lt;/p&gt;

&lt;p&gt;One bad thing about the clicking is annoying everyone in the room with you.  I'm a bit worried I'm slowly going to drive my wife insane.&lt;/p&gt;

&lt;h1&gt;Finger workout&lt;/h1&gt;

&lt;p&gt;The keys have a lot of weight to them compared to the mushy feel of modern keyboards (which usually use some rubber or plastic dome under the keys).  The Customizer's keys have little springs in them, and you can feel the keys pushing back on your fingers as you type.  It feels much different than any other keyboard I've used.&lt;/p&gt;

&lt;p&gt;Is it a good or bad feel?  I'm undecided.  It does feel pretty good, there's a lot of response to the keyboard and you can more easily tell when you miss a key or flub a keypress and hit two keys at once.  I think this probably aids accuracy.  I don't type more accurately but I more easily notice my mistakes.&lt;/p&gt;

&lt;p&gt;I'm afraid the weight might lead to fatigue though; the keys are harder to press than other keyboards and my hands feel like they're getting a workout in comparison. However I've had a few long nights of typing on this keyboard and haven't noticed any more fatigue than usual, so the worry may be unfounded.  On the other hand, I do often notice how annoying it is to type on a laptop which has no resistance and no distance to the keys at all.  The resistance in this keyboard is a nice change of pace.&lt;/p&gt;

&lt;h1&gt;Built well?&lt;/h1&gt;

&lt;p&gt;I think &quot;indestructible&quot; is probably an apt word.  I've only had mine for a couple days, but just hefting the thing, you can tell it's built like a tank.  Very thick hard plastic all around.  It weighs a ton.  If I had to choose a keyboard to use as a weapon in a pinch, I'd grab this one immediately.&lt;/p&gt;

&lt;p&gt;The keys come off easily; every key is just a cap over a smaller plastic key beneath, and that cap is a simple piece atop a tube with a spring in it.  There isn't a lot of room for mechanical failure here unless you lose the springs.  Everything comes off and goes back on very easily, which is nice for when I need to clean out the gunk in a year.&lt;/p&gt;

&lt;p&gt;I have heard that if you spill a cup of milk into one of these keyboards, you may find it hard to drain.  So don't do that.&lt;/p&gt;

&lt;h1&gt;Lack of features is a feature&lt;/h1&gt;

&lt;p&gt;Multimedia keys suck.  I've never used them.  They waste space and the only time I remember they exist is when I push them accidentally.  &lt;/p&gt;

&lt;p&gt;The Customizer is very &quot;traditional&quot;.  There are no multimedia keys, no volume controls, no programmable (i.e. useless) macro keys, no email or internet shortcuts.  Just the standard 105 keys.   This is a plus in my book.&lt;/p&gt;

&lt;p&gt;Caps Lock is slightly shortened with a gap between itself and the A key, which is nice to avoid hitting it accidentally.  The version of the keyboard I got has a modern Super (&quot;windows&quot;) modifier key, but you can get a version without even that, if you like.  Otherwise there are no frills.&lt;/p&gt;

&lt;h1&gt;Speed typing&lt;/h1&gt;

&lt;p&gt;I took a couple of silly online typing tests, and I got between 75 and 95 WPM with 98% accuracy, which is as good as I've ever gotten.  My six-fingered typing style is a bit odd but this keyboard suits me well.&lt;/p&gt;

&lt;p&gt;WPM is a terrible measure of programming speed, because programming has a much higher punctuation-to-letter ratio than English prose.  So I also tried an Emacs session and a bunch of Vimming, and I experienced no problems.  I forgot I was using this keyboard almost immediately, which is a good thing.  It means it wasn't annoying me.&lt;/p&gt;

&lt;p&gt;Very important to me, as a Vimmer, is the position and size of the Escape key.  I have &lt;a href=&quot;http://www.logitech.com/index.cfm/keyboards/keyboard/devices/285&amp;amp;cl=US,EN&quot;&gt;one other keyboard&lt;/a&gt; that has Escape offset to the right a half inch, which is horrendous and messes up my Vimming all the time.  My &lt;a href=&quot;http://www.saitek.com/uk/prod/eclipseii.htm&quot;&gt;other other keyboard&lt;/a&gt; has a tiny little Escape key, half as big as a normal key, which is equally bad.&lt;/p&gt;

&lt;p&gt;On the Customizer, Escape is positioned off by itself in the corner as it should be, with a ton of space between itself and the number row, and the Escape key itself is freaking enormous.  This is a huge plus in my book.  You can't miss Escape on this keyboard.&lt;/p&gt;

&lt;p&gt;Similarly, all the other keys are the right sizes and in the right places.&lt;/p&gt;

&lt;h1&gt;Verdict&lt;/h1&gt;

&lt;p&gt;So how is the Unicomp Customizer?&lt;/p&gt;

&lt;p&gt;It's solid, standard, unique, and has a nice retro, minimalist style that I personally enjoy.&lt;/p&gt;

&lt;p&gt;It's also huge, loud, and expensive.  Is it worth buying?  If you have the money to spend, I think it is.  I don't regret the buy after a few days.  When I come home from work and start typing on this guy, I'm always pleasantly surprised.&lt;/p&gt;</description></item><item><title>A Sad, Dark Day</title><link>http://briancarper.net/blog/a-sad-dark-day</link><guid>http://briancarper.net/blog/a-sad-dark-day</guid><pubDate>Mon, 13 Apr 2009 01:27:12 -0700</pubDate><description>&lt;p&gt;Today was a terrible day.  I found myself subconsciously trying to use Emacs keystrokes in Vim.  I feel dirty.  I took a bath but it won't come clean.  : (&lt;/p&gt;

&lt;p&gt;It just goes to show that &lt;a href=&quot;/blog/lisp-syntax-doesnt-suck&quot;&gt;you can get used to anything&lt;/a&gt; if you do it often enough.  Emacs still drives me up the wall but maybe I've achieved a critical mass of enough custom keybindings to let me tolerate it.&lt;/p&gt;

&lt;p&gt;Aside from &lt;code&gt;paredit&lt;/code&gt;, which has no equal even in Vim, Emacs does have some vaguely non-sucky features.  &lt;code&gt;hi-lock&lt;/code&gt; is pretty nice (Vim has an equivalent of course).  Once I learned a few of the shortcuts for &lt;a href=&quot;http://github.com/tsgates/git-emacs/tree/master&quot;&gt;git-emacs&lt;/a&gt; I actually found myself using Git much more effectively.  Having to drop into a shell to type Git commands is just enough of a disruption to prevent me from doing it often enough.  I never got the hang of any version control library in Vim.&lt;/p&gt;

&lt;p&gt;I'm almost even getting used to the Emacs buffer model.  I find myself &lt;code&gt;C-x b&lt;/code&gt;ing and flipping back and forth between buffers by name, rather than my Vim practice of opening buffers in certain carefully-placed windows and leaving them there.&lt;/p&gt;

&lt;p&gt;On the subject of typing, I broke down finally and ordered a &lt;a href=&quot;http://pckeyboards.stores.yahoo.net/customizer.html&quot;&gt;Unicomp Customizer 104 keyboard&lt;/a&gt;.  I've heard too many hackers say that the old IBM clicky keyboards are good for typing.  It should arrive Tuesday, and I'm a lot more excited than anyone should be over a keyboard.  &lt;/p&gt;

&lt;p&gt;Expect a keyboard review.  Try to contain your excitement until then.  I know it'll be hard.&lt;/p&gt;</description></item><item><title>KDE4 Konsole Kolor Skheme Kdownload</title><link>http://briancarper.net/blog/kde4-konsole-kolor-skheme-kdownload</link><guid>http://briancarper.net/blog/kde4-konsole-kolor-skheme-kdownload</guid><pubDate>Sun, 12 Apr 2009 20:31:19 -0700</pubDate><description>&lt;p&gt;I put a &lt;a href=&quot;http://briancarper.net/page/kde&quot;&gt;color scheme&lt;/a&gt; for KDE4's Konsole up for download.  From a cursory glance I think KDE3 and KDE4 color schemes are the same format, but I haven't tried it.&lt;/p&gt;

&lt;p&gt;Also I know I'm not the first to say it, but all of the K's in KDE program names are a bit annoying after a while, aren't they?&lt;/p&gt;</description></item><item><title>Blog and CRUD</title><link>http://briancarper.net/blog/blog-and-crud</link><guid>http://briancarper.net/blog/blog-and-crud</guid><pubDate>Sun, 12 Apr 2009 20:01:35 -0700</pubDate><description>&lt;p&gt;I updated my &lt;a href=&quot;http://github.com/briancarper/cow-blog/tree/master&quot;&gt;blog source code on github&lt;/a&gt;.  I also split my CRUD library out into its own &lt;a href=&quot;http://github.com/briancarper/clj-crud/tree/master&quot;&gt;clj-crud&lt;/a&gt; repo.  It is cruddy, so the name is apt.&lt;/p&gt;

&lt;p&gt;This code still isn't polished enough for someone to drop it on a server and fire it up, but maybe it'll give someone some ideas.  I think the new code is cleaner and it'll be easier for me to add features now.&lt;/p&gt;

&lt;p&gt;Beware bugs, I'm positive I introduced some.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EDIT&lt;/strong&gt;: A word about the CRUD library... persisting data to disk is hard when the data may be mutated by many threads at once and the destination for your data is an SQL database that may or may not even be running.  I have more respect for people who've written libraries that actually do this kind of thing and work right.  Granted I only spent 3 days on mine but still, it's tricky.&lt;/p&gt;

&lt;p&gt;I gave up for a while and tried &lt;a href=&quot;http://github.com/duelinmarkers/clj-record/tree/master&quot;&gt;clj-record&lt;/a&gt;, but it was prohibitively slow.  It has the old N+1 queries problem when trying to select an object which has N sub-objects.  In real life you'd write SQL joins to avoid such things.  Ruby on Rails on the other hand gets around this via some nasty &lt;code&gt;find&lt;/code&gt; syntax.  &lt;/p&gt;

&lt;p&gt;I get around it by having all my data in a Clojure ref in RAM already so it doesn't matter.  And by using hooks so each object keeps a list of its sub-objects and the list is always up-to-date (updates of sub-objects propagate to their parents).  But the crap I have to do to get this to just barely work is pretty painful.&lt;/p&gt;</description></item><item><title>Lisp Syntax Doesn't Suck</title><link>http://briancarper.net/blog/lisp-syntax-doesnt-suck</link><guid>http://briancarper.net/blog/lisp-syntax-doesnt-suck</guid><pubDate>Wed, 08 Apr 2009 04:03:12 -0700</pubDate><description>&lt;p&gt;I spend a lot of time talking about what I don't like about various languages, but I never talk about what I do like.  And I do like a lot, or I wouldn't spend so much time programming and talking about programming.&lt;/p&gt;

&lt;p&gt;So here goes.  I like the syntax of Lisp.  I like the prefix notation and the parentheses.&lt;/p&gt;

&lt;h1&gt;Common Complaints&lt;/h1&gt;

&lt;p&gt;A common criticism of Lisp from non-Lispers is that the syntax is ugly and weird.  The parentheses are impossible to keep balanced.  It ends up looking like &quot;&lt;a href=&quot;http://en.wikiquote.org/wiki/Larry_Wall&quot;&gt;oatmeal with fingernail clippings mixed in&lt;/a&gt;&quot;.&lt;/p&gt;

&lt;p&gt;Also, prefix notation is horrible. &lt;code&gt;1 + 2&lt;/code&gt; is far superior to &lt;code&gt;(+ 1 2)&lt;/code&gt;.  Infix notation is how everyone learns things and how all the other languages do it.  There are countless numbers of people (&lt;a href=&quot;http://www.dwheeler.com/readable/sweet-expressions.html&quot;&gt;example&lt;/a&gt;) who have proposed to &quot;fix&quot; this, to give Lisp some kind of infix notation.  The topic inevitably comes up on Lisp mailing lists and forums.&lt;/p&gt;

&lt;p&gt;Partly this is subjective opinion and can't be argued with.  I can't say that Lispy parens shouldn't be ugly for people, any more than I can say that someone is wrong to think that peanut butter is gross even though I like the taste of it.  But in another sense, does it matter that it's painful?  Does it need to be changed?  Should the weird syntax stop you from learning Lisp?&lt;/p&gt;

&lt;h1&gt;Prefix Notation: Not Intuitive?&lt;/h1&gt;

&lt;p&gt;There is no &quot;intuitive&quot; when it comes to programming.  There's only what we're used to and what we aren't.&lt;/p&gt;

&lt;p&gt;What does &lt;code&gt;=&lt;/code&gt; mean in a programming language?  Most people from a C-ish background will immediately say assignment.  &lt;code&gt;x = 1&lt;/code&gt; means &quot;give the variable/memory location called &lt;code&gt;X&lt;/code&gt; the value &lt;code&gt;1&lt;/code&gt;&quot;.&lt;/p&gt;

&lt;p&gt;For non-programmers, &lt;code&gt;=&lt;/code&gt; is actually an equality test or a statement of truth.  &lt;code&gt;2 + 2 = 4&lt;/code&gt;; this is either a true or false statement.  There is no &quot;assignment&quot;.  The notion of assignment statements is an odd bit of programming-specific jargon.  In most programming languages we've learned instead that &lt;code&gt;==&lt;/code&gt; is an equality test.  Of course some have &lt;code&gt;:=&lt;/code&gt; for assignment and &lt;code&gt;=&lt;/code&gt; for equality tests.  But &lt;code&gt;=&lt;/code&gt; and &lt;code&gt;==&lt;/code&gt; seems to be more common.  Some languages even have &lt;code&gt;===&lt;/code&gt;.  Or &lt;code&gt;x.equals(y)&lt;/code&gt;.  Even less like what we're used to.  (Don't get started on such magic as &lt;code&gt;+=&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;Most of us have no problem with these, after a while.  But few of us were programmers before we learned basic math.  How many of us remember the point in time when we had to re-adjust our thinking that &lt;code&gt;=&lt;/code&gt; means something other than what we've always learned it to mean?  I actually do remember learning this, over a decade ago.  This kind of un-learning is painful and confusing, there's no question.&lt;/p&gt;

&lt;p&gt;But it's also necessary, because these kinds of conventions are arbitrary and vary between fields of study (and between programming languages).  And there are only so many symbols and words available to use, so we re-use them.  None of the meanings for &lt;code&gt;=&lt;/code&gt; is &quot;right&quot; or more &quot;intuitive&quot; than the other.  &lt;code&gt;=&lt;/code&gt; has no inherent meaning.  It means whatever we want it to mean.  Programming is chock-full of things like this that makes no sense until you memorize the meaning of them.&lt;/p&gt;

&lt;p&gt;Consider a recent article that got a lot of discussion, about why &lt;a href=&quot;http://www.codinghorror.com/blog/archives/001248.html&quot;&gt;all programmers should program in English&lt;/a&gt;.  How much less intuitive can you get, for a native speaker of another language to program using words in English?  Yet they manage.  (Have you ever learned to read sheet music?  Most of the terms are in Italian.  I don't speak a word of Italian, yet I managed.)&lt;/p&gt;

&lt;p&gt;The point is that it's very painful to un-learn things that seem intuitive, and to re-adjust your thinking, but it's also very possible.  We've all done it before to get to where we are.  We can all do it again if we need to.&lt;/p&gt;

&lt;p&gt;Prefix notation is unfamiliar and painful for many people.  When I first started learning Lisp, the prefix notation was awfully hard to read without effort, even harder to write.  I would constantly trip up.  This is a real distraction when you're trying to write code and need to concentrate.  But it only took me maybe a week of constant use to ingrain prefix notation to the point where it didn't look completely alien any longer.&lt;/p&gt;

&lt;p&gt;At this point prefix notation reads to me as easily as infix notation.  I breeze right through Lisp code without a pause.  In Clojure, you can write calls to Java methods in Java order like &lt;code&gt;(. object method arg arg arg)&lt;/code&gt; or you can use a Lispy order like &lt;code&gt;(.method object arg arg arg)&lt;/code&gt;; I find myself invariably using the Lispy way, as does most of the community, even though the more traditional notation is available.&lt;/p&gt;

&lt;p&gt;You can get used to it if you put in a minimal amount of effort.  It's not that hard.&lt;/p&gt;

&lt;h1&gt;Benefits of Prefix Notation&lt;/h1&gt;

&lt;p&gt;Why bother using prefix notation if infix and prefix are equally good (or bad)?  For one thing, prefix notation lets you have variable-length parameter lists for things that are binary operations in other languages.  In an infix language you must say &lt;code&gt;1 + 2 + 3 + 4 + 5&lt;/code&gt;.  In a prefix language you can get away with &lt;code&gt;(+ 1 2 3 4 5)&lt;/code&gt;.  This is a good thing; it's more concise and it makes sense.&lt;/p&gt;

&lt;p&gt;Most languages stop at offering binary operators because that's as good as you get when you have infix operators.  There's a ternary operator &lt;code&gt;x?y:z&lt;/code&gt; but it's an exception.  In Lisp it's rare to find a function artificially limited to two arguments.  Functions tend to take as many arguments as you want to throw at them (if it makes sense for that function).&lt;/p&gt;

&lt;p&gt;Prefix notation is consistent.  It's always &lt;code&gt;(function arg arg arg)&lt;/code&gt;.  The function comes first, everything else is an argument.  Other languages are not consistent.  Which is it, &lt;code&gt;foo(bar, baz)&lt;/code&gt;, or &lt;code&gt;bar.foo(baz)&lt;/code&gt;?  There are even oddities in some languages where to overload a &lt;code&gt;+&lt;/code&gt; operator, you write the function definition prefix, &lt;code&gt;operator+(obj1, obj2)&lt;/code&gt;, but to call that same function you do it infix, &lt;code&gt;obj1 + obj2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The consistency of Lisp's prefix notation opens up new possibilities for Lispy languages (at least, Lisp-1 languages).  If the language knows the first thing in a list is a function, you can put any odd thing you want in there and the compiler will know to call it as a function.  A lambda expression (anonymous function)?  Sure.  A variable whose value is a function?  Why not?  And if you put a variable whose value is a function in some place other than at the start of a list, the language knows you mean to pass that function as an argument, not call it.  Other languages are far more rigid, and must resort to special cases (like Ruby's rather ugly block-passing syntax, or explicit &lt;code&gt;.call&lt;/code&gt; or &lt;code&gt;.send&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Consistency is good.  It's one less thing you have to think about, it's one less thing the compiler has to deal with.  Consistent things can be understood and abstracted away more easily than special cases.  The syntax of most languages largely consists of special cases.&lt;/p&gt;

&lt;h1&gt;Parens: Use Your Editor&lt;/h1&gt;

&lt;p&gt;The second major supposed problem with Lisp syntax is the parens.  How do you keep those things balanced?  How do you read that mess?&lt;/p&gt;

&lt;p&gt;Programming languages are partly for human beings and partly for computers.  Programming in binary machine code would be impossible to read for a human.  Programming in English prose would be impossible to parse and turn into a program for a computer.  So we meet the computer halfway.  The only question is where to draw the line.&lt;/p&gt;

&lt;p&gt;The line is usually closer to the computer than to the human, for any sufficiently powerful language.  There are very few programing languages where we don't have to manually line things up or match delimiters or carefully keep track of punctuation (or syntactic whitespace, or equivalent).&lt;/p&gt;

&lt;p&gt;For example, any language with strings already makes you pay careful attention to quotation marks.  And if you embed a quotation mark in a quote-delimited string, you have to worry about escaping.  And yet we manage.  In fact I think that shell-escaping strings is a much hairier problem than balancing a lot of parens, but we still manage.&lt;/p&gt;

&lt;p&gt;This is sadly a problem we must deal with as programmers trying to talk to computers.  And we deal with it partly by having tools to help us.  Modern text editors do parenthesis matching for you.  If you put the cursor on a paren, it highlights the match.  In Vim you can bounce on the &lt;code&gt;%&lt;/code&gt; key to jump the cursor between matching parens.  Many editors go one step further and insert the closing paren whenever you insert an opening one.  Emacs of course goes one step further still and gives you &lt;a href=&quot;http://www.emacswiki.org/emacs/ParEdit&quot;&gt;ParEdit&lt;/a&gt;.  Some editors will even color your parens like a rainbow, if that floats your boat.  Keeping parens matched isn't so hard when you have a good editor.&lt;/p&gt;

&lt;p&gt;And Lisp isn't all about the parens.  There are also generally-accepted rules about indentation.  No one writes this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defn foo [x y] (if (= (+ x 5) y) (f1 (+ 3 x)) (f2 y)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That is hard to read, sure.  Instead we write this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defn foo [x y]
  (if (= (+ x 5) y)
    (f1 (+ 3 x))
    (f2 y)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is no more difficult to scan visually than any other language, once you're used to seeing it.  And all good text editors will indent your code strangely if you forget to close a paren.  It will be immediately obvious.&lt;/p&gt;

&lt;p&gt;A common sentiment in various Lisp communities is that Lispers don't even see the parens; they only see the indentation.  I wouldn't go that far, but I would say that the indentation makes Lisp code easily bearable.  As bearable as a bunch of gibberish words and punctuation characters can ever be for a human mind.&lt;/p&gt;

&lt;p&gt;When I was first learning Lisp I did have some pain with the parens.  For about a week.  After learning the features of Vim and Emacs that help with paren-matching, that pain went away.  Today I find it easier to work with and manipulate paren-laden code than I do to work with other languages.&lt;/p&gt;

&lt;h1&gt;Benefits of the Parens&lt;/h1&gt;

&lt;p&gt;Why bother with all the parens if there's no benefit?  One benefit is lack of precedence rules.  Lisp syntax has no &quot;order of operations&quot;.  Quick, what does &lt;code&gt;1 + 2 * 3 / 4 - 5&lt;/code&gt; mean?  Not so hard, but it takes you a second or two of thinking.  In Lisp there is no question: &lt;code&gt;(- (+ 1 (/ (* 2 3) 4)) 5)&lt;/code&gt;.  It's always explicit.  (It'd look better properly indented.)&lt;/p&gt;

&lt;p&gt;This is one less little thing you need to keep in short-term memory.  One less source of subtle errors.  One less thing to memorize and pay attention to.  In languages with precedence rules, you usually end up liberally splattering parens all over your code anyways, to disambiguate it.  Lisp just makes you do it consistently.&lt;/p&gt;

&lt;p&gt;As I hinted, code with lots of parens is easy for an editor to understand. This make it easier to manipulate, which makes it faster to write and edit.  Editors can take advantage, and give you powerful commands to play with your paren-delimited code.&lt;/p&gt;

&lt;p&gt;In Vim you can do a &lt;code&gt;ya(&lt;/code&gt; to copy an s-exp.  Vim will properly match the parens of course, skipping nested ones.  Similarly in Emacs you can do &lt;code&gt;C-M-k&lt;/code&gt; to kill an s-exp.  How do you copy one &quot;expression&quot; in Ruby?  An expression may be one line, or five lines, or fifty lines, or half a line if you separate two statements with a semi-colon.  How do you select a code block?  It might be delimited by &lt;code&gt;do/end&lt;/code&gt;, or curly braces, or &lt;code&gt;def/end&lt;/code&gt;, or who knows.  There are plugins like &lt;a href=&quot;http://www.vim.org/scripts/script.php?script_id=39&quot;&gt;matchit&lt;/a&gt; and huge syntax-parsing scripts to help editors understand Ruby code and do these things, but it's not as clean as Lisp code.  Not as easy to implement and not as fool-proof that it'll work in all corner cases.&lt;/p&gt;

&lt;p&gt;ParEdit in Emacs gives you other commands, to split s-exps, to join them together, to move the cursor between them easily, to wrap and unwrap expressions in new parens.  This is all you need to manipulate any part of Lisp code.  It opens up possibilities that are difficult or impossible to do correctly in a language with less regular syntax.&lt;/p&gt;

&lt;p&gt;Of course this consistency is also partly why Lisps can have such nice macro systems to make programmatic code-generation so easy.  It's far easier to construct Lisp code as a bunch of nested lists, than to concatenate together strings in a proper way for your non-Lisp language of choice to parse.&lt;/p&gt;

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

&lt;p&gt;Yeah Lisp syntax isn't intuitive.  But nothing really is.  You can get used to it.  It's that not hard.  It has benefits.&lt;/p&gt;

&lt;p&gt;Sometimes it's worth learning things that aren't intuitive.  You limit yourself and miss out on some good things if you stick with what you already know, or what feels safe and sound.&lt;/p&gt;</description></item><item><title>Disabling Ctrl-Alt-Backspace</title><link>http://briancarper.net/blog/disabling-ctrl-alt-backspace</link><guid>http://briancarper.net/blog/disabling-ctrl-alt-backspace</guid><pubDate>Sat, 04 Apr 2009 23:44:41 -0700</pubDate><description>&lt;p&gt;After being reminded the hard way &lt;em&gt;yet again&lt;/em&gt; that C-S-Backspace in Emacs invokes the very handy &lt;code&gt;kill-whole-line&lt;/code&gt; function, but that C-M-Backspace, while uncomfortably similar to that key-chord, does something &lt;strong&gt;&lt;em&gt;very different&lt;/em&gt;&lt;/strong&gt;, I have now officially added to my /etc/X11/xorg.conf:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Section &quot;ServerFlags&quot;
    Option &quot;DontZap&quot; &quot;True&quot;
EndSection
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to prevent me from accidentally murdering my X server at the worst possible times.&lt;/p&gt;</description></item><item><title>Vim cterm colors</title><link>http://briancarper.net/blog/vim-256-cterm</link><guid>http://briancarper.net/blog/vim-256-cterm</guid><pubDate>Sat, 04 Apr 2009 12:48:06 -0700</pubDate><description>&lt;p&gt;Note to self.  Vim color schemes that only set &lt;code&gt;cterm&lt;/code&gt; colors don't work unless you &lt;code&gt;export TERM=xterm-256color&lt;/code&gt; in your terminal emulator.  Konsole in KDE4 seems to default to plain &lt;code&gt;xterm&lt;/code&gt;.  Took me a half hour to figure out why my color scheme wasn't working in Konsole.&lt;/p&gt;</description></item><item><title>Real Confusing Haskell</title><link>http://briancarper.net/blog/real-confusing-haskell</link><guid>http://briancarper.net/blog/real-confusing-haskell</guid><pubDate>Thu, 02 Apr 2009 23:44:54 -0700</pubDate><description>&lt;p&gt;I can pinpoint the exact page in &lt;a href=&quot;http://book.realworldhaskell.org/&quot;&gt;Real World Haskell&lt;/a&gt; where I became lost.  I was reading along surprisingly well until page 156, upon introduction of &lt;code&gt;newtype&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;At that my point my smug grin became a panicked grimace.  The next dozen pages were an insane downward spiral into the dark labyrinth of Haskell's type system.  I had just barely kept &lt;code&gt;data&lt;/code&gt; and &lt;code&gt;class&lt;/code&gt; and friends straight in my mind. &lt;code&gt;type&lt;/code&gt; I managed to ignore completely.  &lt;code&gt;newtype&lt;/code&gt; was the straw that broke the camel's back.&lt;/p&gt;

&lt;p&gt;As a general rule, Haskell syntax is incredibly impenetrable.  &lt;code&gt;=&amp;gt;&lt;/code&gt; vs. &lt;code&gt;-&amp;gt;&lt;/code&gt; vs. &lt;code&gt;&amp;lt;-&lt;/code&gt;?  I have yet to reach the chapter dealing with &lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt;.  The index tells me I can look forward to such wonders as &lt;code&gt;&amp;gt;&amp;gt;?&lt;/code&gt; and &lt;code&gt;==&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;|&amp;gt;&lt;/code&gt;.  Who in their right mind thought up the operator named &lt;code&gt;.&amp;amp;.&lt;/code&gt;?  The language looks like Japanese emoticons run amuck.  If and when I reach the &lt;code&gt;\(^.^)/&lt;/code&gt; operator I'm calling it a day.&lt;/p&gt;

&lt;p&gt;Maybe Lisp has spoiled me, but the prospect of memorizing a list of punctuation is wearisome.  And the way you can switch between prefix and infix notation using parens and backticks makes my eyes cross.  Add in syntactic whitespace and I don't know what to tell you.&lt;/p&gt;

&lt;p&gt;I could still grow to like Haskell, but learning a new language for me always goes through a few distinct stages: &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Curiosity -&gt; Excitement -&gt; Reality Sets In -&gt; Frustration -&gt; Rage&lt;/em&gt; ...&lt;/p&gt;

&lt;p&gt;At &lt;em&gt;Rage&lt;/em&gt; I reach a fork in the road: I either proceed through &lt;em&gt;Acceptance&lt;/em&gt; into &lt;em&gt;Fumbling&lt;/em&gt; and finally to &lt;em&gt;Productivity&lt;/em&gt;, or I go straight from &lt;em&gt;Rage&lt;/em&gt; to &lt;em&gt;Undying Hatred&lt;/em&gt;.  Haskell could still go either way.&lt;/p&gt;</description></item><item><title>My Poor Headphones</title><link>http://briancarper.net/blog/my-poor-headphones</link><guid>http://briancarper.net/blog/my-poor-headphones</guid><pubDate>Thu, 02 Apr 2009 11:45:01 -0700</pubDate><description>&lt;p&gt;My precious Grado SR-80's needed some emergency surgery a while back, resulting in &lt;a href=&quot;http://briancarper.net/screenshots/photos/img_2177.jpg&quot;&gt;this disaster&lt;/a&gt;.  They still work today, in the sense that sound is still emitted from them, but in terms of aesthetics, the situation has rapidly deteriorated.  I've got bare wire and sticky electrical tape hanging all over the place.  Also I'm probably one good yank away from snapping the wires off again.&lt;/p&gt;

&lt;p&gt;If anyone reading this has a good tutorial or information on re-wiring a set of headphones, it'd be appreciated.  I've never soldered anything in my life.  I don't know where to acquire the wires; I imagine any wire will do, but I'm clueless when it comes to such things.  I think I might like to do something like &lt;a href=&quot;http://www.sgheadphones.net/index.php?showtopic=7621&quot;&gt;this mod&lt;/a&gt; and run the wire up over the top, to prevent the inevitable twisting from destroying the wires in the future, but I'm uncertain I could pull it off without complete destruction.&lt;/p&gt;

&lt;p&gt;(At least I know enough about these things to cringe when people start talking about the &quot;performance&quot; of their headphone wires.  &lt;a href=&quot;http://www.audiorevelation.com/cre/product_info.php?cPath=24&amp;amp;products_id=296&quot;&gt;$400 for a hunk of wire?&lt;/a&gt;  Wow.)&lt;/p&gt;</description></item><item><title>Trying Arch</title><link>http://briancarper.net/blog/trying-arch</link><guid>http://briancarper.net/blog/trying-arch</guid><pubDate>Wed, 01 Apr 2009 00:52:41 -0700</pubDate><description>&lt;p&gt;Thanks to all who gave &lt;a href=&quot;http://briancarper.net/blog/gentoo-vmware-fail#comments&quot;&gt;helpful suggestions&lt;/a&gt; about running VMs in Gentoo.  The main reason I wanted a VM was to play around with some other distros and see what I liked.&lt;/p&gt;

&lt;p&gt;But then I got to thinking, and I realized that I have over 250 GB of free hard drive space sitting around.  So I made a new little partition and per Noah's suggestion, threw &lt;a href=&quot;http://www.archlinux.org/&quot;&gt;Arch Linux&lt;/a&gt; on there. &lt;/p&gt;

&lt;p&gt;I'm fairly impressed so far.  The install was easy.  In contrast to the enormous Gentoo handbook, the whole Arch install guide fits on one page of the &lt;a href=&quot;http://wiki.archlinux.org/index.php/Official_Arch_Linux_Install_Guide&quot;&gt;official Arch wiki&lt;/a&gt;.  Why doesn't Gentoo have an official wiki?  I know there are concerns over the quality of something anyone can edit, but in practice is it a big a deal?  Is it worth the price of sending users elsewhere, to potentially even WORSE places, when the Gentoo docs don't cover everything we need?  The quality of the &lt;a href=&quot;http://en.gentoo-wiki.com/wiki/Main_Page&quot;&gt;unofficial Gentoo wiki&lt;/a&gt; is often very good but sometimes hit-or-miss, and it also sort of crashes and loses all data without backups every once in a while.&lt;/p&gt;

&lt;p&gt;The Arch installer is a commandline app using ncurses for basic menus and such, which is more than sufficient and a good compromise between commandline-only and full-blown X-run Gnome bloat.  The install itself went fine, other than my own mistakes.  I'm sharing &lt;code&gt;/boot&lt;/code&gt; and &lt;code&gt;/home&lt;/code&gt; between Gentoo and Arch so I can switch between them easily.  During the install Arch tried to create some GRUB files, but they already existed care of Gentoo, so the install bombed without much notification and I didn't notice until 3 steps later.  No big deal to fix, but I'd have liked a louder error message right away when it happened.  The base install took about 45 minutes.&lt;/p&gt;

&lt;p&gt;Another nice thing is that the Arch install CD has &lt;code&gt;vi&lt;/code&gt; on it.  I didn't have to resort to freaking &lt;code&gt;nano&lt;/code&gt; or remember to install &lt;code&gt;vim&lt;/code&gt; first thing.  A mild annoyance to be sure, but it bugged me every time I installed Gentoo.&lt;/p&gt;

&lt;p&gt;After boot, installing apps via &lt;code&gt;pacman&lt;/code&gt; is simple enough.  KDE 4.2 installed in about 15 minutes, as you'd expect from a distro with binary packages.  I found a mirror with 1.5 Mb/sec downloads, which is awfully nice.  Syncing the package tree takes less than 2 seconds, which is also nice compared to Portage's 5-minute rsync and &lt;code&gt;eix&lt;/code&gt; update times.  Searching the tree via regex is also somehow instantaneous in Arch.&lt;/p&gt;

&lt;p&gt;Oddly, KDE didn't seem to pull in Xorg as a dependency, but other dependencies worked fine so far.  Time will tell how well this all holds up.  Most package managers do fine on the normal cases but the real test is the funky little obscure apps.  &lt;code&gt;pacman -S gvim&lt;/code&gt; resulted in a Vim with working &lt;code&gt;rubydo&lt;/code&gt; and &lt;code&gt;perldo&lt;/code&gt;, which means Arch passed the &lt;a href=&quot;/blog/oh-come-on&quot;&gt;Ubuntu stink test&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Another nice thing is that KDE4 actually &lt;em&gt;works&lt;/em&gt;.  My Gentoo install is years old and possibly crufted beyond repair, or something else was wrong, but I have yet to get KDE4 working in Gentoo without massive breakage.  Possibly if I wiped Gentoo and tried KDE4 without legacy KDE3 stuff everywhere it'd also be smooth.  &lt;/p&gt;

&lt;p&gt;Regardless, it all works in Arch.  NVidia drivers and Twinview settings were copy/pasted from Gentoo, and compositing all works fine.  No performance problems in KDE with resizing or dragging windows, no Plasma crashes (yet), no missing icons or invisible notification area.  QtCurve works in Qt3, Qt4 and GTK just fine.  My sound card worked without any manual configuration at all.  My mouse worked without tweaking, including the thumb buttons.  Same with networking, the install prompted me for my IP and gateway etc. and then it worked, no effort.&lt;/p&gt;

&lt;p&gt;I've mentioned before, but one nice thing about Linux is that if you have &lt;code&gt;/home&lt;/code&gt; in its own partition, it's no big deal at all to share it between distros.  With no effort at all I'm now using all my old files and settings in Arch, and I can switch back and forth between this and Gentoo without any troubles.&lt;/p&gt;

&lt;p&gt;So we'll see how this goes.  So far so good though.  Arch seems very streamlined and its goal is minimalism, which is nice.  Gentoo has not felt minimalistic to me in a while.  Again, may be due to the age of my install, cruft and bit-rot.&lt;/p&gt;</description></item><item><title>Gentoo VMWare Fail</title><link>http://briancarper.net/blog/gentoo-vmware-fail</link><guid>http://briancarper.net/blog/gentoo-vmware-fail</guid><pubDate>Tue, 31 Mar 2009 00:59:55 -0700</pubDate><description>&lt;p&gt;According to &lt;a href=&quot;http://bugs.gentoo.org/show_bug.cgi?id=260979&quot;&gt;this bug&lt;/a&gt;, VMWare on Gentoo is in a sorry state, with one lone person trying to keep it going.  I can't get &lt;code&gt;vmware-modules&lt;/code&gt; to compile on my system no matter what I try, which is depressing.  Kudos to all of our one-man army Gentoo devs who are keeping various parts of the distro going, but I wonder how many other areas of Gentoo are largely unmaintained nowadays.&lt;/p&gt;

&lt;p&gt;KVM was braindead simple to get set up in comparison with VMWare, but I can't get networking to work.  This is because I'm an idiot when it comes to TUN/TAP and iptables.  I've read wiki articles that suggest setting up my system to NAT-forward traffic into the VM but I couldn't get that working and don't have a lot of time to screw with it.&lt;/p&gt;

&lt;p&gt;On one of the Gentoo mailing lists I noticed that a dev has posted some &lt;a href=&quot;http://www.mail-archive.com/gentoo-dev@lists.gentoo.org/msg33099.html&quot;&gt;KVM images of Gentoo&lt;/a&gt; suitable for testing.  But I'm looking to start up an image from scratch and that doesn't help, and it's not going to help me get networking going any easier.&lt;/p&gt;

&lt;p&gt;Why do I feel like this'd take 10 minutes to set up on Ubuntu?  Look at &lt;a href=&quot;https://help.ubuntu.com/community/VMware&quot;&gt;this&lt;/a&gt;, or search for &quot;&lt;code&gt;ubuntu vmware&lt;/code&gt;&quot; and see the hundreds of results.  Given that it's a VM and it doesn't really matter what the host OS is anyways, I'll probably do that on my laptop, but it's still depressing.&lt;/p&gt;</description></item></channel></rss>
