<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>Technomancy</title>
  <id>tag:technomancy.us,2007:blog/</id>
  <link href="http://technomancy.us/feed/atom" rel="self" type="application/atom+xml"/>
  <link href="http://technomancy.us/" rel="alternate" type="text/html"/>
  <updated>2012-01-31T18:33:19Z</updated>

  
  <entry xml:base="http://technomancy.us">
    <author><name>Phil Hagelberg</name></author>
    <id>tag:technomancy.us,2007:in%20which%20an%20interview%20is%20posted</id>
    <published>2012-01-27T03:58:25Z</published>
    <updated>2012-01-27T03:58:25Z</updated>

    <link href="http://technomancy.us/157" rel="alternate" type="text/html"/>
    <title>in which an interview is posted</title>
    <content type="html">
      &lt;p&gt;The folks over at The Setup just posted
  &lt;a href=&quot;http://phil.hagelberg.usesthis.com/&quot;&gt;an interview&lt;/a&gt;
  with me wherein I rant about hardware, interactivity, and
  Emacs.&lt;/p&gt;

&lt;p&gt;Note: this was written up over a month ago; if I were interviewed
  today I couldn't help but mention
  the &lt;a href=&quot;http://nixos.org/nix&quot;&gt;Nix&lt;/a&gt; package manager. I use
  it on my Debian Squeeze system to complement &lt;tt&gt;apt-get&lt;/tt&gt;; I
  get all the system-level stuff that has to be stable from Debian
  and anything that needs to be fresh from Nix.&lt;/p&gt;
    </content>
  </entry>
  
  <entry xml:base="http://technomancy.us">
    <author><name>Phil Hagelberg</name></author>
    <id>tag:technomancy.us,2007:in%20which%20local%20hacking%20locations%20are%20surveyed</id>
    <published>2011-12-31T02:25:58Z</published>
    <updated>2011-12-31T02:25:58Z</updated>

    <link href="http://technomancy.us/156" rel="alternate" type="text/html"/>
    <title>in which local hacking locations are surveyed</title>
    <content type="html">
      &lt;p&gt;I'm lucky to have the chance to do my job remotely from wherever
  I like. Half the time I work out
  of &lt;a href=&quot;http://www.flickr.com/photos/technomancy/tags/laboratory&quot;&gt;my
  code lab&lt;/a&gt;, which is a converted shed in my back yard. But I
  venture out fairly frequently to local coffee shops. Here are a
  few of my favourites. I should mention that I'm a big fan of
  single-origin pour-over brews, so the list is biased in favour of
  places which serve that well rather than the more traditional
  espresso drinks. All these have at least one location in North
  Seattle.&lt;/p&gt;

&lt;h4&gt;&lt;a href=&quot;http://neptunecoffee.com&quot;&gt;Neptune&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;I'm here a lot because it's the only one on this list I don't
  need to get on the freeway for. The decor is a bit sparse, but
  they're quite friendly here and serve a mean pour-over. They've
  been known to even
  serve &lt;a href=&quot;http://www.youtube.com/watch?v=VbqJKDZNyic&quot;&gt;syphon-brewed
  coffee&lt;/a&gt;, which is always a treat to watch when they fire up the
  bunsen burner. The proprietor also
  runs &lt;a href=&quot;http://tehcoffee.com/&quot;&gt;tehcoffee.com&lt;/a&gt;, a
  (Heroku-hosted) site for competition-level baristas can rank and
  review others. The Greenwood neighborhood is great too; lots of
  lunch options and bookstores to browse. Bonus fact: Allie, the
  inventor
  of &lt;a href=&quot;http://hyperboleandahalf.blogspot.com/2010/04/alot-is-better-than-you-at-everything.html&quot;&gt;the
  mythical Alot beast&lt;/a&gt; has a blend here named after her.&lt;/p&gt;

&lt;img src=&quot;i/milstead.jpg&quot; alt=&quot;milstead views&quot; align=&quot;right&quot; /&gt;

&lt;h4&gt;&lt;a href=&quot;http://www.milsteadandco.com/&quot;&gt;Milstead &amp; Co.&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;This one has only opened relatively recently, but it's made a
  splash for a number of things, not the least of which is the
  spectacular waterfront view from under the Aurora bridge. The
  selection here is excellent; this is the only place on this list
  that serves beans from multiple roasters, and they offer plenty of
  variety in brewing methods. The interior is spacious with high
  ceilings; it's very inviting. Mr. Milstead himself is usually
  around, and his excitement about his craft is infectious and
  obvious once you get him talking. I'd be here all the time if it
  weren't the furthest (south) from where I live.&lt;/p&gt;

&lt;h4&gt;&lt;a href=&quot;http://zokacoffee.com&quot;&gt;Zoka&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;This one is my go-to place. I often run into people I know here,
  (and sometimes &lt;a href=&quot;http://theoatmeal.com/&quot;&gt;people I
  don't&lt;/a&gt;), and we hold
  the &lt;a href=&quot;http://seajure.github.com&quot;&gt;Seattle Clojure group&lt;/a&gt;
  meetings here as well. The University District location in
  particular works well for meetings just because it's so spacious;
  I don't think I've ever seen a larger coffee shop. It's a popular
  place for students to study, so it's pretty quiet in the back. It
  can be crowded at times though, probably based on the school
  schedule. They've got a great selection sourced from all over the
  world that rotates every so often. It's always fun to
  read &lt;a href=&quot;http://www.zokacoffee.com/blog/2011/03/jeffs-trip-to-nicaragua.html&quot;&gt;their
  blog posts about traveling to visit the growers&lt;/a&gt;. The &quot;Zoka
  bars&quot; they serve here are a ridiculously rich treat. The decor
  here is very warm and comfortable with wood paneling
  everywhere.&lt;/p&gt;

&lt;img src=&quot;i/trabant.jpg&quot; alt=&quot;trabant&quot; align=&quot;left&quot; /&gt;

&lt;h4&gt;&lt;a href=&quot;http://trabantcoffee.com&quot;&gt;Trabant&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;I don't come here often because the parking situation is awful,
  but if you are in the area (or taking the bus), definitely check
  out Trabant. They've got good chai, but the thing that keeps
  bringing me back here is
  the &lt;a href=&quot;http://www.slate.com/articles/life/drink/2008/03/could_a_coffee_maker_be_worth_11000.html&quot;&gt;Clover
  machine&lt;/a&gt;. This contraption is capable of extracting rich
  flavours out of a bean like nothing else. Unfortunately Starbucks
  purchased the company that sold them, so there aren't very many
  places with Clovers that offer good beans. (As the owner of
  Trabant said about the acquisition, &quot;wearing Air Jordans doesn't
  make you play like Michael Jordan.&quot;) Anyway, the downtown Trabant
  is very spare, minimalist, and quiet, while the one in the
  University district (pictured) is bustling and quirky.&lt;/p&gt;

&lt;h4&gt;Honorable Mentions&lt;/h4&gt;

&lt;dl&gt;
  &lt;dt&gt;&lt;a href=&quot;http://www.espressovivace.com/&quot;&gt;Vivace&lt;/a&gt;&lt;/dt&gt;
  &lt;dd&gt;I'm of the opinion that Vivace has the best espresso in
    Seattle. It's too far for me to visit regularly, but members of
    the famed
    &lt;a href=&quot;http://seattlerb.org&quot;&gt;Seattle Ruby Brigade&lt;/a&gt; can
    often be found working here in the afternoon.&lt;/dd&gt;

  &lt;dt&gt;&lt;a href=&quot;http://www.seattlecoffeeworks.com/&quot;&gt;Seattle Coffee Works&lt;/a&gt;&lt;/dt&gt;
  &lt;dd&gt;I've only been here a couple times, but I was floored by
    their Yirgacheffe both times. They serve their pour-overs at a
    separate &quot;slow bar&quot; where the baristas are happy to geek out
    over their creations if you show interest. Again, this one's
    too far away (Pike St.) to make me a regular.&lt;/dd&gt;

  &lt;dt&gt;&lt;a href=&quot;http://www.greenbeancoffee.org/&quot;&gt;Green Bean&lt;/a&gt;&lt;/dt&gt;
  &lt;dd&gt;This one is actually a non-profit which supports a number of
    other non-profits on a rotating basis. The staff here are really
    friendly. I like to come here early and get breakfast with my
    family since they've got a kids' corner.&lt;/dd&gt;

  &lt;dt&gt;&lt;a href=&quot;http://www.chocolati.com/&quot;&gt;Chocolati&lt;/a&gt;&lt;/dt&gt;
  &lt;dd&gt;I don't even come here for their coffee, but their hot
    chocolate is superb. They've also got great truffles. The
    Greenwood location is a converted house that offers plenty of
    space to work, while the Greenlake location is a lot smaller but
    has nice views of the water.&lt;/dd&gt;
&lt;/Dal&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;
    </content>
  </entry>
  
  <entry xml:base="http://technomancy.us">
    <author><name>Phil Hagelberg</name></author>
    <id>tag:technomancy.us,2007:in%20which%20version%20two%20seems%20a%20treacherous%20stage</id>
    <published>2011-12-01T07:15:11Z</published>
    <updated>2011-12-01T07:15:11Z</updated>

    <link href="http://technomancy.us/155" rel="alternate" type="text/html"/>
    <title>in which version two seems a treacherous stage</title>
    <content type="html">
      &lt;p&gt;I recently got back from
  the &lt;a href=&quot;http://clojure-conj.org/&quot;&gt;Clojure Conj&lt;/a&gt; conference
  in Raleigh. The sessions were great, but the main highlight for me
  was meeting with &lt;a href=&quot;http://flatland.org/&quot;&gt;the developers of
  Cake&lt;/a&gt; (an alternate Clojure build tool) and discussing how we
  could collaborate on the future of build tools in Clojure. As
  was &lt;a href=&quot;http://groups.google.com/group/leiningen/browse_thread/thread/5a79d02198a91b91&quot;&gt;announced&lt;/a&gt;
  &lt;a href=&quot;https://groups.google.com/group/clojure-cake/browse_thread/thread/186ec36c2426996e&quot;&gt;elsewhere&lt;/a&gt;,
  we will be taking some features from Cake and merging them into
  Leiningen 2.0 as well as just having more hackers involved in
  development efforts.&lt;/p&gt;

&lt;p&gt;The development of Leiningen 1.x pretty much just fell out of the
  usage patterns we saw during my time at Sonian as an early adopter
  of Clojure. We used Maven for eight months, tried to make it work,
  and then took our experience from the pain we saw there to
  Leiningen. Some features (especially checkout dependencies) arose
  directly from finding certain operations with multi-module Maven
  builds extremely cumbersome. But in general nearly everything
  about Leiningen so far has been obvious. I wouldn't say it
  practically wrote itself, but once the central model of a project
  map and resolving/applying tasks from defns was established, the
  only really tricky thing was being strict about establishing a
  narrow scope and knowing when to avoid adding features.&lt;/p&gt;

&lt;blockquote cite=&quot;http://twitter.com/#!/cemerick/status/131414628474437633&quot;&gt;
  &lt;p&gt;&quot;Version 2&quot; is the most dangerous phase in a software
    project's life.&lt;/p&gt;
  &lt;footer&gt;— &lt;a href=&quot;http://twitter.com/#!/cemerick/status/131414628474437633&quot;&gt;Chas
  Emerick&lt;/a&gt;&lt;/footer&gt;
&lt;/blockquote&gt;

&lt;p&gt;So now
  we're &lt;a href=&quot;https://github.com/technomancy/leiningen/wiki/VersionTwo&quot;&gt;digging
  into the question of what bigger-picture changes could be made&lt;/a&gt;
  to improve Leiningen if we leave backwards-compatibility out of
  it. The biggest improvement we've seen implemented so far is
  switching over dependency resolution to the Aether library
  via &lt;a href=&quot;https://github.com/cemerick/pomegranate&quot;&gt;Chas
  Emerick's Pomegranate library&lt;/a&gt;. Aether is a library that
  contains all the dependency management features from Maven
  extracted into an independent module&amp;mdash;basically designed with
  exactly Leiningen's use case in mind.&lt;/p&gt;

&lt;p&gt;But there's more coming. Cake has had the ability to run project
  code &lt;a href=&quot;https://github.com/flatland/classlojure&quot;&gt;in the same
  process as the build tool&lt;/a&gt;, significantly speeding up many
  operations, which is in the process of being ported over to
  Leiningen. I've been working on explicitly delimiting the parts of
  Leiningen that comprise its public API as part
  of &lt;a href=&quot;https://github.com/technomancy/leiningen/tree/master/leiningen-core&quot;&gt;a
  separate &quot;leiningen-core&quot; library&lt;/a&gt; which other tools can depend
  upon. We're looking at adding something like &quot;profiles&quot; do bundle
  up configuration sets which can be activated in given
  contexts.&lt;/p&gt;

&lt;p&gt;With all these ideas flying around I hope we can buckle down and
  get some solid design discussions resulting in well-factored
  features. If you've been looking to contribute, now is a great
  time. Join the &lt;tt&gt;#leiningen&lt;/tt&gt; channel on Freenode and hop on
  the &lt;a href=&quot;http://groups.google.com/group/leiningen/&quot;&gt;mailing
  list&lt;/a&gt;.&lt;/p&gt;
    </content>
  </entry>
  
  <entry xml:base="http://technomancy.us">
    <author><name>Phil Hagelberg</name></author>
    <id>tag:technomancy.us,2007:in%20which%20the%20lesser-known%20are%20brought%20to%20the%20forefront</id>
    <published>2011-10-28T17:21:54Z</published>
    <updated>2011-10-28T17:21:54Z</updated>

    <link href="http://technomancy.us/154" rel="alternate" type="text/html"/>
    <title>in which the lesser-known are brought to the forefront</title>
    <content type="html">
      &lt;p&gt;In my time hacking in Clojure I've found a bunch of
  under-appreciated Clojure libraries of which I'm rather fond. I
  thought it'd be helpful to share, so here they are:&lt;/p&gt;

&lt;h4&gt;&lt;a href=&quot;https://github.com/maravillas/lein-multi&quot;&gt;lein-multi&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;As support for Clojure 1.3 becomes widespread, it becomes more
  important for projects to think about backwards compatibility. You
  can specify a range of versions for Clojure in &lt;tt&gt;project.clj&lt;/tt&gt;
  with &lt;code&gt;[org.clojure/clojure &quot;[1.2.0,1.3.0]&quot;]&lt;/code&gt;, but when
  you're developing, it will just find the latest and pull that in,
  so it's easy for dependence on 1.3-specific features to sneak
  in.&lt;/p&gt;

&lt;p&gt;Enter lein-multi, a plugin for running arbitrary tasks against
  multiple dependency sets. It's most commonly used with
  the &lt;kbd&gt;test&lt;/kbd&gt; task, but it's a general higher-order task
  that can be applied to any other just as well.
  Seeing &lt;tt&gt;lein-multi&lt;/tt&gt; in someone's project.clj is a good
  indicator that they take backwards-compatibility seriously.
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[lein-multi &quot;1.0.0&quot;]&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;&lt;a href=&quot;https://github.com/mmcgrana/clj-stacktrace&quot;&gt;clj-stacktrace&lt;/a&gt;&lt;/h4&gt;

&lt;img src=&quot;i/clj-stacktrace.png&quot; alt=&quot;stack trace&quot; align=&quot;right&quot; /&gt;

&lt;p&gt;The most common complaint I hear about developing in Clojure is
  the fact that its error messages often obscure the true cause of
  the problem. While practice helps here, it's still true that
  there's a lot of irrelevant detail here that can overwhelm the
  trained eye. Mark McGranaghan's clj-stacktrace library does a
  great job at summarizing stack traces by aligning each frame,
  making the namespace distinct from the function name, and even
  coloring frames differently based on whether they come from
  Clojure, Java, or user code. The next version should let you
  filter out frames that are deemed irrelevant on a per-project
  basis.&lt;/p&gt;

&lt;p&gt;The web framework &lt;a href=&quot;http://webnoir.org&quot;&gt;Noir&lt;/a&gt; uses
  clj-stacktrace for its HTML error pages in development mode. To
  use it in your project's repl as well as
  in &lt;code&gt;clojure.test&lt;/code&gt; error reporting, place this code
  in &lt;tt&gt;~/.lein/init.clj&lt;/tt&gt; after running &lt;kbd&gt;$ lein plugin
  install clj-stacktrace 0.2.4&lt;/kbd&gt;:&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable-name&quot;&gt;require&lt;/span&gt; 'leiningen.hooks.clj-stacktrace-test&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;settings&lt;/span&gt; {&lt;span class=&quot;constant&quot;&gt;:repl-options&lt;/span&gt; [&lt;span class=&quot;constant&quot;&gt;:init&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable-name&quot;&gt;require&lt;/span&gt; 'clj-stacktrace.repl&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;
                              &lt;span class=&quot;constant&quot;&gt;:caught&lt;/span&gt; 'clj-stacktrace.repl/pst+]}&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;

&lt;h4&gt;&lt;a href=&quot;https://github.com/scgilardi/slingshot&quot;&gt;slingshot&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;Another common question you hear is &quot;How do I generate custom
  exception classes?&quot;. It's awkward and somewhat un-idiomatic to do
  this, so people generally try to get by with the Exception
  classes that ship with the JDK. But why shouldn't exceptions get
  the same level of dynamicity and flexibility that Clojure affords
  other data types?&lt;/p&gt;

&lt;p&gt;This is basically the question Slingshot addresses. It provides
  enhanced &lt;code&gt;try+&lt;/code&gt; and &lt;code&gt;throw+&lt;/code&gt; counterparts to
  the built-in error mechanisms that let you throw arbitrary data
  types like maps. Then rather than dispatching in your catch blocks
  based on class, you can use arbitrary predicates. You can even
  perform destructuring on maps that are thrown. It's a big step up
  in expressiveness:&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;defn&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;asplode!&lt;/span&gt; []
  &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;throw+ {&lt;span class=&quot;constant&quot;&gt;:bad?&lt;/span&gt; true &lt;span class=&quot;constant&quot;&gt;:tachyon-level&lt;/span&gt; 21}&lt;span class=&quot;esk-paren&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;defn&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;ignorable?&lt;/span&gt; [e]
  &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant&quot;&gt;:silent&lt;/span&gt; e&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable-name&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant&quot;&gt;:fatal?&lt;/span&gt; e&lt;span class=&quot;esk-paren&quot;&gt;))))&lt;/span&gt;

