<?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-05-16T17:07:10Z</updated>

  
  <entry xml:base="http://technomancy.us">
    <author><name>Phil Hagelberg</name></author>
    <id>tag:technomancy.us,2007:in%20which%20three%20programming%20methods%20are%20compared</id>
    <published>2012-05-16T16:07:43Z</published>
    <updated>2012-05-16T16:07:43Z</updated>

    <link href="http://technomancy.us/161" rel="alternate" type="text/html"/>
    <title>in which three programming methods are compared</title>
    <content type="html">
      &lt;p&gt;There are, roughly speaking, three ways to develop large
  user-facing programs, which we will refer to here as 0) the Unix
  way, 1) the Emacs way, and 2) the wrong way.&lt;/p&gt;

&lt;p&gt;The Unix way has been expounded upon at length many times. It
  consists of many small programs which communicate by sending text
  over pipes or using the occasional signal. If you can get away
  with using this model, the simplicity and universality it offers
  is very compelling. You hook into a rich ecosystem of text-based
  processes with a long history of well-understood conventions.
  Anyone can tie into it with programs written in any language. But
  it's not well-suited for everything: sometimes the requirement of
  keeping each part of the system in its own process is too high a
  price to pay, and sometimes circumstances require a richer
  communication channel than just a stream of text.&lt;/p&gt;

&lt;p&gt;This is where the Emacs way shines. A small core written in a
  low-level language implements a higher-level language in which
  most of the rest of the program is implemented. Not only does the
  higher-level language ease the development of the trickier parts
  of the program, but it also makes it much easier to implement a
  good extension system since extensions are placed on even ground
  with the original program itself. I wrote about this in an earlier
  post on the live-development model Emacs offers:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;If you have to use some tacked-on &quot;plugin mechanism&quot;
  to customize it, then you’re going to be limited at the very least
  by the imagination of the author of the plugin mechanism; only the
  things he thought you would want to do with it are doable. But if
  you’re using the exact same tools as the original authors were
  using to write the program in the first place, you can bet they
  put all their effort into making that a seamless, powerful
  experience, and you'll be able to access things on an entirely new
  level.&lt;/p&gt;
  &lt;p&gt;-&lt;a href=&quot;/115&quot;&gt;in which a subject is attempted to be
      approached objectively, though such a thing is actually
      impossible&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;It's worth noting that this is the model under which Mozilla is
  developed. The core Mozilla platform is implemented mostly in a
  gnarly mash of C++, but applications
  like Firefox and &lt;a href=&quot;http://conkeror.org&quot;&gt;Conkeror&lt;/a&gt;
  are primarily written in JavaScript, as are extensions. Following
  the Emacs way accounted for Firefox's continuing popularity even
  back when it was getting trounced by competitors in terms of
  JavaScript performance. Chrome's extension mechanism is laughably
  simplistic in comparison.&lt;/p&gt;

&lt;p&gt;Finally for completeness sake, the wrong way is simply to write a
  large monolithic application in a low-level language, usually C++.
  Often half-hearted attempts at extension mechanisms are bolted on
  to programs developed this way, (usually in order to check off
  another box on a features list) but they are invariably
  frustrating and primitive and don't end up offering extension
  developers the same access to program internals that the
  developers of the original program itself have.&lt;/p&gt;

&lt;p&gt;The Unix way makes particularly explicit the notion of composing
  small programs, but the Emacs way shines when a single runtime
  process plays host to a number of independent programs that can
  interact with each other gracefully. For instance,
  the &lt;a href=&quot;&quot;&gt;Magit&lt;/a&gt; version control interface can run in the
  same Emacs instance as a SLIME session controlling a lisp project.
  They coexist in a complimentary way and compose together without
  interference. So rather than saying there are three ways to write
  large user-facing programs, it might be more accurate to say that
  there are zero good ways to write large user-facing programs and
  two ways to compose a number of small programs into a coherent
  system.&lt;/p&gt;