&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;try+ &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;asplode!&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;catch&lt;/span&gt; ignorable? _&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;constant&quot;&gt;:bad?&lt;/span&gt; e
    &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;log/warn &lt;span class=&quot;string&quot;&gt;&quot;Bummer dude!&quot;&lt;/span&gt; e&lt;span class=&quot;esk-paren&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;constant&quot;&gt;:fatal?&lt;/span&gt; {&lt;span class=&quot;constant&quot;&gt;:keys&lt;/span&gt; [exit-code]}
    &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;preprocessor&quot;&gt;System/exit&lt;/span&gt; exit-code&lt;span class=&quot;esk-paren&quot;&gt;)))&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;[slingshot &quot;0.8.0&quot;]&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;&lt;a href=&quot;https://github.com/brentonashworth/lein-difftest&quot;&gt;lein-difftest&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;If you've ever written a test where you expect two lengthy data
  structures to be equal, you'll remember how annoying it is to try
  to compare the failure message where &quot;expected&quot; and &quot;actual&quot; are
  each spat out on a single line and you're supposed to try to hunt
  down the difference. Using &lt;kbd&gt;lein difftest&lt;/kbd&gt; makes it easy:&lt;/p&gt;

&lt;a href=&quot;https://github.com/brentonashworth/lein-difftest&quot;&gt;
  &lt;img src=&quot;i/lein-difftest.png&quot; alt=&quot;difftest example&quot; /&gt;&lt;/a&gt;

&lt;p&gt;It also uses &lt;tt&gt;clj-stacktrace&lt;/tt&gt; to report errors. This one
  is better off installed as a user-level plugin since you're
  likely to want to be able to use the &lt;kbd&gt;difftest&lt;/kbd&gt; task
  across all your projects:&lt;/p&gt;

&lt;p&gt;&lt;kbd&gt;$ lein plugin install lein-difftest 1.3.7&lt;/kbd&gt;&lt;/p&gt;

&lt;h4&gt;&lt;a href=&quot;https://github.com/joegallo/robert-bruce&quot;&gt;robert-bruce&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;From the do-one-thing-and-do-it-well department, we have Robert
  Bruce, which concerns itself only with determinedly retrying a
  given function. It provides all the options you could imagine for
  how to perform the retries, including pausing between them (with
  exponential decay on backoffs), retry limits, callbacks on
  failure, and so on.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[robert/bruce &quot;0.7.1&quot;]&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;Happy hacking!&lt;/h4&gt;

&lt;p&gt;Do you have a favourite that I've missed here? Leave a comment
  about it. Remember that the version numbers provided here are
  current as of the time of this writing but may be outdated when
  you read this.&lt;/p&gt;
    </content>
  </entry>
  
  <entry xml:base="http://technomancy.us">
    <author><name>Phil Hagelberg</name></author>
    <id>tag:technomancy.us,2007:in%20which%20version%20two%20turns%20the%20inside%20out</id>
    <published>2011-09-28T04:12:54Z</published>
    <updated>2011-09-28T04:12:54Z</updated>

    <link href="http://technomancy.us/153" rel="alternate" type="text/html"/>
    <title>in which version two turns the inside out</title>
    <content type="html">
      &lt;p&gt;I just got back last week from
  the &lt;a href=&quot;https://thestrangeloop.com/&quot;&gt;Strange Loop
  conference&lt;/a&gt; in St. Louis. The conference showcased some really
  quality keynotes and session talks, but I had been invited to give
  a workshop teaching Emacs, which was a blast. The workshop was
  three hours long, but I still felt like I was zooming
  through. &lt;a href=&quot;http://p.hagelb.org/getting-cozy-with-emacs.org.html&quot;&gt;My
  outline&lt;/a&gt; is available, though it may not be all that useful
  unless you were there.&lt;/p&gt;

&lt;img src=&quot;i/cozy-with-emacs.jpg&quot; alt=&quot;getting cozy&quot; align=&quot;right&quot; /&gt;

&lt;p&gt;The talk focused on the task of crafting your own set of
  dotfiles. Naturally I did talk some about
  the &lt;a href=&quot;https://github.com/technomancy/emacs-starter-kit&quot;&gt;Emacs
  Starter Kit&lt;/a&gt;, though my approach there has changed fairly
  radically. I've been developing version 2 of the Starter Kit
  since the beginning of the summer, but now I think it's time to
  make the release official and give it wider exposure.&lt;/p&gt;

&lt;h4&gt;The Emacs Starter Kit, version 2&lt;/h4&gt;

&lt;p&gt;Version 2 of the Starter Kit turns things inside out. The
  original version was very prescriptive; you used it by cloning a
  git repo to use as your entire &lt;tt&gt;~/.emacs.d&lt;/tt&gt; directory, and
  you fit your own customizations inside the structure it
  provided. This was mostly due to the fact that when it was
  released the packaging story for elisp was very immature. Use of
  package.el was not very widespread, so the Starter Kit had to
  include a copy as well as bundle a bunch of libraries that had not
  been packaged yet. As it turned out, I think the Starter Kit had a
  role in helping popularize package.el.&lt;/p&gt;

&lt;p&gt;A lot has changed since 2008&amp;mdash;primarily
  that &lt;a href=&quot;/133&quot;&gt;package.el has been included in Emacs&lt;/a&gt; and
  &lt;a href=&quot;http://marmalade-repo.org&quot;&gt;Marmalade&lt;/a&gt;
  has &lt;a href=&quot;/144&quot;&gt;picked up lots of steam&lt;/a&gt;, becoming the
  de-facto community package source with over 250 packages. It's now
  feasible for the Starter Kit to be distributed as just another
  package, leaving you free to structure your dotfiles however you
  like. All it takes is setting yourself up to get packages from
  Marmalade:&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;require&lt;/span&gt; '&lt;span class=&quot;constant&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;add-to-list 'package-archives
             '&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&quot;marmalade&quot;&lt;/span&gt; . &lt;span class=&quot;string&quot;&gt;&quot;http://marmalade-repo.org/packages/&quot;&lt;/span&gt;&lt;span class=&quot;esk-paren&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;package-initialize&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;

&lt;img src=&quot;/i/langley-rocket.jpg&quot; alt=&quot;rocket, man&quot; align=&quot;left&quot; /&gt;

&lt;p&gt;Place that in &lt;tt&gt;~/.emacs.d/init.el&lt;/tt&gt; and evaluate it with
  &lt;kbd&gt;M-x eval-buffer&lt;/kbd&gt;. From there you can run &lt;kbd&gt;M-x
  package-refresh-contents&lt;/kbd&gt; to pull in the latest package lists
  (analogous to &lt;kbd&gt;apt-get update&lt;/kbd&gt;) followed by &lt;kbd&gt;M-x
  package-install starter-kit&lt;/kbd&gt;. And then you're set.&lt;/p&gt;

&lt;p&gt;However, it's unlikely that the starter-kit is the only package
  you're interested in. Rather than picking packages by hand, I'm a
  fan of keeping a list of all the packages you use in your
  dotfiles. That way when you move to a new machine, you won't have
  to remember what packages you've come to depend upon; checking out
  your dotfiles on a new machine will pull in everything you've
  specified. Here's my list along with some code to handle it:&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;not package-archive-contents&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;package-refresh-contents&lt;span class=&quot;esk-paren&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;defvar&lt;/span&gt; &lt;span class=&quot;variable-name&quot;&gt;my-packages&lt;/span&gt; '&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;starter-kit starter-kit-lisp starter-kit-eshell
                                  starter-kit-bindings scpaste
                                  clojure-mode clojure-test-mode
                                  markdown-mode yaml-mode tuareg
                                  marmalade oddmuse scpaste&lt;span class=&quot;esk-paren&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;dolist&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;p my-packages&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;not &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;package-installed-p p&lt;span class=&quot;esk-paren&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;package-install p&lt;span class=&quot;esk-paren&quot;&gt;)))&lt;/span&gt;&lt;/pre&gt;

&lt;h4&gt;What's Changed&lt;/h4&gt;

&lt;p&gt;Being a 2.0 release, you can't expect 100% backwards compatibility
  with the old Starter Kit. In particular, it is much more
  modular. The base of the Starter Kit simply gives you better
  default settings and a few new commands. There are separate
  modules supporting various languages like Ruby, Lisp (Clojure,
  Emacs Lisp, Scheme, and Common Lisp), and Javascript, though right
  now the Lisp one is the most polished. If anyone is interested in
  helping maintain alternate language modules, please contact
  me &lt;a href=&quot;https://github.com/technomancy&quot;&gt;on
  Github&lt;/a&gt;. Key bindings have also been spun out into their own module
  since they don't follow Emacs binding conventions strictly.&lt;/p&gt;

&lt;p&gt;There is also no more &lt;tt&gt;elpa-to-submit&lt;/tt&gt; directory; if you
  rely on packages that aren't on Marmalade yet, it's up to you to
  either check them into your own dotfiles or better yet upload them
  yourself. There's also no more explicit &lt;tt&gt;recentf&lt;/tt&gt; support
  since a new feature called &lt;tt&gt;ido-use-virtual-buffers&lt;/tt&gt; allows
  recent files to show up in the regular &lt;kbd&gt;C-x b&lt;/kbd&gt; buffer
  switcher, simplifying things. The addition of
  the &lt;a href=&quot;https://github.com/technomancy/ido-ubiquitous&quot;&gt;ido-ubiquitous&lt;/a&gt;
  package makes it so regular completion gets enhanced with ido
  magic, so functionality like &lt;tt&gt;ido-imenu&lt;/tt&gt; is no longer
  needed.&lt;/p&gt;