&lt;p&gt;This is especially interesting to me right now since it has come
  to my attention that when it was rewritten in the transition from
  version 2 to version
  3, &lt;a href=&quot;http://blog.ometer.com/2008/08/25/embeddable-languages/&quot;&gt;GNOME
  has switched to the second way&lt;/a&gt; via an embedded JavaScript
  runtime, which means things are about to
  get &lt;a href=&quot;https://github.com/technomancy/lein-gnome&quot;&gt;very
  interesting&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%20korean%20hardware%20pleases</id>
    <published>2012-05-09T04:25:14Z</published>
    <updated>2012-05-09T04:25:14Z</updated>

    <link href="http://technomancy.us/160" rel="alternate" type="text/html"/>
    <title>in which korean hardware pleases</title>
    <content type="html">
      &lt;p&gt;I just got a new laptop, and while I wouldn't post about it
  normally I've had a number of people ask me what I thought of it.
  For the last five years or so I've been a Thinkpad user
  exclusively, but the latest models of their lightweight X series
  have offered disappointing screens with 1366x786 being the only
  resolution option. Since my dignity prevents me from buying a
  laptop with fewer vertical pixels than my phone, I broadened my
  search this time around and came across the 13-inch Samsung Series
  9, aka NP900X3B.&lt;/p&gt;

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

&lt;p&gt;At first the most striking thing about it is its thin profile,
  but once you've started using it you realize it's the screen that
  really sets it apart. Samsung is the largest manufacturer of LCDs
  in the world, so it makes sense that the screen would be the
  distinguishing factor on their high-end models. The resolution is
  1600x900, which I couldn't find in anything else smaller than 14
  inches, but it's the 400 cd/m&lt;sup&gt;2&lt;/sup&gt; of brightness that
  really sets it apart. With summer right around the corner, this
  perfect
  for &lt;a href=&quot;http://www.flickr.com/photos/technomancy/tags/remoteoffice/&quot;&gt;working
  outdoors&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While I'm pretty thrilled with the new machine, the thin profile
  forces some difficult compromises with the keyboard. It's of the
  standard chicklet design, which is a drag coming from the
  Thinkpad. The X200s Thinkpad I was using previously had a very
  comfortable response and depth to it that you don't find with
  chicklet keybords. The Samsung also lacks a trackpoint, drainage
  tray, and dedicated volume buttons. The X200s isn't appreciably
  heavier than the Samsung; (only ½ a pound more) but it is over
  twice as thick. Personally if it's light enough I don't find
  thickness to be a problem; I'd much rather have a comfortable
  keyboard than a 0.4-inch profile. But it does turn heads.&lt;/p&gt;

&lt;p&gt;The speakers on ultraportable laptops like the X200s typically
  come across as a token effort to fill a feature checkbox, but the
  Samsung's are fairly respectable. I was pleased to see the lack of
  the hardware wifi kill switch that plagued me on my Thinkpad. It's
  also got a bigger selection of ports than you'd expect with the
  slim profile: USB 2, USB 3, micro-HDMI, combined mic/headphones,
  and Ethernet, though the latter must be used with the provided
  adapter.&lt;/p&gt;

&lt;p&gt;I'm running Debian Wheezy on it because I
  read &lt;a href=&quot;http://www.ing.unitn.it/~zatelli/linux/samsung.html&quot;&gt;on
  a blog post&lt;/a&gt; that a newer kernel was needed for the wifi
  drivers, but apparently this was only the case with an earlier
  model of the Series 9 that used the Broadcom chipset; The NP900X3B
  uses an Intel chipset that has been well-supported for some time.
  Everything worked perfectly out of the box except the keys for
  adjusting the keyboard backlight. The camera, external monitor
  port, and multitouch trackpad work as you'd expect. The suspend
  functionality, which has traditionally lagged behind Mac OS X,
  resumes in a couple short seconds.&lt;/p&gt;