&lt;p&gt;The other breakage is that the Starter Kit is now intended only
  for use with Emacs 24 onward. Yes, technically Emacs 24 has not
  yet been released, but it's in active pretest and is readily
  available for most platforms.[&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;]. I've been
  using it since 23 was released and have had no trouble with it.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;[&lt;a name=&quot;fn1&quot;&gt;1&lt;/a&gt;] It's not hard to
  compile &lt;a href=&quot;http://github.com/emacsmirror/emacs&quot;&gt;from
  source&lt;/a&gt;, but precompiled versions are readily available for
  &lt;a href=&quot;http://emacs.naquadah.org/&quot;&gt;Debian-based
  systems&lt;/a&gt;, &lt;a href=&quot;http://emacsformacosx.com/builds&quot;&gt;Mac OS
  X&lt;/a&gt;, and
  &lt;a href=&quot;http://code.google.com/p/emacs-for-windows/updates/list&quot;&gt;Windows&lt;/a&gt;.&lt;/p&gt;
    </content>
  </entry>
  
  <entry xml:base="http://technomancy.us">
    <author><name>Phil Hagelberg</name></author>
    <id>tag:technomancy.us,2007:in%20which%20static%20types%20are%20friends,%20not%20foes</id>
    <published>2011-08-15T01:37:00Z</published>
    <updated>2011-08-15T01:37:00Z</updated>

    <link href="http://technomancy.us/152" rel="alternate" type="text/html"/>
    <title>in which static types are friends, not foes</title>
    <content type="html">
      &lt;p&gt;I'm a big fan of composability in user interfaces. Unix has
  traditionally been strong in this area with its culture of pipes
  and standard in/out, making it easy to chain together small tools
  with orthogonal purposes. Unfortunately this usually does not
  extend to GUI tools which often tend towards monolithic
  globs of functionality. There are a few exceptions, my favourites
  including &lt;a href=&quot;http://www.nongnu.org/xbindkeys/xbindkeys.html&quot;&gt;xbindkeys&lt;/a&gt;
  and &lt;a href=&quot;http://musicpd.org/&quot;&gt;mpd&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The most versatile of these I've found has
  been &lt;a href=&quot;http://tools.suckless.org/dmenu&quot;&gt;dmenu&lt;/a&gt;, a
  graphical option chooser in the style of Emacs' &lt;tt&gt;ido-mode&lt;/tt&gt;:
  it presents a list of options, and as you type it narrows to just
  the options which match the input that's been entered so far. I've
  built a number of tools on top of this including
  a &lt;a href=&quot;https://github.com/technomancy/dotfiles/blob/43e98156961a7592a1b809740d0af4f04d4835db/bin/music-choose&quot;&gt;music
  frontend to mpd&lt;/a&gt;
  and &lt;a href=&quot;https://github.com/technomancy/dotfiles/blob/master/bin/skyyy&quot;&gt;a
    script that allows me to perform a number of Skype actions from
    the keyboard&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The problem is that dmenu is pretty minimalistic compared to
  ido. The main annoyance to me is that it doesn't support flex
  matching&amp;mdash;in other words, only exact matches are shown. In Emacs,
  &lt;tt&gt;ido&lt;/tt&gt; lets me match a few characters against the front of
  the string and a few against the tail. Any input is accepted as
  long as it uniquely identifies one of the choices. Since dmenu is
  written in C I didn't exactly relish the idea of picking up skills
  in that language to add this functionality, so I wrote a
  replacement in OCaml instead:&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;&lt;span class=&quot;tuareg-font-lock-governing&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;tuareg-font-lock-governing&quot;&gt;rec&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;read_lines&lt;/span&gt;&lt;span class=&quot;variable-name&quot;&gt; lines &lt;/span&gt;&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;try&lt;/span&gt; read_lines &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;(&lt;/span&gt;read_line &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;::&lt;/span&gt; lines&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;with&lt;/span&gt; End_of_file &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;-&amp;gt;&lt;/span&gt; lines

&lt;span class=&quot;tuareg-font-lock-governing&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;variable-name&quot;&gt;lines &lt;/span&gt;&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;=&lt;/span&gt; read_lines &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;[]&lt;/span&gt;

&lt;span class=&quot;tuareg-font-lock-governing&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;lines_matching&lt;/span&gt;&lt;span class=&quot;variable-name&quot;&gt; pattern matched line &lt;/span&gt;&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;tuareg-font-lock-governing&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;variable-name&quot;&gt;_ &lt;/span&gt;&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;Str&lt;/span&gt;.search_forward pattern line 0 &lt;span class=&quot;tuareg-font-lock-governing&quot;&gt;in&lt;/span&gt; 
      line &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;::&lt;/span&gt; matched
    &lt;span class=&quot;keyword&quot;&gt;with&lt;/span&gt; Not_found &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;-&amp;gt;&lt;/span&gt; matched

&lt;span class=&quot;tuareg-font-lock-governing&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;escape&lt;/span&gt;&lt;span class=&quot;variable-name&quot;&gt; &lt;/span&gt;&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;
 &lt;span class=&quot;variable-name&quot;&gt; &lt;/span&gt;&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;' '&lt;/span&gt; &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;.*&quot;&lt;/span&gt;
  &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;|&lt;/span&gt; c &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;Char&lt;/span&gt;.escaped c

&lt;span class=&quot;tuareg-font-lock-governing&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;variable-name&quot;&gt; input &lt;/span&gt;&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;type&quot;&gt;Str&lt;/span&gt;.regexp &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;String&lt;/span&gt;.concat &lt;span class=&quot;string&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;List&lt;/span&gt;.map escape input&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;tuareg-font-lock-governing&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;matched&lt;/span&gt;&lt;span class=&quot;variable-name&quot;&gt; input lines &lt;/span&gt;&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;type&quot;&gt;List&lt;/span&gt;.fold_left &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;(&lt;/span&gt;lines_matching &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;(&lt;/span&gt;pattern input&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;[]&lt;/span&gt; lines

&lt;span class=&quot;tuareg-font-lock-governing&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;tuareg-font-lock-governing&quot;&gt;rec&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;draw_matches&lt;/span&gt;&lt;span class=&quot;variable-name&quot;&gt; matches &lt;/span&gt;&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;type&quot;&gt;Graphics&lt;/span&gt;.open_graph &lt;span class=&quot;string&quot;&gt;&quot; 1440x15&quot;&lt;/span&gt;&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;type&quot;&gt;Graphics&lt;/span&gt;.set_window_title &lt;span class=&quot;string&quot;&gt;&quot;erythrina&quot;&lt;/span&gt;&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;type&quot;&gt;Graphics&lt;/span&gt;.draw_string &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;String&lt;/span&gt;.concat &lt;span class=&quot;string&quot;&gt;&quot; | &quot;&lt;/span&gt; matches&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;tuareg-font-lock-governing&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;finish&lt;/span&gt;&lt;span class=&quot;variable-name&quot;&gt; input lines &lt;/span&gt;&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;type&quot;&gt;Graphics&lt;/span&gt;.close_graph &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;match&lt;/span&gt; matched input lines &lt;span class=&quot;keyword&quot;&gt;with&lt;/span&gt;
    &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;|&lt;/span&gt; f &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;::&lt;/span&gt; _ &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;-&amp;gt;&lt;/span&gt; print_string f
    &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;tuareg-font-lock-governing&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;butlast&lt;/span&gt;&lt;span class=&quot;variable-name&quot;&gt; input &lt;/span&gt;&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;List&lt;/span&gt;.rev input &lt;span class=&quot;keyword&quot;&gt;with&lt;/span&gt;
    &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;|&lt;/span&gt; _ &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;::&lt;/span&gt; rest &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;List&lt;/span&gt;.rev rest

&lt;span class=&quot;tuareg-font-lock-governing&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;tuareg-font-lock-governing&quot;&gt;rec&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;variable-name&quot;&gt; input &lt;/span&gt;&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;=&lt;/span&gt;
  draw_matches &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;(&lt;/span&gt;matched input lines&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;Graphics&lt;/span&gt;.read_key &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;keyword&quot;&gt;with&lt;/span&gt;
    &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;comment-delimiter&quot;&gt;(* &lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;enter &lt;/span&gt;&lt;span class=&quot;comment-delimiter&quot;&gt;*)&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;'\r'&lt;/span&gt; &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;-&amp;gt;&lt;/span&gt; finish input lines
    &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;comment-delimiter&quot;&gt;(* &lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;escape &lt;/span&gt;&lt;span class=&quot;comment-delimiter&quot;&gt;*)&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;'\027'&lt;/span&gt; &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;Graphics&lt;/span&gt;.close_graph &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;comment-delimiter&quot;&gt;(* &lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;backspace &lt;/span&gt;&lt;span class=&quot;comment-delimiter&quot;&gt;*)&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;'\b'&lt;/span&gt; &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;-&amp;gt;&lt;/span&gt; main &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;(&lt;/span&gt;butlast input&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;comment-delimiter&quot;&gt;(* &lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;any other &lt;/span&gt;&lt;span class=&quot;comment-delimiter&quot;&gt;*)&lt;/span&gt; c &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;-&amp;gt;&lt;/span&gt; main &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;List&lt;/span&gt;.append input &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;[&lt;/span&gt;c&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;])&lt;/span&gt;

&lt;span class=&quot;tuareg-font-lock-governing&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;variable-name&quot;&gt;_ &lt;/span&gt;&lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;=&lt;/span&gt; main &lt;span class=&quot;tuareg-font-lock-operator&quot;&gt;[]&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;In 39 lines of OCaml I've achieved near feature-parity to the
  700 lines of C that make up dmenu. The only missing features are
  tab-completion and font/color customization, though I have added
  the flex-matching feature mentioned above that dmenu lacks, which
  makes tab completion less important.&lt;/p&gt;

&lt;p&gt;This is my second foray back into the land of static typing since
  university. (Supposedly I learned C++ in school, but I've long
  since mercifully forgotten it all.) I picked
  up &lt;a href=&quot;http://mirah.org&quot;&gt;Mirah&lt;/a&gt; last year
  and &lt;a href=&quot;/145&quot;&gt;spent a little more time hacking in it earlier
  this year for an Android app&lt;/a&gt;. While Mirah is a huge
  improvement over Java, its type inference unfortunately only
  extends to locals, (a common shortcoming of most JVM-hosted type
  systems from what I gather) meaning if you tend to write small
  methods you end up specifying all your types anyway. OCaml on the
  other hand infers all types
  using &lt;a href=&quot;http://en.wikipedia.org/wiki/Type_inference#Hindley.E2.80.93Milner_type_inference_algorithm&quot;&gt;Hindley
  Milner inference&lt;/a&gt;, allowing the types to be effectively
  invisible.&lt;/p&gt;

&lt;p&gt;I've only spent a few days writing OCaml, but I've got to say I'm
  impressed. The type system stayed out of the way, only making a
  fuss when I'd clearly made an error. Pattern matching is a dream:
  you'll notice that all the conditionals in the code above come
  from &lt;tt&gt;match&lt;/tt&gt; rather than &lt;tt&gt;if&lt;/tt&gt;. It's fast, it's
  pleasantly interactive, (especially
  via &lt;a href=&quot;http://marmalade-repo.org/packages/tuareg&quot;&gt;tuareg&lt;/a&gt;
  and Emacs) and the executables produced by the compiler are tiny
  and quick to start, which is valuable for anyone who spends a lot
  of time on the JVM and is looking for something to fill those
  pesky gaps for which the JVM is admittedly lousy.&lt;/p&gt;

&lt;p&gt;My only real complaints surround the fact that the standard
  library is slim and quirky. It throws exceptions in places you
  wouldn't expect, like hitting the end of the file while reading or
  searching for a regex when the text contains no match. The regex
  support is a bit odd, but that's not too surprising considering
  how old the language is.&lt;/p&gt;

&lt;p&gt;Of course the standard library is augmented by a number of
  third-party libraries. It seems like up until recently it's been
  assumed that you'll use either &lt;tt&gt;apt-get&lt;/tt&gt; as the main way to
  pull these in or run &lt;tt&gt;make install&lt;/tt&gt; from source. As
  I've &lt;a href=&quot;/152&quot;&gt;blogged about recently&lt;/a&gt;, &lt;tt&gt;apt-get&lt;/tt&gt;
  is a bit of a drag for libraries that are obscure or change
  frequently. It looks
  like &lt;a href=&quot;http://oasis.forge.ocamlcore.org/documentation.html&quot;&gt;Oasis&lt;/a&gt;
  is making it easier to build projects
  while &lt;a href=&quot;http://oasis.ocamlcore.org/dev/browse&quot;&gt;ODB&lt;/a&gt; is
  the beginning of a rich library dependency system, though it's
  still got a long way to go. My needs have been simple enough that
  I've been able to stick with the standard library for my current
  project, but it's great to see progress in this direction.&lt;/p&gt;

&lt;p&gt;Anyway, it's always a bit disorienting to toss yourself into a
  new environment like this. But OCaml has proven to be quite a
  treat. I recommend starting
  with &lt;a href=&quot;http://mirror.ocamlcore.org/ocaml-tutorial.org/&quot;&gt;this
  OCaml Tutorial&lt;/a&gt; which also links off to many other helpful
  resources. Have fun!&lt;/p&gt;
    </content>
  </entry>
  
  <entry xml:base="http://technomancy.us">
    <author><name>Phil Hagelberg</name></author>
    <id>tag:technomancy.us,2007:in%20which%20an%20operating%20system%20makes%20trade-offs</id>
    <published>2011-07-29T19:27:51Z</published>
    <updated>2011-07-29T19:27:51Z</updated>

    <link href="http://technomancy.us/151" rel="alternate" type="text/html"/>
    <title>in which an operating system makes trade-offs</title>
    <content type="html">
      &lt;p&gt;I've been a user of
  Debian's &lt;a href=&quot;http://wiki.debian.org/Apt&quot;&gt;apt-get&lt;/a&gt; package
  manager for nearly as long as I've been serious about computers,
  and I love it. Going back to a system that lacked apt's depth and
  stability would be like having to write with my non-dominant hand
  or worse&amp;mdash;going back to typing on a QWERTY layout. I have
  seamless access to everything I need[&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;], and it
  never breaks unless I do something crazy like add unsupported
  third-party repositories or run the unstable distribution. Who
  could ask for more? So I'm quite proud to see
  &lt;a href=&quot;https://github.com/technomancy/leiningen&quot;&gt;Leiningen&lt;/a&gt;
  &lt;a href=&quot;http://anonscm.debian.org/gitweb/?p=pkg-java/leiningen.git&quot;&gt;getting
  packaged for Debian&lt;/a&gt; with lots of help from the Java
  Maintainers team.&lt;/p&gt;

&lt;img src=&quot;/i/rice.jpg&quot; alt=&quot;debian rice&quot; align=&quot;right&quot; /&gt;

&lt;p&gt;It's interesting to get a look inside the sausage factory of
  packaging. The biggest hurdle for me as I was learning the ropes
  was that all the packaging introductions assume you are building a
  C program and
  have &lt;a href=&quot;http://twitter.com/technomancy/status/85930967025459202&quot;&gt;familiarity
  with makefiles&lt;/a&gt;. You can tell that the packaging culture has
  its roots in C, and packages from other runtimes feel a bit
  foreign.[&lt;a href=&quot;#fn2&quot;&gt;2&lt;/a&gt;] Even more so with a language like
  Clojure... you're off into unexplored territory, blazing your own
  trail.&lt;/p&gt;

&lt;p&gt;The biggest change from what I'm used to is the notion that only
  a single version of a package can be installed at a time. I think
  I understand the motivation here: it's crucial that when a
  security vulnerability is reported the affected packages and all
  those that depend on them have access to the fix. I'm used to
  developer-focused package managers that allow many versions to be
  installed side-by-side, but that places the burden of security
  updates on the developers using it since it's common for packages
  to depend on exact versions rather than allowing bugfix versions
  to sneak in. It's a lot more work to track down security issues, but
  this is not a big deal in the context of developer-centric systems
  since these particular users are less likely to mind having to pay
  attention to that sort of detail; it's what they're paid to
  do.&lt;/p&gt;

&lt;p&gt;So there's a real tension here; end users want packages to just
  work and be safe without thinking about them while developers
  demand repeatability and control. Developers need the flexibility
  to choose exactly when they want to pull in new versions of
  libraries, while end users want things to hum along out of
  sight.&lt;/p&gt;

&lt;p&gt;The problem is that the one-version-of-a-package-at-a-time policy
  doesn't always work in practice. Over time backwards compatibility
  is the exception rather than the rule; in many cases there simply
  is no substitute for having multiple versions of a package
  installed simultaneously. And apt's answer here is just to create
  a new package with the incompatible version number as part of the
  package name. There's no clue that these packages are related, and
  upgrades won't pick the new versions up. This is quite a shame,
  because I love everything else about apt. I look at complicated
  production deployment schemes and think to myself how much simpler
  things would be if deploying were just a matter of adding our
  internal apt repository and running apt-get install,
  but... versions.&lt;/p&gt;

&lt;p&gt;Of course, these gripes are not really relevant to having
  Leiningen in Debian.[&lt;a href=&quot;#fn3&quot;&gt;3&lt;/a&gt;] Users of Debian-based
  systems will be well-served by getting Leiningen through their OS,
  and once it's on their system, they're free to use it to solve
  their developer-centric problems. This plays to the strengths of
  each system, and everybody wins.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Update&lt;/b&gt;: Leiningen has
  been &lt;a href=&quot;http://packages.qa.debian.org/l/leiningen.html&quot;&gt;accepted
    into Debian&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;[&lt;a name=&quot;fn1&quot;&gt;1&lt;/a&gt;] Except Emacs; that's the only thing I still
  build myself from
  source. Though &lt;a href=&quot;http://emacs.naquadah.org/&quot;&gt;http://emacs.naquadah.org&lt;/a&gt;
  looks like it delivers perfectly passable builds of 24 if you're
  not interested in any of
  the &lt;a href=&quot;http://bzr.savannah.gnu.org/lh/emacs/concurrency/files&quot;&gt;experimental&lt;/a&gt;
  &lt;a href=&quot;http://bzr.savannah.gnu.org/lh/emacs/xwidget/files&quot;&gt;branches&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;[&lt;a name=&quot;fn2&quot;&gt;2&lt;/a&gt;] It's especially noticeable with Ruby and
  the JVM. Part of this is due to the fact that the JVM has only
  been free software for a relatively short period of time, and a
  lot of the existing culture around Java distribution goes against
  the grain of repeatable builds by ignoring source and shuttling
  binary bytecode around everywhere.&lt;/p&gt;

&lt;p&gt;[&lt;a name=&quot;fn3&quot;&gt;3&lt;/a&gt;] And it's looking like it'll make it into
  Ubuntu 11.10 as well.&lt;/p&gt;
    </content>
  </entry>
  
  <entry xml:base="http://technomancy.us">
    <author><name>Phil Hagelberg</name></author>
    <id>tag:technomancy.us,2007:in%20which%20systems%20are%20captured</id>
    <published>2011-06-29T15:42:38Z</published>
    <updated>2011-06-29T15:42:38Z</updated>

    <link href="http://technomancy.us/150" rel="alternate" type="text/html"/>
    <title>in which systems are captured</title>
    <content type="html">
      &lt;p&gt;When working on a project, I try to take care
  that &lt;a href=&quot;http://www.jbarnette.com/2009/09/07/boring-things-first.html&quot;&gt;a
  dev environment can be brought up with as little fuss as
  possible&lt;/a&gt;. This requires some discipline even with simple
  programs, but once you get into the realm of &lt;i&gt;systems&lt;/i&gt;, more
  up-front effort is required for repeatability.&lt;/p&gt;

&lt;p&gt;We've all been in the position of being the new hire on the
  team. On some teams you're lucky if you can get to actually
  running code on your machine in your first week. You think to
  yourself that it could surely be simplified, but once you're all
  set up there's not a lot of incentive to come back and make it
  easy for the next time.&lt;/p&gt;

&lt;p&gt;It's easy enough to track language-level
  dependencies using
  &lt;a href=&quot;http://github.com/technomancy/leiningen&quot;&gt;Leiningen&lt;/a&gt;,
  Rubygems, or whatever is standard for your language, but very few
  large systems end there. You almost always have further external
  dependencies that are best handled by the system-level package
  manager, be they databases, message queues, or even your language
  runtime itself.&lt;/p&gt;

&lt;img src=&quot;/i/pond.jpg&quot; alt=&quot;discovery park. no reason.&quot; /&gt;

&lt;p&gt;I've found the best way to make sure this stuff is kept up is to
  make it the status quo. At work nearly everyone develops in a VM,
  and when a new dependency is needed, instead of everyone having to
  hunt down and install it, it just gets added to the setup
  script. This reduces redundancy as well as helping to
  eliminate &lt;a href=&quot;http://codinghorror.typepad.com/.a/6a0120a85dcdae970b0128776ff992970c-pi&quot;&gt;Works
  on My Machine&lt;/a&gt; issues.&lt;/p&gt;

&lt;p&gt;Recently I've found &lt;a href=&quot;http://vagrantup.com&quot;&gt;Vagrant&lt;/a&gt; to
  be a really helpful tool for streamlining this process even
  further. Before I was using
  raw &lt;a href=&quot;http://www.virtualbox.org&quot;&gt;VirtualBox&lt;/a&gt;, which was
  all right for launching fresh VMs, though the interface was always
  a little awkward. Vagrant streamlines this greatly, making it
  trivial to configure, suspend, and rebuild VMs. It also helps keep
  the configuration of the VM alongside the project for which it's
  meant.&lt;/p&gt;

&lt;p&gt;Vagrant allows you to provision new VMs
  with &lt;a href=&quot;http://wiki.opscode.com/display/chef/&quot;&gt;Chef&lt;/a&gt;. While
  this is pretty handy if you've already got recipes written, it's a
  bit intimidating as the mental model needed to operate Chef is
  quite baroque. But it's easy enough to bypass Chef and
  provide &lt;a href=&quot;https://github.com/Seajure/emacs-clojure-vagrant/blob/master/clojure_emacs.sh&quot;&gt;an
  arbitrary shell script&lt;/a&gt; as a provisioner. You need to take a
  bit of care to ensure the script is idempotent as it's much more
  useful if you can re-run it whenever the dependencies change, but
  it's a great way to get started.&lt;/p&gt;

&lt;p&gt;There are a few gotchas. Vagrant is rather particular about what
  version of Virtualbox (and the VBox extension pack) you use, and
  reinstalling Virtualbox only makes it confused. The OSS edition
  isn't supported, but thankfully an apt repository is
  available:&lt;/p&gt;

&lt;pre style=&quot;font-size: 80%;&quot;&gt;$ sudo apt-add-repository &quot;deb http://download.virtualbox.org/virtualbox/debian $(lsb_release -cs) contrib&quot;
$ wget -q -O - http://download.virtualbox.org/virtualbox/debian/oracle_vbox.asc | sudo apt-key add -
$ sudo apt-get update &amp;&amp; sudo apt-get install virtualbox-4.0
$ sudo gem install vagrant&lt;/pre&gt;

&lt;p&gt;On a related note, I've had had a couple people ask what a good
  project to get started with Clojure web programming would be. The
  most widely-used Clojure web app that I know of
  is &lt;a href=&quot;http://clojars.org&quot;&gt;Clojars&lt;/a&gt;, the community
  repository. But it's been pretty dormant recently; there are
  &lt;a href=&quot;http://groups.google.com/group/clojars-maintainers/browse_thread/thread/d4149ec96316d5b1&quot;&gt;plenty
  of great features&lt;/a&gt; just waiting to be implemented, but getting
  it set up is hard work given all the moving parts.&lt;/p&gt;

&lt;p&gt;Vagrant is perfect for smoothing this over. I've got
  a &lt;a href=&quot;https://github.com/technomancy/clojars-web/tree/vagrant&quot;&gt;vagrant
  branch of clojars&lt;/a&gt; that makes it as simple as &lt;kbd&gt;vagrant
  up&lt;/kbd&gt; (modulo a small issue with the nailgun scp server I'm
  still working out). So this should allow folks to contribute to
  the codebase more easily.&lt;/p&gt;

&lt;p&gt;I've also helped out
  with &lt;a href=&quot;https://github.com/Seajure/emacs-clojure-vagrant&quot;&gt;Justin
  Lilly's Clojure/Emacs environment&lt;/a&gt; which provides a
  fully-configured Emacs 24 install intended to help facilitate our
  &lt;a href=&quot;http://seajure.github.com&quot;&gt;Seajure hackfests&lt;/a&gt;. Give
  it a try if you've had trouble configuring Emacs for Clojure
  hacking. And feel free to crib from these setups for automating
  your own projects.&lt;/p&gt;
    </content>
  </entry>
  
  <entry xml:base="http://technomancy.us">
    <author><name>Phil Hagelberg</name></author>
    <id>tag:technomancy.us,2007:in%20which%20radical%20simplification%20ensues</id>
    <published>2011-05-17T04:02:23Z</published>
    <updated>2011-05-17T04:02:23Z</updated>

    <link href="http://technomancy.us/149" rel="alternate" type="text/html"/>
    <title>in which radical simplification ensues</title>
    <content type="html">
      &lt;p&gt;While Emacs support has come a long
  way &lt;a href=&quot;http://groups.google.com/group/clojure/tree/browse_frm/month/2009-01/d42e6fca3af34c41?rnum=11&amp;_done=%2Fgroup%2Fclojure%2Fbrowse_frm%2Fmonth%2F2009-01%3F#doc_56e09db3f292020a&quot;&gt;since
  I first got started with Clojure&lt;/a&gt;, I'm reminded every time I
  help newbies get set up that there are still way too many moving
  parts. This is in part due to the fact that things center around
  &lt;a href=&quot;http://common-lisp.net/project/slime/&quot;&gt;SLIME&lt;/a&gt;, a tool
  which was originally developed to work with Common Lisp. SLIME
  doesn't have stable releases; the developers expect everyone to
  run from CVS trunk (I wish I were joking), so I had to do some
  ad-hoc packaging just in order to prevent constant breakage. But
  synchronizing compatible versions between two separate package
  managers on two separate runtimes is a headache.&lt;/p&gt;

&lt;p&gt;I've cooked up something much simpler for the next swank-clojure release:&lt;/p&gt;

&lt;video width=&quot;640&quot; height=&quot;416&quot; controls&gt;
  &lt;source src=&quot;v/slime-in-60-seconds.mp4&quot;  type='video/mp4; codecs=&quot;avc1.42E01E&quot;' /&gt;
  &lt;source src=&quot;v/slime-in-60-seconds.webm&quot; type='video/webm; codecs=&quot;vp8&quot;' /&gt;
  &lt;source src=&quot;v/slime-in-60-seconds.ogv&quot;  type='video/ogg; codecs=&quot;theora&quot;' /&gt;
&lt;/video&gt;

&lt;p&gt;[&lt;a href=&quot;v/slime-in-60-seconds.mp4&quot;&gt;download video&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;This makes it possible for a single piece of elisp to bootstrap
  an entire SLIME environment. It's also set up so it can be
  extensible&amp;mdash;if a project like &lt;a href=&quot;148&quot;&gt;Slamhound&lt;/a&gt;
  wants to distribute an elisp library, it will be able to be loaded
  automatically upon connecting SLIME. The number of steps is
  reduced to three:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Install &lt;a href=&quot;http://github.com/technomancy/clojure-mode&quot;&gt;clojure-mode&lt;/a&gt;
    via &lt;a href=&quot;http://marmalade-repo.org&quot;&gt;Marmalade&lt;/a&gt; or from git.&lt;/li&gt;
  &lt;li&gt;&lt;kbd&gt;lein plugin install swank-clojure 1.3.1&lt;/kbd&gt;&lt;/li&gt;
  &lt;li&gt;Invoke &lt;kbd&gt;M-x clojure-jack-in&lt;/kbd&gt; from a project&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The video uses swank-clojure 1.4.0-SNAPSHOT, which
  includes &lt;a href=&quot;http://georgejahad.com/clojure/swank-cdt.html&quot;&gt;some
  new debugging features&lt;/a&gt;, but the most stable release (1.3.1 as
  noted above) will also work. Hopefully this eases a few headaches!&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Update&lt;/b&gt;: Right now there are known issues with having
  multiple versions of swank-clojure present, both
  in &lt;tt&gt;lib/dev&lt;/tt&gt; and &lt;tt&gt;~/.lein/plugins&lt;/tt&gt;, so check to make
  sure they aren't conflicting. This will be fixed in the next
  version of Leiningen. It's probably best to remove swank-clojure
  from :dev-dependencies in project.clj entirely and have each user
  who wants to use swank install it as a local plugin instead.&lt;/p&gt;

&lt;p&gt;If you have issues, please post to
  the &lt;a href=&quot;http://groups.google.com/group/swank-clojure&quot;&gt;swank-clojure
    mailing list&lt;/a&gt; or
  open &lt;a href=&quot;https://github.com/technomancy/swank-clojure/issues&quot;&gt;a
    github issue. Blog comments are a lousy place for bug reports.&lt;/p&gt;
    </content>
  </entry>
  
  <entry xml:base="http://technomancy.us">
    <author><name>Phil Hagelberg</name></author>
    <id>tag:technomancy.us,2007:in%20which%20a%20violent%20metaphor%20features%20prominently</id>
    <published>2011-05-01T06:05:12Z</published>
    <updated>2011-05-01T06:05:12Z</updated>

    <link href="http://technomancy.us/148" rel="alternate" type="text/html"/>
    <title>in which a violent metaphor features prominently</title>
    <content type="html">
      &lt;p&gt;This past week I've had a lot of fun
  with &lt;a href=&quot;http://github.com/technomancy/slamhound&quot;&gt;Slamhound&lt;/a&gt;,
  my most recent project. Often times when writing Clojure, your
  &lt;a href=&quot;http://blog.8thlight.com/articles/2010/12/6/clojure-libs-and-namespaces-require-use-import-and-ns&quot;&gt;namespace
  declarations&lt;/a&gt; are a pain to keep in order&amp;mdash;you've got to
  specify all the namespaces you depend upon, and once you've got a
  lot of them in there, it's hard to keep them straight; often
  duplicates sneak in and things just get really messy. So Slamhound
  takes a source file, discards the namespace declaration, and tries
  to determine how to reconstruct it from the code alone. I had a
  lot of fun putting it together, so here's a little walk-through of
  how it works.&lt;/p&gt;

&lt;p&gt;A big part of why it was so much fun is that the code is very
  functional. It takes a file as input, throws it into a pipeline,
  and spits out an answer. The only impure part is the reading of
  the file.[&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;] The pipeline is built in
  the &lt;code&gt;slam.hound/reconstruct&lt;/code&gt; function: &lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;defn&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;reconstruct&lt;/span&gt; [filename]
  &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;io/reader filename&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;
      asplode
      regrow
      stitch-up&lt;span class=&quot;esk-paren&quot;&gt;))&lt;/span&gt; &lt;/pre&gt;

&lt;p&gt;But first a little back-story: Slamhound is named after the
  explosive device from William Gibson's novel
  &lt;a href=&quot;http://en.wikipedia.org/wiki/Count_Zero&quot;&gt;Count
  Zero&lt;/a&gt;. At the start of the story, the main character Turner
  has an encounter with one, after which he spends three months in
  surgery while his skin and organs are regrown before he's
  stitched back together. Files in Slamhound go through the same
  process: asplode, re-grow, stitch-up. (I've quoted code selections
  inline, but for the complete listing a link is given for each phase.)&lt;/p&gt;

&lt;h4&gt;Phase 1: &lt;a href=&quot;https://github.com/technomancy/slamhound/blob/master/src/slam/hound/asplode.clj&quot;&gt;asplode&lt;/a&gt;&lt;/h4&gt;

&lt;pre class=&quot;code&quot;&gt;&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;defn&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;asplode&lt;/span&gt; [rdr]
  &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;let&lt;/span&gt; [rdr &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;preprocessor&quot;&gt;PushbackReader.&lt;/span&gt; rdr&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;
        ns-map &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;ns-to-map &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;read&lt;/span&gt; rdr&lt;span class=&quot;esk-paren&quot;&gt;))&lt;/span&gt;
        stripped-ns &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;apply&lt;/span&gt; dissoc ns-map [&lt;span class=&quot;builtin&quot;&gt;:use&lt;/span&gt; &lt;span class=&quot;builtin&quot;&gt;:require&lt;/span&gt; &lt;span class=&quot;builtin&quot;&gt;:import&lt;/span&gt;]&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;
        body &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;take-while&lt;/span&gt; #&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;not=&lt;/span&gt; &lt;span class=&quot;builtin&quot;&gt;::done&lt;/span&gt; %&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;
                         &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;repeatedly&lt;/span&gt; #&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;read&lt;/span&gt; rdr false &lt;span class=&quot;builtin&quot;&gt;::done&lt;/span&gt;&lt;span class=&quot;esk-paren&quot;&gt;)))&lt;/span&gt;]
    [stripped-ns body]&lt;span class=&quot;esk-paren&quot;&gt;))&lt;/span&gt; &lt;/pre&gt;

&lt;p&gt;Like its counterpart in the book,
  the first
  phase is quick, simple, and messy. First we need to construct
  a PushbackReader in order for &lt;code&gt;clojure.core/read&lt;/code&gt; to
  operate. This gives us the &lt;code&gt;ns&lt;/code&gt; form as a list. Then in
  &lt;code&gt;ns-to-map&lt;/code&gt; (not shown) we perform the translation into
  a map by splitting each clause
  (&lt;code&gt;:use&lt;/code&gt;, &lt;code&gt;:require&lt;/code&gt;,
  and &lt;code&gt;:import&lt;/code&gt;) out, since the map form is a lot easier
  to operate on in during the regrow stage. But often times you have
  left-over clauses from earlier revisions, so
  we &lt;code&gt;dissoc&lt;/code&gt; them out in order to start from
  scratch. Then we &lt;code&gt;repeatedly&lt;/code&gt; &lt;code&gt;read&lt;/code&gt; until
  EOF to get the body. The stripped ns and body are passed to the
  next phase. &lt;/p&gt;

&lt;h4&gt;Phase 2: &lt;a href=&quot;https://github.com/technomancy/slamhound/blob/master/src/slam/hound/regrow.clj&quot;&gt;regrow&lt;/a&gt;&lt;/h4&gt;

  &lt;pre class=&quot;code&quot;&gt;&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;defn&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;regrow&lt;/span&gt;
  &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;[[ns-map body]]
     &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;force&lt;/span&gt; pre-load&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;regrow [ns-map body] nil&lt;span class=&quot;esk-paren&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;[[ns-map body] last-missing]
     &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;if-let&lt;/span&gt; [{&lt;span class=&quot;builtin&quot;&gt;:keys&lt;/span&gt; [missing type]} &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;check-for-failure ns-map body&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;]
       &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;=&lt;/span&gt; last-missing missing&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;preprocessor&quot;&gt;Exception.&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;Couldn't resolve &quot;&lt;/span&gt; missing&lt;span class=&quot;esk-paren&quot;&gt;)))&lt;/span&gt;
         &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;recur&lt;/span&gt; [&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;grow-step missing type ns-map&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt; body] missing&lt;span class=&quot;esk-paren&quot;&gt;))&lt;/span&gt;
       ns-map&lt;span class=&quot;esk-paren&quot;&gt;)))&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The re-grow phase is where the pain-staking progress is made. The
  first arity forces the &lt;code&gt;pre-load&lt;/code&gt; delay which ensures
  all the source is loaded for compilation purposes, then hands off
  to the second arity. There's a recursive loop here: we attempt to
  compile the body with the current ns-map
  in &lt;code&gt;check-for-failure&lt;/code&gt; (see below.) If it fails, we analyze the
  problematic &lt;code&gt;missing&lt;/code&gt; piece in &lt;code&gt;grow-step&lt;/code&gt;,
  which searches for all possible &lt;code&gt;candidates&lt;/code&gt;, sorts
  in &lt;code&gt;disambiguate&lt;/code&gt;, and picks one. Then the compilation
  is retried by &lt;code&gt;recur&lt;/code&gt;ring.&lt;/p&gt;

&lt;p&gt;Right now if the retry results in the same failure, it gives up,
  though there's no reason in the future it couldn't continue down
  the list of candidates. Of course, if compilation succeeds, the
  re-grow process is finished, and it returns
  the &lt;code&gt;ns-map&lt;/code&gt; with the new clauses for the next
  phase, &lt;code&gt;stitch-up&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;check-for-failure&lt;/code&gt; deserves special attention as
  it's where the meat of the process happens:&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;defn&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;check-for-failure&lt;/span&gt; [ns-map body]
  &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;let&lt;/span&gt; [sandbox-ns `slamhound.sandbox#
        ns-form &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;stitch/ns-from-map &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;assoc&lt;/span&gt; ns-map &lt;span class=&quot;builtin&quot;&gt;:name&lt;/span&gt; sandbox-ns&lt;span class=&quot;esk-paren&quot;&gt;))&lt;/span&gt;]
    &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;binding&lt;/span&gt; [*ns* &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;create-ns&lt;/span&gt; sandbox-ns&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;]
      &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;try&lt;/span&gt;
        &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;eval&lt;/span&gt; `&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; ~ns-form ~@body nil&lt;span class=&quot;esk-paren&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;preprocessor&quot;&gt;Exception&lt;/span&gt; e
          &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;failure-details &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;preprocessor&quot;&gt;.getMessage&lt;/span&gt; e&lt;span class=&quot;esk-paren&quot;&gt;))&lt;/span&gt;
              &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;throw&lt;/span&gt; e&lt;span class=&quot;esk-paren&quot;&gt;)))&lt;/span&gt;
        &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;finally&lt;/span&gt;
         &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;remove-ns&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;preprocessor&quot;&gt;.name&lt;/span&gt; *ns*&lt;span class=&quot;esk-paren&quot;&gt;)))))))&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Here we see that a unique sandbox namespace is created using
  auto-gensym. Next we reach ahead a bit into the
  next &lt;code&gt;stitch-up&lt;/code&gt; phase for the &lt;code&gt;ns-from-map&lt;/code&gt;
  function, which takes our map representation and turns it back
  into an executable &lt;code&gt;ns&lt;/code&gt; declaration. Stepping into this
  sandbox namespace with &lt;code&gt;binding&lt;/code&gt;, we attempt
  to &lt;code&gt;eval&lt;/code&gt; the body. If it fails, we analyze the
  exception with &lt;code&gt;failure-details&lt;/code&gt;. This tells us whether
  it was a &lt;code&gt;:use&lt;/code&gt;, &lt;code&gt;:require&lt;/code&gt;,
  or &lt;code&gt;:import&lt;/code&gt; clause that caused the failure as well as
  the name of the missing class or var. These details are used
  by &lt;code&gt;candidates&lt;/code&gt; to determine the ns-map for the next
  attempt.&lt;/p&gt;

  &lt;pre class=&quot;code&quot;&gt;&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;defmethod&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;candidates&lt;/span&gt; &lt;span class=&quot;builtin&quot;&gt;:require&lt;/span&gt; [type missing]
  &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;for&lt;/span&gt; [n &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;all-ns&lt;/span&gt;&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;builtin&quot;&gt;:when&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;=&lt;/span&gt; missing &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;last&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;preprocessor&quot;&gt;.split&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;ns-name&lt;/span&gt; n&lt;span class=&quot;esk-paren&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;\\.&quot;&lt;/span&gt;&lt;span class=&quot;esk-paren&quot;&gt;)))&lt;/span&gt;]
    [&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;ns-name&lt;/span&gt; n&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;builtin&quot;&gt;:as&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;symbol&lt;/span&gt; missing&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;]&lt;span class=&quot;esk-paren&quot;&gt;))&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;candidates&lt;/code&gt; multimethod operates on each of the
  three clause types
  (&lt;code&gt;:use&lt;/code&gt;/&lt;code&gt;:require&lt;/code&gt;/&lt;code&gt;:import&lt;/code&gt;),
  but they're all slight variations on the same
  theme. The &lt;code&gt;:require&lt;/code&gt; version is given here: it simply
  loops through all the available namespaces and returns the ones
  which match the &lt;code&gt;missing&lt;/code&gt; name from the compilation
  failure.&lt;/p&gt;