&lt;p&gt;While I would love to see this same screen on a laptop with the
  luxurious keyboard, carbon fiber body, and replaceable battery of a
  Thinkpad, the Series 9 is quite slick and should keep me happy for a
  number of years.&lt;/p&gt;
    </content>
  </entry>
  
  <entry xml:base="http://technomancy.us">
    <author><name>Phil Hagelberg</name></author>
    <id>tag:technomancy.us,2007:in%20which%20we%20plot%20an%20escape%20from%20the%20quagmire%20of%20equality</id>
    <published>2012-04-27T05:45:01Z</published>
    <updated>2012-04-27T05:45:01Z</updated>

    <link href="http://technomancy.us/159" rel="alternate" type="text/html"/>
    <title>in which we plot an escape from the quagmire of equality</title>
    <content type="html">
      &lt;p&gt;If you follow happenings in the Clojure world, you may have
  noticed that the announcement
  of &lt;a href=&quot;https://github.com/halgari/clojure-py&quot;&gt;clojure-py&lt;/a&gt;
  brings the number of runtimes targeted by Clojure up to four.
  While it's great to see the language expand beyond the JVM, it's
  not too exciting to me personally since the runtime I spend the
  most time in by far is that of Emacs. Of course, Emacs can already
  be programmed with lisp, but the dialect it uses leaves much to be
  desired. I miss first-class functions[&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;],
  destructuring, literals for associative data, and immutability
  whenever I find myself writing nontrivial Emacs Lisp code, and the
  lack of these features makes me reluctant to write in it even
  though it offers an environment with live feedback unmatched by anything
  but
  the &lt;a href=&quot;http://en.wikipedia.org/wiki/Smalltalk#Image-based_persistence&quot;&gt;Smalltalk
  images&lt;/a&gt;
  and &lt;a href=&quot;http://en.wikipedia.org/wiki/Genera_(operating_system)&quot;&gt;Lisp
  Machines&lt;/a&gt; of yore.&lt;/p&gt;

&lt;img src=&quot;http://p.hagelb.org/duck-hand.png&quot; align=&quot;right&quot;
     alt=&quot;why? why do you need a reason?&quot; 
     title=&quot;why? why do you need a reason?&quot; /&gt;

&lt;p&gt;Part of what makes ClojureScript interesting is that it has
  distilled the number of primitives needed to port Clojure to a new
  runtime down to a small number due to its push towards
  self-hosting. One of the Summer of Code projects for this year is
  to allow for pluggable backends in the ClojureScript compiler,
  with Lua as a proof of concept. I started to think through what
  would be necessary for this to happen on the Emacs runtime, but I
  ran into an interesting quandary
  regarding &lt;a href=&quot;http://en.wikipedia.org/wiki/Referential_transparency_(computer_science)&quot;&gt;referential
  transparency&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A function is referentially transparent when it is guaranteed to
  return the same value every time it is called with a given set of
  arguments. This is a great guarantee to be able to make about your
  functions as it reduces the number of things you need to keep
  in your head. Referentially transparent functions really can be
  thought of as black boxes: always deterministic and predictable.
  But a function that operates on mutable objects cannot be
  referentially transparent&amp;mdash;it cannot make any guarantees that
  future calls involving that same object will result in the same
  value since that object could have a different value at any time.&lt;/p&gt;

&lt;p&gt;Since Emacs Lisp does not provide any immutable data types other
  than numbers, only functions that operate on numbers alone can be
  referentially transparent. This is a shame, since referential
  transparency allows you to have much greater confidence that your
  code is correct. Without it, the best you can say is &quot;as long as
  the rest of this program behaves itself, this function should
  work&quot;. This works a lot like older OSes with cooperative
  multitasking and no process memory isolation, which is to say not
  very well.&lt;/p&gt;