&lt;h4&gt;Phase 3: &lt;a href=&quot;https://github.com/technomancy/slamhound/blob/master/src/slam/hound/stitch.clj&quot;&gt;stitch up&lt;/a&gt;&lt;/h4&gt;

&lt;pre class=&quot;code&quot;&gt;&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;defn&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;stitch-up&lt;/span&gt; [ns-map]
  &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt; ns-map
      collapse-clauses
      sort-subclauses
      ns-from-map
      prettify&lt;span class=&quot;esk-paren&quot;&gt;))&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Once we've got a successful compilation, we have what we
  need. All that's left is to turn it back from a map into code
  form, which is handled by the stitch phase. Technically only the
  the &lt;code&gt;ns-from-map&lt;/code&gt; function we saw used above is
  necessary, but the ns declaration looks a lot nicer if you
  collapse all the clauses down first:&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;:use&lt;/span&gt; [clojure.test &lt;span class=&quot;builtin&quot;&gt;:only&lt;/span&gt; [deftest]]
      [clojure.test &lt;span class=&quot;builtin&quot;&gt;:only&lt;/span&gt; [testing]]
      [clojure.test &lt;span class=&quot;builtin&quot;&gt;:only&lt;/span&gt; [is]]
      [clojure.test &lt;span class=&quot;builtin&quot;&gt;:only&lt;/span&gt; [are]]&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;after collapsing becomes:
&lt;/span&gt;
&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;:use&lt;/span&gt; [clojure.test &lt;span class=&quot;builtin&quot;&gt;:only&lt;/span&gt; [deftest testing is are]]&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Sorting subclauses doesn't hurt either, though it's strictly
  cosmetic. Finally we turn it back into code form and pretty-print
  it using &lt;code&gt;clojure.pprint/pprint&lt;/code&gt;. And that's it!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;a name=&quot;fn1&quot;&gt;&lt;/a&gt;&lt;b&gt;1&lt;/b&gt;: Technically there's one exception to
  this; see if you can spot it.&lt;/p&gt;
    </content>
  </entry>
  
  <entry xml:base="http://technomancy.us">
    <author><name>Phil Hagelberg</name></author>
    <id>tag:technomancy.us,2007:in%20which%20secrets%20are%20kept</id>
    <published>2011-04-01T03:03:55Z</published>
    <updated>2011-04-01T03:03:55Z</updated>

    <link href="http://technomancy.us/147" rel="alternate" type="text/html"/>
    <title>in which secrets are kept</title>
    <content type="html">
      &lt;p&gt;Back when Leiningen was &lt;a href=&quot;/131&quot;&gt;first launched&lt;/a&gt; it
  coincided with the launch
  of &lt;a href=&quot;http://clojars.org&quot;&gt;Clojars&lt;/a&gt;, the public community
  repository for Clojure
  projects. This &lt;a href=&quot;http://www.infoq.com/news/2009/11/clojars-leiningen-clojure&quot;&gt;worked
  out really well&lt;/a&gt; for Clojure as far as the timing was
  concerned&amp;mdash;it allowed the ecosystem to grow quickly.&lt;/p&gt;

&lt;img src=&quot;/i/chain-stump.jpg&quot; alt=&quot;scenery&quot; align=&quot;right&quot; /&gt;

&lt;p&gt;But
  Clojars &lt;a href=&quot;http://mobile.twitter.com/cemerick/status/45923604000555008&quot;&gt;doesn't
  work for everything&lt;/a&gt;; some situations call for libraries to be
  shared on a team without making them public. For cases like this
  it's necessary to publish to private repositories. This has been a
  really common question with Leiningen that hasn't had a good
  answer until recently; some folks bite the bullet and run &lt;tt&gt;lein
  install&lt;/tt&gt; on every development machine while others set up
  shared static-file repositories maintained mostly by
  hand. At &lt;a href=&quot;http://sonian.net&quot;&gt;work&lt;/a&gt; we've nginx'd up a
  directory that gets deployed to from our Hudson (soon to
  be &lt;a href=&quot;http://jenkinsci.org&quot;&gt;Jenkins&lt;/a&gt;) jobs.&lt;/p&gt;

&lt;p&gt;But the 1.5.0 release of Leiningen has added the &lt;tt&gt;deploy&lt;/tt&gt;
  task along with
  a &lt;a href=&quot;https://github.com/technomancy/leiningen/blob/stable/DEPLOY.md&quot;&gt;deploy
  guide&lt;/a&gt;. Now you can deploy to private repositories like
  instances of &lt;a href=&quot;http://archiva.apache.org&quot;&gt;Archiva&lt;/a&gt; and
  &lt;a href=&quot;http://nexus.sonatype.org&quot;&gt;Nexus&lt;/a&gt;. Just configure
  your &lt;tt&gt;:repositories&lt;/tt&gt; in project.clj with the URL and
  credentials for uploading:&lt;/p&gt;

&lt;pre class=&quot;code&quot; style=&quot;font-size: 90%;&quot;&gt;
  &lt;span class=&quot;builtin&quot;&gt;:repositories&lt;/span&gt; {&lt;span class=&quot;string&quot;&gt;&quot;snapshots&quot;&lt;/span&gt; {&lt;span class=&quot;builtin&quot;&gt;:url&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;http://blueant.com/archiva/snapshots&quot;&lt;/span&gt;
                              &lt;span class=&quot;builtin&quot;&gt;:username&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;milgrim&quot;&lt;/span&gt; &lt;span class=&quot;builtin&quot;&gt;:password&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;locative.1&quot;&lt;/span&gt;}
                 &lt;span class=&quot;string&quot;&gt;&quot;releases&quot;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;http://blueant.com/archiva/internal&quot;&lt;/span&gt;}&lt;/pre&gt;

&lt;p&gt;If you're shy about checking passwords into project.clj, you can
  put them in &lt;tt&gt;~/.lein/init.clj&lt;/tt&gt; as mentioned in
  the &lt;a href=&quot;https://github.com/technomancy/leiningen/blob/stable/DEPLOY.md&quot;&gt;deploy
  guide&lt;/a&gt;. Note that the naming is significant; if you are
  deploying a &lt;code&gt;SNAPSHOT&lt;/code&gt; version, it will go to the
  &quot;snapshots&quot; repository, while stable versions will go to the
  &quot;releases&quot; repository. Hopefully this is useful for teams
  collaborating on multiple projects in private.&lt;/p&gt;
    </content>
  </entry>
  
  <entry xml:base="http://technomancy.us">
    <author><name>Phil Hagelberg</name></author>
    <id>tag:technomancy.us,2007:in%20which%20the%20local%20meeting%20celebrates%20a%20year</id>
    <published>2011-03-01T05:08:38Z</published>
    <updated>2011-03-01T05:08:38Z</updated>

    <link href="http://technomancy.us/146" rel="alternate" type="text/html"/>
    <title>in which the local meeting celebrates a year</title>
    <content type="html">
      &lt;p&gt;This month
  marks &lt;a href=&quot;http://groups.google.com/group/clojure/browse_thread/thread/6cc17288d23cbf69/2b66a6af09ba2c32&quot;&gt;the
  first anniversary&lt;/a&gt;
  of &lt;a href=&quot;http://seajure.technomancy.us&quot;&gt;Seajure&lt;/a&gt;, the
  Seattle Clojure group. I've had a lot of fun conducting these
  meetings. It sounds like our group is a little different from the
  way most people run things, so I thought I'd write a bit about
  what has worked for us.&lt;/p&gt;

&lt;img src=&quot;/i/seajure-chinese-democracy.jpg&quot; 
     alt=&quot;chinese democracy&quot; align=&quot;right&quot; /&gt;

&lt;p&gt;One thing I knew I wanted from the start was for meetings to be
  very code-centric. The Seattle Ruby group used to have talks
  regularly, and they found that in that kind of situation after a
  few months things usually fall into patterns of just having the
  same person present over and over.&lt;/p&gt;

&lt;p&gt;So we focus on code instead. We try to come up with a small
  project that's somewhat useful on its own but not too ambitious to
  build in a couple hours. Everyone logs into a shared tmux session
  running Emacs and can all collaborate on the code as it's being
  written. Of course still only one person can type at a time, but
  it's a lot less hassle than having to set up a projector, and it's
  much more interactive.&lt;/p&gt;

&lt;p&gt;This only really works because we have a small group; with larger
  attendance levels the group may need to be divided somehow. We
  have swarm-coding sessions for only about half of our meetings
  when we have a good idea for a project. Other times we'll just
  discuss new features of Clojure or specific tools; one meeting we
  had an Emacs workshop to get people started. We also spend about
  half an hour starting out just chatting and making sure everyone
  has been introduced.&lt;/p&gt;

&lt;p&gt;Normally I stress the importance of keeping the same location
  consistently since people have an easier time planning for it if
  it doesn't shift around, but &lt;a href=&quot;http://zokacoffee.com&quot;&gt;the
  coffee shop in which we hold our meetings&lt;/a&gt; is closing early for
  winter hours, so we're in the University
  District &lt;a href=&quot;http://trabantcoffee.com&quot;&gt;Trabant&lt;/a&gt; for our
  March meeting. If you're in the Seattle area, join
  the &lt;a href=&quot;http://groups.google.com/group/seajure&quot;&gt;join the
  mailing list&lt;/a&gt; and come on by!&lt;/p&gt;
    </content>
  </entry>
  
  <entry xml:base="http://technomancy.us">
    <author><name>Phil Hagelberg</name></author>
    <id>tag:technomancy.us,2007:in%20which%20a%20peek%20is%20given,%20sneakily</id>
    <published>2011-01-31T07:17:52Z</published>
    <updated>2011-01-31T07:17:52Z</updated>

    <link href="http://technomancy.us/145" rel="alternate" type="text/html"/>
    <title>in which a peek is given, sneakily</title>
    <content type="html">
      &lt;p&gt;Here's a little glimpse of something I've been cooking up:&lt;/p&gt;

&lt;a href=&quot;http://ferrante-della-griva.appspot.com&quot;&gt;
  &lt;img src=&quot;/i/ferrante.png&quot; alt=&quot;Ferrante&quot; /&gt;&lt;/a&gt;

&lt;p&gt;I've &lt;a href=&quot;/134&quot;&gt;hinted before&lt;/a&gt; about getting interested in
  mobile development for Android, but this past year Leiningen has
  really snatched up the bulk of my hacking time. Now that it's
  matured and stabilized a bit I've had a chance to take another
  look at Mirah, a fringe JVM language that's perfect for Android by
  virtue of bringing along zero additional runtime baggage. Ferrante
  is my first nontrivial app, and it's really been fun to piece
  together, blazing my own trail.&lt;/p&gt;

&lt;p&gt;It's still got some spots where rough around the edges, but
  there's enough to poke at for the intrepid developer or curious
  beta tester. Source is
  &lt;a href=&quot;http://github.com/technomancy/ferrante&quot;&gt;on
  Github&lt;/a&gt;. I'll be sure to post more as I get things figured
  out; with a little more work I think using Mirah for mobile
  development could really be a lot of fun.&lt;/p&gt;
    </content>
  </entry>
  
  <entry xml:base="http://technomancy.us">
    <author><name>Phil Hagelberg</name></author>
    <id>tag:technomancy.us,2007:in%20which%20the%20author%20sighs%20and%20realizes%20he%20publishes%20very%20few%20posts%20which%20do%20not%20contain%20the%20word%20package</id>
    <published>2010-12-30T16:32:42Z</published>
    <updated>2010-12-30T16:32:42Z</updated>

    <link href="http://technomancy.us/144" rel="alternate" type="text/html"/>
    <title>in which the author sighs and realizes he publishes very few posts which do not contain the word package</title>
    <content type="html">
      &lt;p&gt;As someone who maintains a fair amount of Emacs libraries, I've
  long been in search of improvements to the release process. I've
  &lt;a href=&quot;/133&quot;&gt;lobbied for including package.el in
    Emacs itself&lt;/a&gt;, which finally happened over the summer. But
    political concerns interfered a bit, and it is only configured
    to point
    to &lt;a href=&quot;http://elpa.gnu.org/packages/archive-contents&quot;&gt;the
    FSF package repository&lt;/a&gt; out of the box. This repository only
    accepts code for which copyright has been granted to the Free
    Software Foundation. At the time of this writing it has only six
    packages in it compared to ELPA's 130, making it somewhat less
    useful than it could be. For a number of
    reasons[&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;] the copyright assignment policy
    doesn't work for the packages I maintain, so this was a bit
    disappointing to me.&lt;/p&gt;

&lt;img src=&quot;/i/corn.jpg&quot; 
     alt=&quot;some corn or something, I dunno man. unrelated.&quot;
     title=&quot;some corn or something, I dunno man. unrelated.&quot;
     align=&quot;right&quot; /&gt;

&lt;p&gt;On the other hand, I was able to add support for multiple package
  sources to package.el before it was included in Emacs. This allows
  users to add alternate third-party sources like the
  original &lt;a href=&quot;http://tromey.com/elpa&quot;&gt;ELPA&lt;/a&gt; repository. I
  should note here that there's been some confusion regarding the
  difference between package.el and ELPA which I must admit to
  having helped spread at one point. To be precise, package.el is
  the package manager, while ELPA is the original package source
  from which most packages so far have been hosted. The term &quot;ELPA&quot;
  is often mistakenly used to refer to package.el because for a long
  time package.el was hard-coded to only download from ELPA, but now
  that it supports multiple sources it's important to make a
  distinction between them.&lt;/p&gt;

&lt;p&gt;Unfortunately ELPA is still manually curated with package
  submission over email, so it can take weeks or even months for new
  versions of my libraries to become available. I've started my own
  package source
  at &lt;a href=&quot;http://repo.technomancy.us/emacs&quot;&gt;http://repo.technomancy.us/emacs&lt;/a&gt;,
  but it turns out maintaining a package source consisting of a
  bunch of static files is not a lot of fun and can be error
  prone. Luckily Nathan Wizenbaum has cooked
  up &lt;a href=&quot;http://marmalade-repo.org&quot;&gt;Marmalade&lt;/a&gt;, a community
  package source that allows users to upload their own packages much
  like &lt;a href=&quot;http://clojars.org&quot;&gt;Clojars&lt;/a&gt;
  or &lt;a href=&quot;http://rubygems.org&quot;&gt;Rubygems.org&lt;/a&gt;. While it hasn't
  seen much use yet, it's quite promising as a way for elisp authors
  to get their code out to users. The following snippet will add
  Marmalade as a repository:&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;(&lt;span class=&quot;keyword&quot;&gt;require&lt;/span&gt; '&lt;span class=&quot;constant&quot;&gt;package&lt;/span&gt;)
(add-to-list 'package-archives
             '(&lt;span class=&quot;string&quot;&gt;&quot;marmalade&quot;&lt;/span&gt; . 
               &lt;span class=&quot;string&quot;&gt;&quot;http://marmalade-repo.org/packages/&quot;&lt;/span&gt;) t)
(package-initialize)&lt;/pre&gt;

&lt;p&gt;You'll need to run &lt;kbd&gt;M-x package-refresh-contents&lt;/kbd&gt;
  manually to download the latest package list. If you are using
  Emacs 23 you can &lt;a href=&quot;http://bit.ly/pkg-el23&quot;&gt;download a
  compatible package.el&lt;/a&gt;. The version from tromey.com doesn't
  support multiple archive sources.&lt;/p&gt;

&lt;p&gt;Moving forward I'm planning on uploading the packages I maintain
  over to Marmalade. It offers a much faster turnaround time
  for updates than the old system of submitting by email to
  ELPA. I've already uploaded my Clojure libraries and am working
  on a version of
  the &lt;a href=&quot;http://github.com/technomancy/emacs-starter-kit&quot;&gt;Emacs
  Starter Kit&lt;/a&gt; that is structured as a set of packages in order
  to be more modular. (The new Starter Kit only targets Emacs 24 and
  up, so at this point it's intended for the adventurous.) Happy hacking!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;[&lt;a name=&quot;fn1&quot;&gt;1&lt;/a&gt;] The main reason being that I could never
  bring myself to answer the question &quot;can you apply this patch?&quot;
  with &quot;well that depends, &lt;a href=&quot;http://achewood.com/index.php?date=11222006&quot;&gt;do you have a fax machine&lt;/a&gt;?&quot;.&lt;/p&gt;
    </content>
  </entry>
  
  <entry xml:base="http://technomancy.us">
    <author><name>Phil Hagelberg</name></author>
    <id>tag:technomancy.us,2007:in%20which%20the%20perils%20of%20the%20gilardi%20scenario%20are%20overcome</id>
    <published>2010-11-10T05:43:43Z</published>
    <updated>2010-11-10T05:43:43Z</updated>

    <link href="http://technomancy.us/143" rel="alternate" type="text/html"/>
    <title>in which the perils of the gilardi scenario are overcome</title>
    <content type="html">
      &lt;p&gt;There's an interesting gotcha that's bitten me a few times while
  exploring the fringes of Clojure. The &lt;code&gt;eval&lt;/code&gt; function is
  not often used, but there are some cases when it's justifiable.
  It comes up while writing Leiningen plugins since code needs to
  be constructed in the context of Leiningen and run in the context
  of a project.&lt;/p&gt;

&lt;p&gt;The Gilardi Scenario refers to a case where you want to evaluate
  some code that both loads in a new var and refers to that var in
  the same piece of code:&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;eval&lt;/span&gt; `&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;when&lt;/span&gt; ~&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;:some-set&lt;/span&gt; project&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;require&lt;/span&gt; '~'clojure.set&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;region&quot;&gt;clojure.set/difference&lt;/span&gt;
          ~&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;:some-set&lt;/span&gt; project&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt; #{&lt;span class=&quot;builtin&quot;&gt;:bad-key&lt;/span&gt;}&lt;span class=&quot;esk-paren&quot;&gt;)))&lt;/span&gt;

java.lang.ClassNotFoundException: clojure.set&lt;/pre&gt;

&lt;p&gt;The problem is that Clojure has to compile this whole block of
  code as a single unit. At compile time, the &lt;code&gt;clojure.set&lt;/code&gt;
  namespace has not been loaded yet, so the attempt to look up
  the &lt;code&gt;difference&lt;/code&gt; var is doomed to failure.&lt;/p&gt;

&lt;p&gt;In Clojure 1.1, the compiler introduced special handling to work
  around this. If the top-level form being evaled is
  a &lt;code&gt;do&lt;/code&gt;, then it will be broken up and each subform will
  be evaled separately. Unfortunately this only goes so far; it only
  applies to top-level &lt;code&gt;do&lt;/code&gt;s, so even though
  our &lt;code&gt;when&lt;/code&gt; above macro-expands to a form that
  contains &lt;code&gt;do&lt;/code&gt;, the compiler can't apply its
  special-case.&lt;/p&gt;

&lt;p&gt;Another way around it is to look up the var at runtime. The
  &lt;code&gt;ns-resolve&lt;/code&gt; function works well for that.&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;eval&lt;/span&gt; `&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;when&lt;/span&gt; ~&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;:some-set&lt;/span&gt; project&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;require&lt;/span&gt; '~'clojure.set&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;esk-paren&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;ns-resolve&lt;/span&gt; '~'clojure.set '~'difference&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;
          ~&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;:some-set&lt;/span&gt; project&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt; #{&lt;span class=&quot;builtin&quot;&gt;:bad-key&lt;/span&gt;}&lt;span class=&quot;esk-paren&quot;&gt;)))&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;This delays the lookup of &lt;code&gt;clojure.set/difference&lt;/code&gt; to
  runtime, incurring a small penalty but tidily avoiding the Gilardi
  scenario. It also looks a bit ugly due to the quote-unquote-quote
  notation. This is necessary inside a backtick since symbols are
  fully-qualified to avoid accidental aliasing existing names. I'm
  not sure if this is an intentional design decision of Clojure,
  but it's certainly a sign that you're off the beaten path and
  into possibly-inadvisable territory.&lt;/p&gt;

&lt;p&gt;Leiningen used to encourage the &lt;code&gt;ns-resolve&lt;/code&gt; solution
  above since it needed to support eval of arbitrary forms from
  plugins. Even if your form had a &lt;code&gt;do&lt;/code&gt; at the top-level
  to invoke the compiler's special-case, you could easily have
  situations where &lt;a href=&quot;/141&quot;&gt;add-hook&lt;/a&gt; has been used to wrap
  the form in enclosing forms, making your &lt;code&gt;do&lt;/code&gt; nested
  deeply where the compiler wouldn't split it out.&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;defn&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;get-readable-form&lt;/span&gt; [java project form init]
  &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;let&lt;/span&gt; [cp &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;preprocessor&quot;&gt;.getClasspath&lt;/span&gt; &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;preprocessor&quot;&gt;.getCommandLine&lt;/span&gt; java&lt;span class=&quot;esk-paren&quot;&gt;)))&lt;/span&gt;
        form `&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; ~init
                  &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function-name&quot;&gt;~&lt;/span&gt;'classpath ~cp&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;
                  &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;set! ~'*warn-on-reflection*
                        ~&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;:warn-on-reflection&lt;/span&gt; project&lt;span class=&quot;esk-paren&quot;&gt;))&lt;/span&gt;
                  ~form&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;]
    &lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;builtin&quot;&gt;prn-str&lt;/span&gt; form&lt;span class=&quot;esk-paren&quot;&gt;)))&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;But the latest version of Leiningen makes it work
  without &lt;code&gt;ns-resolve&lt;/code&gt;. Even
  though &lt;code&gt;eval-in-project&lt;/code&gt; accepts any form to eval, it
  splices it into an existing &lt;code&gt;do&lt;/code&gt; form that places
  all &lt;code&gt;requires&lt;/code&gt; (the &lt;code&gt;init&lt;/code&gt; argument in the
  function above) into the top-level of the &lt;code&gt;do&lt;/code&gt; where
  the compiler can work its magic. So if you've got a namespace that
  your form is going to depend upon, just pass in &lt;code&gt;'(require
  'my.ns)&lt;/code&gt; as the &lt;code&gt;init&lt;/code&gt; arg
  to &lt;code&gt;eval-in-project&lt;/code&gt; to deftly maneuver your way
  through the Gilardi Scenario.&lt;/p&gt;
    </content>
  </entry>
  
  <entry xml:base="http://technomancy.us">
    <author><name>Phil Hagelberg</name></author>
    <id>tag:technomancy.us,2007:in%20which%20the%20conjference%20is%20recapitulated</id>
    <published>2010-10-31T05:15:28Z</published>
    <updated>2010-10-31T05:15:28Z</updated>

    <link href="http://technomancy.us/142" rel="alternate" type="text/html"/>
    <title>in which the conjference is recapitulated</title>
    <content type="html">
      &lt;p&gt;I got back last night from a week in &lt;abbr title=&quot;Boston-Atlanta
  Metropolitan Axis&quot;&gt;BAMA&lt;/abbr&gt; for
  the &lt;a href=&quot;http://first.clojure-conj.org/&quot;&gt;Clojure Conj&lt;/a&gt;
  conference. The consistent quality of the talks surpassed any
  other conference I've attended so far, and there was a palpable
  high-energy air of potential with so many focused hackers
  congregating for the first time. The only downside was that the
  breakneck pace of fitting all the talks into two days left little
  time for ad-hoc chatter and hackfests, something I've greatly
  enjoyed at Ruby conferences.&lt;/p&gt;

&lt;p&gt;I got a chance to speak on
  Leiningen. [&lt;a href=&quot;http://p.hagelb.org/conj-2010-slides.org.html&quot;&gt;slides&lt;/a&gt;]
  I opened with basic usage followed by a few little-known but
  useful features. After that I took some time to explain how
  Leiningen tasks are written and &lt;a href=&quot;/141&quot;&gt;extended&lt;/a&gt;. I
  spent a little more time on this since
  it's &lt;a href=&quot;http://stackoverflow.com/questions/3906276/whats-the-difference-between-cake-and-leiningen/3908108#3908108&quot;&gt;something
  that folks have asked about recently&lt;/a&gt;. The gist I tried to get
  across is that it's best to structure core concepts like tasks
  around functions rather than one-off mechanisms like macros or
  custom deftypes if at all possible as it encourages composability
  and is instantly recognizable to users at a glance.&lt;/p&gt;

&lt;p&gt;It turned out the emphasis on functions in order to support
  composability was a common theme that everyone seemed to come back
  around to, most notably Mark McGranahan on Ring and Stuart
  Halloway on simplicity in general.&lt;/p&gt;

&lt;img src=&quot;/i/stuart-simple.jpg&quot; alt=&quot;Stuart Halloway on Simplicity&quot; /&gt;

&lt;p&gt;Near the end of the conference Rich gave a self-professed
  non-technical rant on the simple subject of thinking hard about
  hard problems. He said that one of the things he's most thankful
  of in his life is the opportunity to spend years thinking about a
  few problems. The idea that you could think about a hard problem
  for months on end, in what he termed &quot;hammock time&quot;, is something
  most people (myself included) just hadn't ever considered.&lt;/p&gt;

&lt;img src=&quot;http://p.hagelb.org/hammock.jpg&quot; 
     alt=&quot;Stop. Hammock Time.&quot; align=&quot;left&quot; /&gt;

&lt;p&gt;When I met him after the &lt;a href=&quot;/139&quot;&gt;Emerging Languages&lt;/a&gt;
  conference earlier this year, he mentioned how the notion of
  linear version numbers no longer meshes with the reality of
  distributed development. On
  &lt;a href=&quot;http://clojars.org&quot;&gt;Clojars&lt;/a&gt; there's a notion of
  non-canonical versions being distributed under a separate group,
  which makes Maven unable to weed out duplicates. But if they were
  kept under the same group, it would have to use version numbers to
  distinguish between the official version and the patched
  one-offs. Even in a non-forked project you have branches from
  which you may wish to publish artifacts. Being linear, version
  numbers are really not well-suited for this. They are
  lexographically sorted, which means there's no way to denote that
  &lt;code&gt;1.3.0-alpha3&lt;/code&gt; may be newer
  than &lt;code&gt;1.3.0-par2&lt;/code&gt;. Dependency management needs to
  accept the fact that versions branch into trees. But representing
  it as such is really only the first step; the other tricky part is
  coming up with a strategy to choose a branch and how to decide
  between different dependencies that both may request different
  branches of a third dependency. It's a juicy problem that was also
  mentioned a few times at the Conj, and it may be the kind of
  &quot;hammock time&quot; problem to keep in the back of my mind for a few
  months or years.&lt;/p&gt;
    </content>
  </entry>
  
</feed>