&lt;p&gt;But arguably the worst thing about lacking referential
  transparency is that you can't check for equality in a
  meaningful way. Henry Baker's
  paper &lt;a href=&quot;http://home.pipeline.com/~hbaker1/ObjectIdentity.html&quot;&gt;&quot;Equal
  Rights for Functional Objects&quot;&lt;/a&gt; addresses the problem of
  equality in Common Lisp[&lt;a href=&quot;#fn2&quot;&gt;2&lt;/a&gt;], which is notable for
  having a plethora of equality predicates depending on what level
  of coarseness you want:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;EQ&lt;/code&gt;: are both arguments the same object in memory?&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;EQL&lt;/code&gt;: like &lt;code&gt;EQ&lt;/code&gt;, but compares value for
    non-immediate numbers like tagged fixnums and bignums.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;EQUAL&lt;/code&gt;: do both arguments have the same structure
    and contents?&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;EQUALP&lt;/code&gt;: like &lt;code&gt;EQUAL&lt;/code&gt;, but allows
    integers to equal floats and ignores string case.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;=&lt;/code&gt;: are both numbers of equal value?&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;CHAR=&lt;/code&gt;, &lt;code&gt;STRING=&lt;/code&gt;, &lt;code&gt;STRING-EQUAL&lt;/code&gt;,
    ad nauseum.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Baker argues that this confusion is due to a muddled notion of
  object identity. Everything would be so much simpler if we could
  think in terms of operational equivalence:&lt;/p&gt;

&lt;blockquote&gt;Two objects are &quot;operationally equivalent&quot; if and only
  if there is no way that they can be distinguished, using ...
  primitives other than [equality primitives].[RNRS]&lt;/blockquote&gt;

&lt;p&gt;Asking &quot;Are these two objects stored in the same memory
  location?&quot; lets implementation details leak into your code.
  Equality should really be about &quot;Can these two objects behave
  differently in any observable way?&quot;. Baker's paper implements the
  &lt;code&gt;egal&lt;/code&gt; function in terms of this question; it's an
  equality predicate that defines object identity as a transitive
  closure of immutable attributes of an object. So without
  immutability, &lt;code&gt;egal&lt;/code&gt; always returns false.&lt;/p&gt;

&lt;p&gt;Of course, with a compiler that targets Emacs Lisp, you can work
  around this by implementing your own immutable types. But this
  makes any form of interop much more cumbersome; close integration
  with its host platform is one of the core design tenets of
  Clojure, and having to perform conversions on basic types like
  strings just to call native elisp functions would be too
  cumbersome to be practical. So with the Emacs runtime as it is,
  you have to choose between getting equality right and seamless
  interop. Damned if you do; damned if you don't.&lt;/p&gt;

&lt;p&gt;There are two possible solutions to this. There has been an
  ongoing effort to
  get &lt;a href=&quot;http://www.emacswiki.org/emacs/GuileEmacs&quot;&gt;Emacs Lisp
  running on the Guile VM&lt;/a&gt;. As it comes from a Scheme background,
  Guile provides the immutable data types we need. &lt;b&gt;Update&lt;/b&gt;:
  the immutable types offered in Guile do not actually come from the
  Scheme standard, but they are present nonetheless. However, Emacs
  Lisp is very different from Scheme, and the Guile implementors
  have an enormous task ahead of them to get even the basics
  working; the amount of work needed to achieve compatibility with
  the bulk of quirky extant Emacs Lisp code is daunting. But it
  would be wonderful if it were possible.&lt;/p&gt;

&lt;p&gt;The more realistic option is to add immutable data types to the
  existing Emacs implementation. I suggested in passing on the
  emacs-devel mailing list that I would be interested in financially
  supporting such a feature, which led
  to &lt;a href=&quot;http://lists.gnu.org/archive/html/emacs-devel/2012-04/msg00684.html&quot;&gt;
  a discussion of its pros and cons&lt;/a&gt;. It turns out there is very
  little code that would break if Emacs strings became immutable;
  even though it's possible to change strings it happens rarely
  enough in real code to not pose serious problems. Changing lists
  to be immutable would break huge amounts of code though, so a more
  reasonable approach would be to offer an alternate list
  constructor for immutable lists so that functional code could have
  access to immutability without wreaking havoc on existing
  functionality. Ideally libraries could opt-in to having the reader
  return immutable lists, but I don't know enough about Emacs's
  reader to know how feasible this is.&lt;/p&gt;

&lt;p&gt;Unfortunately I'm not the one calling the shots; I don't have the
  C skills necessary to make it happen even if the Emacs maintainers
  were favourable to the idea. But it's interesting to think about,
  especially as concurrency may be introduced in Emacs 25. One
  certainly can dream.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;[&lt;a name=&quot;fn1&quot;&gt;1&lt;/a&gt;] Common Lisp fans claim that lisp-2s have
  first-class functions, but the way they are kept separate from
  other first-class values in their own namespace ghetto brings to
  mind claims of &quot;separate but equal&quot;&amp;mdash;at best it is Jim Crow
  functional programming.&lt;/p&gt;

&lt;p&gt;[&lt;a name=&quot;fn2&quot;&gt;2&lt;/a&gt;] Emacs Lisp is not Common Lisp, but the two
  dialects are very closely related, and for the purposes of this
  post share the same problems.&lt;/p&gt;
    </content>
  </entry>
  
  <entry xml:base="http://technomancy.us">
    <author><name>Phil Hagelberg</name></author>
    <id>tag:technomancy.us,2007:in%20which%20we%20coin%20a%20term%20which%20is%20the%20opposite%20of%20deprecate</id>
    <published>2012-02-29T00:57:50Z</published>
    <updated>2012-02-29T00:57:50Z</updated>

    <link href="http://technomancy.us/158" rel="alternate" type="text/html"/>
    <title>in which we coin a term which is the opposite of deprecate</title>
    <content type="html">
      &lt;p&gt;Earlier this month
  I &lt;a href=&quot;http://lein-survey.herokuapp.com/results&quot;&gt;published the
  results&lt;/a&gt; of a survey I had posted for Leiningen users. I got a
  lot of great data, but I especially appreciated the free-form
  &quot;other comments&quot; section that let people just ramble. I was happy
  to see that many of the suggestions have already been implemented
  in the ongoing work on Leiningen 2.&lt;/p&gt;

&lt;blockquote&gt;I still think lein-multi should be rolled into core so
  people can be encouraged to test cross-version.&lt;/blockquote&gt;

&lt;h4&gt;Profiles&lt;/h4&gt;

&lt;p&gt;This brings me to what is probably the biggest feature in
  Leiningen 2.0: profiles. In Leiningen 1 we had some special
  cases to segregate out &quot;dev&quot; mode from the rest so you would only
  have certain dependencies or directories available during
  development. This is useful to have, but the implementation was
  pretty ad-hoc and riddled with special cases. During
  some &lt;a href=&quot;/155&quot;&gt;discussion with the Cake developers&lt;/a&gt; we
  talked about whether that could be generalized, which turned into
  the idea of profiles.&lt;/p&gt;

&lt;p&gt;So now rather than a handful of project configuration keys that
  are only active during development time, we have a &lt;tt&gt;:dev&lt;/tt&gt;
  profile that's active by default where you can keep your
  additional test-only &lt;tt&gt;:dependencies&lt;/tt&gt;
  and &lt;tt&gt;:resource-paths&lt;/tt&gt;. You can also keep all
  your &lt;tt&gt;:plugins&lt;/tt&gt; that you want active across all projects in
  the &lt;tt&gt;:user&lt;/tt&gt; profile rather than using &lt;kbd&gt;lein plugin
  install&lt;/kbd&gt;. That way there is only ever one plugin list active
  at a time, meaning it can be de-duplicated, avoiding messy conflicts.&lt;/p&gt;

&lt;p&gt;But you can also create profiles for other situations:&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;&lt;span class=&quot;esk-paren&quot;&gt;(&lt;/span&gt;defproject clj-http &lt;span class=&quot;string&quot;&gt;&quot;0.3.3-SNAPSHOT&quot;&lt;/span&gt;
  &lt;span class=&quot;constant&quot;&gt;:description&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;A Clojure HTTP library&quot;&lt;/span&gt;
  &lt;span class=&quot;constant&quot;&gt;:url&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;https://github.com/dakrone/clj-http/&quot;&lt;/span&gt;
  &lt;span class=&quot;constant&quot;&gt;:min-lein-version&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;2.0.0&quot;&lt;/span&gt;
  &lt;span class=&quot;constant&quot;&gt;:dependencies&lt;/span&gt; [[org.clojure/clojure &lt;span class=&quot;string&quot;&gt;&quot;1.3.0&quot;&lt;/span&gt;] &lt;span class=&quot;comment-delimiter&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;elided below...
&lt;/span&gt;                 [org.apache.httpcomponents/httpclient &lt;span class=&quot;string&quot;&gt;&quot;4.1.2&quot;&lt;/span&gt;]
                 [cheshire &lt;span class=&quot;string&quot;&gt;&quot;2.2.0&quot;&lt;/span&gt;]]
  &lt;span class=&quot;constant&quot;&gt;:profiles&lt;/span&gt; {&lt;span class=&quot;constant&quot;&gt;:dev&lt;/span&gt; {&lt;span class=&quot;constant&quot;&gt;:dependencies&lt;/span&gt; [[ring/ring-jetty-adapter &lt;span class=&quot;string&quot;&gt;&quot;1.0.2&quot;&lt;/span&gt;]
                                  [ring/ring-devel &lt;span class=&quot;string&quot;&gt;&quot;1.0.2&quot;&lt;/span&gt;]]}
             &lt;span class=&quot;constant&quot;&gt;:1.2&lt;/span&gt; {&lt;span class=&quot;constant&quot;&gt;:dependencies&lt;/span&gt; [[org.clojure/clojure &lt;span class=&quot;string&quot;&gt;&quot;1.2.1&quot;&lt;/span&gt;]]}
             &lt;span class=&quot;constant&quot;&gt;:1.4&lt;/span&gt; {&lt;span class=&quot;constant&quot;&gt;:dependencies&lt;/span&gt; [[org.clojure/clojure &lt;span class=&quot;string&quot;&gt;&quot;1.4.0-beta1&quot;&lt;/span&gt;]]}}
  &lt;span class=&quot;constant&quot;&gt;:aliases&lt;/span&gt; {&lt;span class=&quot;string&quot;&gt;&quot;all&quot;&lt;/span&gt; [&lt;span class=&quot;string&quot;&gt;&quot;with-profile&quot;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;dev,1.2:dev:dev,1.4&quot;&lt;/span&gt;]}&lt;span class=&quot;esk-paren&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Here you can see the &lt;tt&gt;:dev&lt;/tt&gt; profile with some handy
  dependencies used for testing, but there are also profiles
  for &lt;tt&gt;:1.2&lt;/tt&gt; and &lt;tt&gt;:1.4&lt;/tt&gt; that can be used like lein
  multi. The &lt;tt&gt;with-profile&lt;/tt&gt; task is used to apply alternate
  profiles to a given task run:&lt;/p&gt;

&lt;pre&gt;$ lein with-profile dev,1.2 test
Performing task 'test' with profile(s): 'dev,1.2'

Testing clj-http.test.client

Testing clj-http.test.cookies

Testing clj-http.test.core

Ran 47 tests containing 175 assertions.
0 failures, 0 errors.&lt;/pre&gt;

&lt;p&gt;You can see that commas allow multiple profiles to be specified
  at once. You can also use colons to chain together profile sets
  sequentially:&lt;/p&gt;

&lt;pre&gt;$ lein with-profile dev:dev,1.2:dev,1.4 test
Performing task 'test' with profile(s): 'dev'
[...]
Performing task 'test' with profile(s): 'dev,1.2'
[...]
Performing task 'test' with profile(s): 'dev,1.4'
[...]&lt;/pre&gt;

&lt;p&gt;Of course, since &lt;tt&gt;with-profile&lt;/tt&gt; is a higher-order task, it
  can accept any other task as an argument, not just &lt;tt&gt;test&lt;/tt&gt;.
  So you could use it for deploying to different environments or
  any place where you'd want an alternate set of project
  configuration values.&lt;/p&gt;

&lt;h4&gt;Aliases&lt;/h4&gt;

&lt;p&gt;You'll also notice that the &lt;tt&gt;:aliases&lt;/tt&gt; entry in the
  &lt;tt&gt;defproject&lt;/tt&gt; above maps a string to a vector. This is a new
  feature about which I am unreasonably pleased. You've always been
  able to add aliases for Leiningen tasks; this is how &lt;kbd&gt;lein
  halp&lt;/kbd&gt; has worked. But now you can actually alias a string to
  a partial application of a task:&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;&lt;span class=&quot;constant&quot;&gt;:aliases&lt;/span&gt; {&lt;span class=&quot;string&quot;&gt;&quot;all&quot;&lt;/span&gt; [&lt;span class=&quot;string&quot;&gt;&quot;with-profile&quot;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;dev,1.2:dev:dev,1.4&quot;&lt;/span&gt;]}&lt;/pre&gt;

&lt;p&gt;This means that &lt;kbd&gt;all test&lt;/kbd&gt; translates into
  calling &lt;kbd&gt;with-profile dev,1.2:dev:dev,1.4 test&lt;/kbd&gt;. But
  partially-applied aliases have other uses as well:&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;&lt;span class=&quot;constant&quot;&gt;:aliases&lt;/span&gt; {&lt;span class=&quot;string&quot;&gt;&quot;reflect&quot;&lt;/span&gt; [&lt;span class=&quot;string&quot;&gt;&quot;assoc&quot;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;:warn-on-reflection&quot;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;compile&quot;&lt;/span&gt;]}&lt;/pre&gt;

&lt;p&gt;This allows you to invoke &lt;kbd&gt;lein reflect&lt;/kbd&gt; to get a list
  of all your reflection warnings. Note that in this
  case &lt;kbd&gt;assoc&lt;/kbd&gt; refers to the task that comes from
  the &lt;a href=&quot;https://github.com/technomancy/lein-assoc&quot;&gt;lein-assoc&lt;/a&gt;
  plugin, not the &lt;kbd&gt;clojure.core/assoc&lt;/kbd&gt; function. Each
  string in the alias vector is interpreted the same way as if it
  were a direct command-line argument to the &lt;kbd&gt;lein&lt;/kbd&gt; script,
  which is why strings must be used. In this case reading it into
  keywords and booleans happens inside the &lt;kbd&gt;assoc&lt;/kbd&gt;
  task.&lt;/p&gt;

&lt;p&gt;And that's one of the neat things about having tasks as functions.&lt;/p&gt;

&lt;h4&gt;Preview&lt;/h4&gt;

&lt;p&gt;By this point I'm sure you're thinking to yourself, &quot;Gosh, that
  sounds super; I wish I could use it now!&quot; In fact, Leiningen 2 is
  already pretty usable and stable if you don't mind running from
  git. You need a copy of Leiningen 1.x around to bootstrap it, but
  running &lt;kbd&gt;lein install&lt;/kbd&gt; inside the &lt;tt&gt;leiningen-core&lt;/tt&gt;
  directory should get you to the point where you can
  symlink &lt;tt&gt;bin/lein&lt;/tt&gt; to somewhere on your path and have it
  work. I recommend linking it as &lt;tt&gt;lein2&lt;/tt&gt; for the time being
  since you'll probably still need an installation of 1.x easily
  accessible.&lt;/p&gt;

&lt;p&gt;Of course, being a major version increment it's got some
  backwards-incompatibilities. Fresh from witnessing the very bumpy
  transition to Clojure 1.3, I'd rather avoid that for Leiningen 2,
  so taking a cue from golang's &lt;tt&gt;gofix&lt;/tt&gt; tool, I've
  released the &lt;tt&gt;lein-precate&lt;/tt&gt; plugin.&lt;/p&gt;

&lt;p&gt;Precate, obviously, is the opposite of deprecate. The idea is
  that you could run it on your project and have it spit out a new
  &lt;tt&gt;project.clj&lt;/tt&gt; which would be compatible with Leiningen 2.
  It's not perfect, but it should provide you with a starting point
  for your transition:&lt;/p&gt;

&lt;pre&gt;$ lein plugin install lein-precate 0.3.0
$ cat project.clj # the original 1.x-compatible version:
(defproject clojure-http-client &quot;1.1.1-SNAPSHOT&quot;
  :description &quot;An HTTP client for Clojure.&quot;
  :source-path &quot;src/clj&quot;
  :extra-classpath-dirs [&quot;dumb-stuff&quot;]
  :dev-dependencies [[swank-clojure &quot;1.3.4&quot;]]
  :dependencies [[org.clojure/clojure &quot;1.2.1&quot;]
                 [org.clojure/clojure-contrib &quot;1.2.0&quot;]])

$ lein precate # let's see how that would look for Leiningen 2
(defproject clojure-http-client &quot;1.1.1-SNAPSHOT&quot;
  :description &quot;An HTTP client for Clojure.&quot;
  :source-paths [&quot;src/clj&quot;]
  :dependencies {org.clojure/clojure &quot;1.2.1&quot;, 
                 org.clojure/clojure-contrib &quot;1.2.0&quot;}
  :profiles {:dev
              {:resource-paths [&quot;dumb-stuff&quot;],
               :dependencies {swank-clojure &quot;1.3.4&quot;}}}
  :min-lein-version &quot;2.0.0&quot;)&lt;/pre&gt;

&lt;p&gt;Unfortunately that output had to be manually edited a bit for cosmetic
  reasons; Clojure's pretty-printer doesn't really know what to do
  with &lt;code&gt;defproject&lt;/code&gt; forms. But it should cover most of
  the changes necessary to take your project into the exciting new
  world of Leiningen 2. The biggest changes will come from the move
  from &lt;tt&gt;:dev-dependencies&lt;/tt&gt; to &lt;tt&gt;:dependencies&lt;/tt&gt; in
  the &lt;tt&gt;:dev&lt;/tt&gt; profile. But this is not a foolproof translation
  since in Leiningen 2 &lt;tt&gt;:dependencies&lt;/tt&gt; only run in the
  context of the project itself, while in Leiningen
  1 &lt;tt&gt;:dev-dependencies&lt;/tt&gt; ran in both Leiningen and the
  project. In retrospect this was a design mistake, but there are a
  number of plugins out there that take advantage of this fact and
  will need to be split into separate artifacts for the parts that
  run in Leiningen vs the parts that run in the project. I've taken
  some time to adapt some of the most commonly-used plugins for this
  change, but I'm sure I missed some of the more obscure ones.&lt;/p&gt;

&lt;p&gt;The plan from here is to polish off a few more features and cut a
  preview release. The preview will still be missing a handful of
  the more obscure features from Leiningen 1 like shell wrappers and
  selective transitive class file cleaning, but for the vast
  majority of projects it should be usable for everyday work. See
  the &quot;post-preview&quot; section
  of &lt;a href=&quot;https://github.com/technomancy/leiningen/blob/master/todo.org&quot;&gt;the
  todo file&lt;/a&gt; for details on what's remaining. The hope is to have
  it ready at latest by
  the &lt;a href=&quot;http://clojurewest.org/&quot;&gt;Clojure/West
  conference&lt;/a&gt;. Enjoy!&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Update&lt;/b&gt;: Leiningen
    2.0.0-preview3 &lt;a href=&quot;https://groups.google.com/group/clojure/browse_thread/thread/91079a531ee1f1c8&quot;&gt;has
    been released&lt;/a&gt;! See
    the &lt;a href=&quot;https://github.com/technomancy/leiningen/wiki/Upgrading&quot;&gt;upgrade
    guide&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%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>
  
</feed>

