<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:wfw="http://wellformedweb.org/CommentAPI/"
     xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:atom="http://www.w3.org/2005/Atom"
     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">
  <channel>
    <title>Asymmetrical View</title>
    <atom:link href="http://asymmetrical-view.com/feed/" rel="self" type="application/rss+xml" />
    <link>http://asymmetrical-view.com/</link>
    <description>Seeking no barriers to abstraction</description>
    <pubDate>2010-07-07T00:16:46-04:00</pubDate>

    <generator>http://asymmetrical-view.com/</generator>
    <language>en</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>

    
    <item>
      <title>Automating Capistrano Password Prompts with Expect</title>
      <link>http://blog.asymmetrical-view.com/2010/07/06/automate-capistrano-passwords.html</link>
      <comments>http://blog.asymmetrical-view.com/2010/07/06/automate-capistrano-passwords.html#comments</comments>

      <pubDate>2010-07-06T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2010/07/06/automate-capistrano-passwords.html</guid>

      <id>http://blog.asymmetrical-view.com/2010/07/06/automate-capistrano-passwords</id>
      <description><![CDATA[<h1>Automating Capistrano Password Prompts with Expect</h1>
<p>I just started using <a href="http://capify.org/">Capistrano</a> for deploying my <a href="http://rubyonrails.org/">Rails</a> applications (like <a href="http://snapclean.me/">Snapclean.me</a>&quot;).  I also just started using <a href="http://github.com/vigetlabs/capistrano_rsync_with_remote_cache">capistrano_rsync_with_remote_cache</a> to help push releases out faster than the <code>:copy</code> deploy strategy.</p>
<p>I&#8217;m very happy with how much faster it is than the a <code>:copy</code>, but I&#8217;m impatient and having to provide the password more than once per invocation is frustrating to me.  I know the old Unix standby <a href="http://en.wikipedia.org/wiki/Expect">Expect</a> can do this easily, my only problem is I don&#8217;t remember <a href="http://en.wikipedia.org/wiki/Tcl">Tcl</a> very well and every time I&#8217;ve done this I forget how / what I did.  This post is a write up so I know where to come back to the next time I need to do this (and I know I&#8217;ll run into it again).</p>
<h2>Spawn and Expect</h2>
<p>Conceptually the basic use of Expect is very straight forward.  You execute another program and you can register handlers that will be invoked when the program emits specific output.  In the case of executing capistrano, and it executing other commands, I&#8217;m looking for anything that looks like a password prompt.  When a password prompt is emitted I want to send the password.</p>
<p>The script below does exactly that, first asking the user for the password (disabling terminal echo) before spawning the capistrano command itself.</p>

<pre class="code">
#!/usr/bin/env expect
stty -echo
send_user -- "Login Password: "
expect_user -re "(.*)\n"
send_user "\n"
stty echo
set the_password $expect_out(1,string)

spawn cap deploy
expect {
  -re " *\[Pp\]assword: *" {
    send "$the_password\n"
    exp_continue
  }
}
</pre>
<p>I put the above script in a file called <code>wrap-cap</code>, and did a <code>chmod 755 ./wrap-cap</code> on the file.</p>
<p>The <code>exp_continue</code> is used to reset (or loop) expect so that it will continue to look for password prompts and provide the password as many times as it is requested &#8211; since there are various commands that may ask for it (rsync, ssh, sudo, etc.) and some of them are optional (especially sudo), this &#8216;looping&#8217; behavior is very handy.</p>
<p>Expect is a great Unix tool for developers and system administrators to have in their toolboxes.</p>
<p class="meta">Kyle Burton, 6 Jul 2010 &#8211; Philadelphia PA</p>
<p><br /></p>]]></description>
      <content:encoded><![CDATA[<h1>Automating Capistrano Password Prompts with Expect</h1>
<p>I just started using <a href="http://capify.org/">Capistrano</a> for deploying my <a href="http://rubyonrails.org/">Rails</a> applications (like <a href="http://snapclean.me/">Snapclean.me</a>&quot;).  I also just started using <a href="http://github.com/vigetlabs/capistrano_rsync_with_remote_cache">capistrano_rsync_with_remote_cache</a> to help push releases out faster than the <code>:copy</code> deploy strategy.</p>
<p>I&#8217;m very happy with how much faster it is than the a <code>:copy</code>, but I&#8217;m impatient and having to provide the password more than once per invocation is frustrating to me.  I know the old Unix standby <a href="http://en.wikipedia.org/wiki/Expect">Expect</a> can do this easily, my only problem is I don&#8217;t remember <a href="http://en.wikipedia.org/wiki/Tcl">Tcl</a> very well and every time I&#8217;ve done this I forget how / what I did.  This post is a write up so I know where to come back to the next time I need to do this (and I know I&#8217;ll run into it again).</p>
<h2>Spawn and Expect</h2>
<p>Conceptually the basic use of Expect is very straight forward.  You execute another program and you can register handlers that will be invoked when the program emits specific output.  In the case of executing capistrano, and it executing other commands, I&#8217;m looking for anything that looks like a password prompt.  When a password prompt is emitted I want to send the password.</p>
<p>The script below does exactly that, first asking the user for the password (disabling terminal echo) before spawning the capistrano command itself.</p>

<pre class="code">
#!/usr/bin/env expect
stty -echo
send_user -- "Login Password: "
expect_user -re "(.*)\n"
send_user "\n"
stty echo
set the_password $expect_out(1,string)

spawn cap deploy
expect {
  -re " *\[Pp\]assword: *" {
    send "$the_password\n"
    exp_continue
  }
}
</pre>
<p>I put the above script in a file called <code>wrap-cap</code>, and did a <code>chmod 755 ./wrap-cap</code> on the file.</p>
<p>The <code>exp_continue</code> is used to reset (or loop) expect so that it will continue to look for password prompts and provide the password as many times as it is requested &#8211; since there are various commands that may ask for it (rsync, ssh, sudo, etc.) and some of them are optional (especially sudo), this &#8216;looping&#8217; behavior is very handy.</p>
<p>Expect is a great Unix tool for developers and system administrators to have in their toolboxes.</p>
<p class="meta">Kyle Burton, 6 Jul 2010 &#8211; Philadelphia PA</p>
<p><br /></p>]]></content:encoded>
    </item>
    
    <item>
      <title>New Clojure Libraries: Bloom Filter and LFSR</title>
      <link>http://blog.asymmetrical-view.com/2010/07/01/two-new-clojure-libs.html</link>
      <comments>http://blog.asymmetrical-view.com/2010/07/01/two-new-clojure-libs.html#comments</comments>

      <pubDate>2010-07-01T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2010/07/01/two-new-clojure-libs.html</guid>

      <id>http://blog.asymmetrical-view.com/2010/07/01/two-new-clojure-libs</id>
      <description><![CDATA[<h1>New Clojure Libraries: Bloom Filter and <span class="caps">LFSR</span></h1>
<p>I created two new clojure libraries as part of my continued study of all things computing related.  I was introduced to the <a href="http://en.wikipedia.org/wiki/Bloom_filter">Bloom Filter</a> through <a href="http://news.ycombinator.com/">Hacker News</a> and to the <a href="http://en.wikipedia.org/wiki/LFSR">Linear Feedback Shift Register [<span class="caps">LFSR</span>]</a> through <a href="http://codeslinger.posterous.com/">Toby DiPasquale</a>.  It turns out that each of these will have practical application for me in the near future.  They are the kind of thing I wish I had learned about sooner.</p>
<h2><a href="http://en.wikipedia.org/wiki/Bloom_filter">Bloom Filter</a></h2>
<p>You can download clj-bloom from <a href="http://github.com/kyleburton/clj-bloom">Gitub.com/kyleburton/clj-bloom</a>  The filter is &#8220;a probabilistic data structure for testing set membership&#8221;, they &#8220;sacrifice determinism in favor of significantly lower memory usage&#8221;.  They make this trade off at the cost of false positives &#8211; but you can tune the filter&#8217;s false positive probability.  They are useful in situations when you need to test for membership in a very large set of data and can&#8217;t (or don&#8217;t want to) hold the set members themselves in memory.  A common use case is with a large corpus of documents &#8211; being able to quickly check if a new document is not in the set, storing it if it&#8217;s not, or pulling the existing copy and comparing it if you do.  In this type of use, a false positive has little impact as you&#8217;d pull the document and compare it anyway.  You can save the cost of making the initial query by using the bloom filter.</p>
<h2><a href="http://en.wikipedia.org/wiki/LFSR">Linear Feedback Shift Register [<span class="caps">LFSR</span>]</a></h2>
<p>LFSRs are related to Pseudo Random Number Generators [PRNGs].  There is a very interesting special class of LFSRs that have maximal period length &#8211; these LFSRs can be used as binary numbering systems since they iterate through all (2^n) &#8211; 1 possible bit combinations.  Unlike counting up from 1 in binary (0, 1, 10, 11, 100, 101, 110, 111, 1000, &#8230;) they are much less deterministic looking in how they iterate through the values.  I am currently looking at using them in ID generation, so that the IDs generated are not adjacent numeric values, eg: look pseudo-random, but are still guaranteed to be unique.  LFSRs are also easily serializable, which makes it possible for you to use them as a kind of pseudo random unique sequence.   You can download the code from <a href="http://github.com/kyleburton/clj-lfsr">Gitub.com/kyleburton/clj-lfsr</a></p>
<p>I found these two constructs fascinating, I hope you find the implementations useful.</p>
<p class="meta">Kyle Burton, 1 Jul 2010 &#8211; Philadelphia PA</p>
<p><br /></p>]]></description>
      <content:encoded><![CDATA[<h1>New Clojure Libraries: Bloom Filter and <span class="caps">LFSR</span></h1>
<p>I created two new clojure libraries as part of my continued study of all things computing related.  I was introduced to the <a href="http://en.wikipedia.org/wiki/Bloom_filter">Bloom Filter</a> through <a href="http://news.ycombinator.com/">Hacker News</a> and to the <a href="http://en.wikipedia.org/wiki/LFSR">Linear Feedback Shift Register [<span class="caps">LFSR</span>]</a> through <a href="http://codeslinger.posterous.com/">Toby DiPasquale</a>.  It turns out that each of these will have practical application for me in the near future.  They are the kind of thing I wish I had learned about sooner.</p>
<h2><a href="http://en.wikipedia.org/wiki/Bloom_filter">Bloom Filter</a></h2>
<p>You can download clj-bloom from <a href="http://github.com/kyleburton/clj-bloom">Gitub.com/kyleburton/clj-bloom</a>  The filter is &#8220;a probabilistic data structure for testing set membership&#8221;, they &#8220;sacrifice determinism in favor of significantly lower memory usage&#8221;.  They make this trade off at the cost of false positives &#8211; but you can tune the filter&#8217;s false positive probability.  They are useful in situations when you need to test for membership in a very large set of data and can&#8217;t (or don&#8217;t want to) hold the set members themselves in memory.  A common use case is with a large corpus of documents &#8211; being able to quickly check if a new document is not in the set, storing it if it&#8217;s not, or pulling the existing copy and comparing it if you do.  In this type of use, a false positive has little impact as you&#8217;d pull the document and compare it anyway.  You can save the cost of making the initial query by using the bloom filter.</p>
<h2><a href="http://en.wikipedia.org/wiki/LFSR">Linear Feedback Shift Register [<span class="caps">LFSR</span>]</a></h2>
<p>LFSRs are related to Pseudo Random Number Generators [PRNGs].  There is a very interesting special class of LFSRs that have maximal period length &#8211; these LFSRs can be used as binary numbering systems since they iterate through all (2^n) &#8211; 1 possible bit combinations.  Unlike counting up from 1 in binary (0, 1, 10, 11, 100, 101, 110, 111, 1000, &#8230;) they are much less deterministic looking in how they iterate through the values.  I am currently looking at using them in ID generation, so that the IDs generated are not adjacent numeric values, eg: look pseudo-random, but are still guaranteed to be unique.  LFSRs are also easily serializable, which makes it possible for you to use them as a kind of pseudo random unique sequence.   You can download the code from <a href="http://github.com/kyleburton/clj-lfsr">Gitub.com/kyleburton/clj-lfsr</a></p>
<p>I found these two constructs fascinating, I hope you find the implementations useful.</p>
<p class="meta">Kyle Burton, 1 Jul 2010 &#8211; Philadelphia PA</p>
<p><br /></p>]]></content:encoded>
    </item>
    
    <item>
      <title>How We Run Cucumber</title>
      <link>http://blog.asymmetrical-view.com/2010/06/10/how-we-run-cucumber.html</link>
      <comments>http://blog.asymmetrical-view.com/2010/06/10/how-we-run-cucumber.html#comments</comments>

      <pubDate>2010-06-10T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2010/06/10/how-we-run-cucumber.html</guid>

      <id>http://blog.asymmetrical-view.com/2010/06/10/how-we-run-cucumber</id>
      <description><![CDATA[<h1>How We Run Cucumber</h1>
<p><a href="http://cukes.info/">Cucumber</a> is a wonderful behavior driven development tool by <a href="http://github.com/aslakhellesoy/">Aslak Hellesøy</a>.  There is a <a href="http://wiki.github.com/aslakhellesoy/cucumber/">getting started</a> guide in the wiki at <a href="http://github.com/aslakhellesoy/cucumber">github</a> that describes how to get it set up and running.</p>
<p>We&#8217;ve written a wrapper around Cucumber to help make it easier to run along with our application and to make it less intrusive when it runs the browser (at least under Linux).</p>
<h2>Server Execution</h2>
<p>Most of our test driven development doesn&#8217;t require <code>script/server</code> to be running the web application, and we want it to run under either the <code>cucumber</code> or <code>test</code> rails environment when it does.  Stopping (if it&#8217;s running) the development server, starting it and then shutting it down again when the tests are done was a manual process that we automated.</p>
<h2>Xnest</h2>
<p>When we run Cucumber under X Windows, it often grabs focus and keeps us from doing anything else with the desktop while the tests are running.  This is annoying to say the least.  Thankfully X11 has a utility called Xnest which allows you to run a window which is a contained X desktop.  Running this and then telling the browser to run inside it keeps it out of our way and allows us to keep using the machine without being constantly interrupted by the browser constantly jumping to the foreground.</p>
<h2><code>script/server</code> Arguments</h2>
<p>To pass arguments (such as the port, or other options) through to <code>script/server</code>, put a <code>--</code> between the arguments to <code>script/cucumber-runner</code> and they will be passed on verbatim to <code>script/server</code>.  In this example, <code>-p 8080</code> will be passed to <code>script/server</code> instructing it to use port 8080.</p>
<pre class="code">
$ script/cucumber-runner -g 1024x768 -- -p 8080
</pre>
<h2><code>cucumber-runner</code></h2>


<pre class="code">
#!/usr/bin/env ruby
require 'optparse'

# Controller for running Cucumber feature tests on your Rails application.
# Supports stopping/starting WEBRick in cucumber or test rails environment and
# (on supporting systems, eg: Linux) running the browser under Xnest to keep it
# away from your other desktop activities.
#
#
# Author::     Kyle Burton &lt;kyle.burton@gmail.com&gt;
# Copyright::  Copyright (c) 2010 Kyle Burton
# License::    Distributes under the same terms as Ruby

#
# Command line runner.
#
class CucumberRunner

  # location of the rails scripts
  SCRIPT_ROOT = File.dirname(__FILE__)

  # Set up defaults, can be overridden with command line parameters.
  def initialize
    @opts = {
      :env             =&gt; 'cucumber',
      :geometry        =&gt; '1280x800',
      :display         =&gt; ENV['DISPLAY'],
      :xnest_display   =&gt; ':2',
      :control_webrick =&gt; true,
      :try_use_xnest   =&gt; true
    }
  end

  # Determine if Xnest is present, and if it should be used (Not on OS X).
  def use_xnest?
    return false unless @opts[:try_use_xnest]
    on_darwin = (`uname` =~ /Darwin/)
    has_xnest = !(`which Xnest`.empty?)
    !on_darwin &amp;&amp; has_xnest
  end

  # Start Xnest in the background, save off the pid so it can be stopped later.
  def start_xnest
    @opts[:display] = @opts[:xnest_display]
    cmd = "Xnest #{@opts[:xnest_display]} &amp; echo $!"
    @xnest_pid = `#{cmd}`.to_i
  end

  # Stop Xnest with a SIGTERM.
  def stop_xnest
    Process.kill("TERM", @xnest_pid) if @xnest_pid
  end

  # Stop the WEBRick server by looking for it in the process tree.
  def stop_webrick
    res = `ps aux | grep [r]uby | grep [s]cript/server`
    pid = res.split[1]
    return unless pid
    puts "#{$0} STOPPING WEBRick pid=#{pid}"
    Process.kill "KILL", pid.to_i
  end

  # Start WEBRick with the configured rails environment as a daemon (background).
  def start_webrick
    cmd = "#{SCRIPT_ROOT}/server -e #{@opts[:env]} -d"
    puts "#{$0} Starting WEBRick: #{cmd}"
    system cmd
  end

  # Process any command line arguments.
  def parse_opts
    OptionParser.new do |opts|
      opts.banner = "Usage: #{$0} [options]"

      opts.on("-h", "--help") do
        puts &lt;&lt;-EOH
       #{$0} [[opts]]

        -e ENV  --envrionment ENV   Rails environment to run under default=#{@opts[:env]}
        -g GEO  --geometry GEO      Xnest geometry to use default=#{@opts[:geometry]}
        -X      --no-xnest          Do not use Xnest (even if present)
        -d DSP  --display DSP       DISPLAY to use default=#{@opts[:display]}
        -x DSP  --xnest-display DSP Xnest's DISPLAY to use default=#{@opts[:xnest_display]}
        -W      --no-webrick        Don't start WEBRick (assume running) default=false
        EOH
        exit 0
      end

      opts.on("-e", "--envrionment ENV") do |env|
        @opts[:env] = env
      end

      opts.on("-g", "--geometry GEO") do |geo|
        @opts[:geometry] = geo
      end

      opts.on("-X", "--no-xnest") do
        options[:use_xnest] = false
      end

      opts.on("-d", "--display DSP") do |dsp|
        options[:display] = dsp
      end

      opts.on("-x", "--xnest-display DISP") do |disp|
        options[:xnest_display] = disp
      end

      opts.on("-W", "--no-webrick") do
        options[:control_webrick] = false
      end
    end.parse!
  end

  # Process options, start Xnest, [re]start WEBRick, execute the cucumber
  # suite, then stop Xnest and stop WEBrick
  def run
    parse_opts
    start_xnest if use_xnest?

    if @opts[:control_webrick]
      stop_webrick
      start_webrick
    end

    cmd = "#{SCRIPT_ROOT}/runner #{SCRIPT_ROOT}/cucumber #{ARGV}"
    ENV['DISPLAY']   = @opts[:display]
    ENV['RAILS_ENV'] = @opts[:env]
    puts "#{$0} using RAILS_ENV=#{ENV['RAILS_ENV']}"
    res = system cmd

  ensure
    stop_webrick  if @opts[:control_webrick]
    stop_xnest    if @xnest_pid
  end

  def self.main
    self.new.run
  end
end

CucumberRunner.main
</pre>
<p>You can download or check out <a href="http://github.com/kyleburton/cucumber-example/blob/master/cukeex/script/cucumber-runner">cucumber-runner</a> from my github <a href="http://github.com/kyleburton/cucumber-example/">cucumber-example project</a>.</p>
<p>Running Cucumber with this wrapper helps make it easier and less intrusive to use.  If anyone has suggestions for how to make it less intrusive while running under OS X, please <a href="mailto:kyle.burton@gmail.com">email me</a>, I&#8217;d love to hear your suggestions.</p>
<p class="meta">Kyle Burton, 10 Jun 2010 &#8211; Philadelphia PA</p>
<p><br /></p>]]></description>
      <content:encoded><![CDATA[<h1>How We Run Cucumber</h1>
<p><a href="http://cukes.info/">Cucumber</a> is a wonderful behavior driven development tool by <a href="http://github.com/aslakhellesoy/">Aslak Hellesøy</a>.  There is a <a href="http://wiki.github.com/aslakhellesoy/cucumber/">getting started</a> guide in the wiki at <a href="http://github.com/aslakhellesoy/cucumber">github</a> that describes how to get it set up and running.</p>
<p>We&#8217;ve written a wrapper around Cucumber to help make it easier to run along with our application and to make it less intrusive when it runs the browser (at least under Linux).</p>
<h2>Server Execution</h2>
<p>Most of our test driven development doesn&#8217;t require <code>script/server</code> to be running the web application, and we want it to run under either the <code>cucumber</code> or <code>test</code> rails environment when it does.  Stopping (if it&#8217;s running) the development server, starting it and then shutting it down again when the tests are done was a manual process that we automated.</p>
<h2>Xnest</h2>
<p>When we run Cucumber under X Windows, it often grabs focus and keeps us from doing anything else with the desktop while the tests are running.  This is annoying to say the least.  Thankfully X11 has a utility called Xnest which allows you to run a window which is a contained X desktop.  Running this and then telling the browser to run inside it keeps it out of our way and allows us to keep using the machine without being constantly interrupted by the browser constantly jumping to the foreground.</p>
<h2><code>script/server</code> Arguments</h2>
<p>To pass arguments (such as the port, or other options) through to <code>script/server</code>, put a <code>--</code> between the arguments to <code>script/cucumber-runner</code> and they will be passed on verbatim to <code>script/server</code>.  In this example, <code>-p 8080</code> will be passed to <code>script/server</code> instructing it to use port 8080.</p>
<pre class="code">
$ script/cucumber-runner -g 1024x768 -- -p 8080
</pre>
<h2><code>cucumber-runner</code></h2>


<pre class="code">
#!/usr/bin/env ruby
require 'optparse'

# Controller for running Cucumber feature tests on your Rails application.
# Supports stopping/starting WEBRick in cucumber or test rails environment and
# (on supporting systems, eg: Linux) running the browser under Xnest to keep it
# away from your other desktop activities.
#
#
# Author::     Kyle Burton &lt;kyle.burton@gmail.com&gt;
# Copyright::  Copyright (c) 2010 Kyle Burton
# License::    Distributes under the same terms as Ruby

#
# Command line runner.
#
class CucumberRunner

  # location of the rails scripts
  SCRIPT_ROOT = File.dirname(__FILE__)

  # Set up defaults, can be overridden with command line parameters.
  def initialize
    @opts = {
      :env             =&gt; 'cucumber',
      :geometry        =&gt; '1280x800',
      :display         =&gt; ENV['DISPLAY'],
      :xnest_display   =&gt; ':2',
      :control_webrick =&gt; true,
      :try_use_xnest   =&gt; true
    }
  end

  # Determine if Xnest is present, and if it should be used (Not on OS X).
  def use_xnest?
    return false unless @opts[:try_use_xnest]
    on_darwin = (`uname` =~ /Darwin/)
    has_xnest = !(`which Xnest`.empty?)
    !on_darwin &amp;&amp; has_xnest
  end

  # Start Xnest in the background, save off the pid so it can be stopped later.
  def start_xnest
    @opts[:display] = @opts[:xnest_display]
    cmd = "Xnest #{@opts[:xnest_display]} &amp; echo $!"
    @xnest_pid = `#{cmd}`.to_i
  end

  # Stop Xnest with a SIGTERM.
  def stop_xnest
    Process.kill("TERM", @xnest_pid) if @xnest_pid
  end

  # Stop the WEBRick server by looking for it in the process tree.
  def stop_webrick
    res = `ps aux | grep [r]uby | grep [s]cript/server`
    pid = res.split[1]
    return unless pid
    puts "#{$0} STOPPING WEBRick pid=#{pid}"
    Process.kill "KILL", pid.to_i
  end

  # Start WEBRick with the configured rails environment as a daemon (background).
  def start_webrick
    cmd = "#{SCRIPT_ROOT}/server -e #{@opts[:env]} -d"
    puts "#{$0} Starting WEBRick: #{cmd}"
    system cmd
  end

  # Process any command line arguments.
  def parse_opts
    OptionParser.new do |opts|
      opts.banner = "Usage: #{$0} [options]"

      opts.on("-h", "--help") do
        puts &lt;&lt;-EOH
       #{$0} [[opts]]

        -e ENV  --envrionment ENV   Rails environment to run under default=#{@opts[:env]}
        -g GEO  --geometry GEO      Xnest geometry to use default=#{@opts[:geometry]}
        -X      --no-xnest          Do not use Xnest (even if present)
        -d DSP  --display DSP       DISPLAY to use default=#{@opts[:display]}
        -x DSP  --xnest-display DSP Xnest's DISPLAY to use default=#{@opts[:xnest_display]}
        -W      --no-webrick        Don't start WEBRick (assume running) default=false
        EOH
        exit 0
      end

      opts.on("-e", "--envrionment ENV") do |env|
        @opts[:env] = env
      end

      opts.on("-g", "--geometry GEO") do |geo|
        @opts[:geometry] = geo
      end

      opts.on("-X", "--no-xnest") do
        options[:use_xnest] = false
      end

      opts.on("-d", "--display DSP") do |dsp|
        options[:display] = dsp
      end

      opts.on("-x", "--xnest-display DISP") do |disp|
        options[:xnest_display] = disp
      end

      opts.on("-W", "--no-webrick") do
        options[:control_webrick] = false
      end
    end.parse!
  end

  # Process options, start Xnest, [re]start WEBRick, execute the cucumber
  # suite, then stop Xnest and stop WEBrick
  def run
    parse_opts
    start_xnest if use_xnest?

    if @opts[:control_webrick]
      stop_webrick
      start_webrick
    end

    cmd = "#{SCRIPT_ROOT}/runner #{SCRIPT_ROOT}/cucumber #{ARGV}"
    ENV['DISPLAY']   = @opts[:display]
    ENV['RAILS_ENV'] = @opts[:env]
    puts "#{$0} using RAILS_ENV=#{ENV['RAILS_ENV']}"
    res = system cmd

  ensure
    stop_webrick  if @opts[:control_webrick]
    stop_xnest    if @xnest_pid
  end

  def self.main
    self.new.run
  end
end

CucumberRunner.main
</pre>
<p>You can download or check out <a href="http://github.com/kyleburton/cucumber-example/blob/master/cukeex/script/cucumber-runner">cucumber-runner</a> from my github <a href="http://github.com/kyleburton/cucumber-example/">cucumber-example project</a>.</p>
<p>Running Cucumber with this wrapper helps make it easier and less intrusive to use.  If anyone has suggestions for how to make it less intrusive while running under OS X, please <a href="mailto:kyle.burton@gmail.com">email me</a>, I&#8217;d love to hear your suggestions.</p>
<p class="meta">Kyle Burton, 10 Jun 2010 &#8211; Philadelphia PA</p>
<p><br /></p>]]></content:encoded>
    </item>
    
    <item>
      <title>Creating Standalone Java Applications with Leiningen</title>
      <link>http://blog.asymmetrical-view.com/2010/06/08/building-standalone-jars-wtih-leiningen.html</link>
      <comments>http://blog.asymmetrical-view.com/2010/06/08/building-standalone-jars-wtih-leiningen.html#comments</comments>

      <pubDate>2010-06-08T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2010/06/08/building-standalone-jars-wtih-leiningen.html</guid>

      <id>http://blog.asymmetrical-view.com/2010/06/08/building-standalone-jars-wtih-leiningen</id>
      <description><![CDATA[<h1>Creating Standalone Java Applications with Leiningen</h1>
<p><a href="http://github.com/technomancy/leiningen">Leiningen</a> is a simpler build tool for <a href="http://clojure.org/">Clojure</a>.  <a href="/2010/06/03/leiningen.html">Previously</a> I covered a few basic aspects including how to run the <span class="caps">HEAD</span> version of Leiningen.  Leiningen can also build a standalone jars in the same way the <a href="http://maven.apache.org/plugins/maven-assembly-plugin/">maven assembly plug-in</a> does.  There are a few steps you need to follow, I&#8217;ll walk you through them here.  This example is available in my <a href="http://github.com/kyleburton/sandbox/tree/master/examples/clojure/leiningen/cljcsv/">sandbox</a>.</p>
<h2><code>project.clj</code></h2>
<p>For the example, I started by creating a new project (for testing a <a href="http://github.com/davidsantiago/clojure-csv">csv parsing library</a>) by running <code>lein new cljcsv</code>.  I added <code>clojure-csv</code> as a dependency, set <code>cljcsv.core</code> to be compiled, by specifying the name-space with the <code>:aot</code> parameter and specified <code>cljcsv.core</code> to be the main class invoked for the jar file by specifying it with <code>:main</code>.</p>
<pre class="code">
(defproject cljcsv "1.0.0-SNAPSHOT"
  :description "CSV Example."
  :dependencies
    [[org.clojure/clojure "1.1.0"]
     [org.clojure/clojure-contrib "1.1.0"]
     [clojure-csv/clojure-csv "1.0.0"]]
  :aot  [cljcsv.core]
  :main cljcsv.core)
</pre>
<h2><code>src/cljcsv/core.clj</code></h2>
<p>To have a Clojure program produce a class file with a <code>main</code> function, you need to ensure you have <code>:gen-class</code> specified in the name-space for your program and that you define a <code>-main</code> function to act as the main.</p>
<pre class="code">
(ns cljcsv.core
  (:require [com.davidsantiago.csv :as cdc]
            [clojure.contrib.pprint :as pp])
  (:gen-class))

(defn parse-cdc [file]
 (let [rs (cdc/parse-csv (slurp file))]
  (prn (str "rs=" rs))
  (prn (pp/cl-format nil "cdc: rows: ~a~&amp;" (count rs)))
  (prn (pp/cl-format nil "cdc: ~a~&amp;" rs))))

(defn -main [&amp; args]
  (prn (format "args=%s" args))
  (if (not (empty? args))
    (do
      (parse-cdc (first args)))))

</pre>
<p>Then to build and run the jar:</p>
<pre class="code">
$ lein compile
$ lein uberjar
$ java -jar cljcsv-standalone.jar input.csv
</pre>
<p>Leiningen makes creating and building Clojure projects quick and easy.  It makes creating an executable jar for your project, which may have many dependencies, about as easy as you can get.</p>
<p class="meta">Kyle Burton, 08 Jun 2010 &#8211; Philadelphia PA</p>
<h5>Special Thanks</h5>
<p>Special thanks to <a href="http://technomancy.us/">technomancy</a>, for creating Leiningen.</p>
<p><br /></p>]]></description>
      <content:encoded><![CDATA[<h1>Creating Standalone Java Applications with Leiningen</h1>
<p><a href="http://github.com/technomancy/leiningen">Leiningen</a> is a simpler build tool for <a href="http://clojure.org/">Clojure</a>.  <a href="/2010/06/03/leiningen.html">Previously</a> I covered a few basic aspects including how to run the <span class="caps">HEAD</span> version of Leiningen.  Leiningen can also build a standalone jars in the same way the <a href="http://maven.apache.org/plugins/maven-assembly-plugin/">maven assembly plug-in</a> does.  There are a few steps you need to follow, I&#8217;ll walk you through them here.  This example is available in my <a href="http://github.com/kyleburton/sandbox/tree/master/examples/clojure/leiningen/cljcsv/">sandbox</a>.</p>
<h2><code>project.clj</code></h2>
<p>For the example, I started by creating a new project (for testing a <a href="http://github.com/davidsantiago/clojure-csv">csv parsing library</a>) by running <code>lein new cljcsv</code>.  I added <code>clojure-csv</code> as a dependency, set <code>cljcsv.core</code> to be compiled, by specifying the name-space with the <code>:aot</code> parameter and specified <code>cljcsv.core</code> to be the main class invoked for the jar file by specifying it with <code>:main</code>.</p>
<pre class="code">
(defproject cljcsv "1.0.0-SNAPSHOT"
  :description "CSV Example."
  :dependencies
    [[org.clojure/clojure "1.1.0"]
     [org.clojure/clojure-contrib "1.1.0"]
     [clojure-csv/clojure-csv "1.0.0"]]
  :aot  [cljcsv.core]
  :main cljcsv.core)
</pre>
<h2><code>src/cljcsv/core.clj</code></h2>
<p>To have a Clojure program produce a class file with a <code>main</code> function, you need to ensure you have <code>:gen-class</code> specified in the name-space for your program and that you define a <code>-main</code> function to act as the main.</p>
<pre class="code">
(ns cljcsv.core
  (:require [com.davidsantiago.csv :as cdc]
            [clojure.contrib.pprint :as pp])
  (:gen-class))

(defn parse-cdc [file]
 (let [rs (cdc/parse-csv (slurp file))]
  (prn (str "rs=" rs))
  (prn (pp/cl-format nil "cdc: rows: ~a~&amp;" (count rs)))
  (prn (pp/cl-format nil "cdc: ~a~&amp;" rs))))

(defn -main [&amp; args]
  (prn (format "args=%s" args))
  (if (not (empty? args))
    (do
      (parse-cdc (first args)))))

</pre>
<p>Then to build and run the jar:</p>
<pre class="code">
$ lein compile
$ lein uberjar
$ java -jar cljcsv-standalone.jar input.csv
</pre>
<p>Leiningen makes creating and building Clojure projects quick and easy.  It makes creating an executable jar for your project, which may have many dependencies, about as easy as you can get.</p>
<p class="meta">Kyle Burton, 08 Jun 2010 &#8211; Philadelphia PA</p>
<h5>Special Thanks</h5>
<p>Special thanks to <a href="http://technomancy.us/">technomancy</a>, for creating Leiningen.</p>
<p><br /></p>]]></content:encoded>
    </item>
    
    <item>
      <title>Leiningen</title>
      <link>http://blog.asymmetrical-view.com/2010/06/03/leiningen.html</link>
      <comments>http://blog.asymmetrical-view.com/2010/06/03/leiningen.html#comments</comments>

      <pubDate>2010-06-03T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2010/06/03/leiningen.html</guid>

      <id>http://blog.asymmetrical-view.com/2010/06/03/leiningen</id>
      <description><![CDATA[<h1>Leiningen</h1>
<p><a href="http://github.com/technomancy/leiningen">Leiningen</a> is a simpler build tool for <a href="http://clojure.org/">Clojure</a>.  It is easier to get started with than <a href="http://maven.apache.org/">Maven</a> (though you <a href="http://asymmetrical-view.com/2009/06/22/executable-clojure-jars.html">can do it</a>, as <a href="http://alexott.net/en/clojure/ClojureMaven.html">more than one</a> <a href="http://muckandbrass.com/web/display/~cemerick/2010/03/25/Why+using+Maven+for+Clojure+builds+is+a+no-brainer">post shows</a>), as well as <a href="http://ant.apache.org/">ant</a>.</p>
<p>Leiningen is, as maven is, rooted in convention over configuration to reduce the complexity of its build configuration.  Leiningen expects your Clojure source code to be in <code>&lt;project&gt;/src</code> and your tests to be in <code>&lt;project&gt;/test</code>.  These can be overridden with <code>:source-path</code> and <code>:test-path</code> respectively.</p>
<p>You create a <code>project.clj</code> in your project&#8217;s root directory to control how Leiningen builds your project.  Leiningen manages your dependencies in a brief syntax using the same dependency resolution system as maven, and it integrates with <a href="http://clojars.org/">Clojars</a>, a jar repository for Clojure projects (which is also a maven repository), both for pulling dependencies as well as allowing you to upload your own open source projects to the remote repository.</p>
<p>There is a full walk through for installing and getting started with Leiningen that is part of the <a href="http://github.com/technomancy/leiningen">Leiningen documentation</a>, so I am going to focus on what I found useful that isn&#8217;t already part of that guide and only show the basics of getting started &#8211; you should refer to <a href="http://github.com/technomancy/leiningen">that page</a> (or the <a href="http://groups.google.com/group/leiningen">google group</a>) for more information.</p>
<h2>Dependency Version Strings</h2>
<p>For those of you who have never used Maven, it is worth reading about <a href="http://github.com/technomancy/leiningen/blob/master/INTRO.md">maven version strings</a> to familiarize yourself with how they work and the effect that something like <code>SNAPSHOT</code> in the version string will have on your build.</p>
<h2><code>:warn-on-reflection</code></h2>
<p><code>:warn-on-reflection</code> is used to set the Clojure compiler option for warning on reflection.  This will point out where adding in Clojure (make this a link) type declarations will help speed up your code.</p>
<h2><code>:dependencies</code></h2>
<p><code>:dependencies</code> specifies a list of pairs of project and version string of the libraries you depend on.</p>
<h2><code>:dev-dependencies</code></h2>
<p><code>:dev-dependencies</code> is similar to <code>:dependencies</code>, but the dependencies are not considered to be run-time dependencies, they are only for use by Leiningen during the build.  The one I most commonly use is <code>swank-clojure</code>.</p>
<h2>Example project.clj</h2>
<p>This example is from the <a href="http://github.com/kyleburton/clj-bloom">clj-bloom</a> library</p>
<pre class="code">
(defproject com.github.kyleburton/clj-bloom "1.0.1"
  :description "Bloom Filter implementation in Clojure, see also: http://github.com/kyleburton/clj-bloom"
  :warn-on-reflection true
  :dependencies
  [[org.clojure/clojure "1.1.0"]
   [org.clojure/clojure-contrib "1.1.0"]]
  :dev-dependencies
  [[swank-clojure "1.2.1"]])
</pre>
<h2>Common Leiningen Commands</h2>
<h3><code>lein deps</code></h3>
<p>Prior to version 1.2 of Leiningen, it did not have a build life cycle.  With 1.2 it does, this means that it understands that <code>test</code> depends on <code>compile</code>, similar to how <a href="http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html">maven&#8217;s life-cycle works</a>.  If you&#8217;re using a version older than 1.2 and you get a message like: <code>"Exception in thread "main" java.lang.NoClassDefFoundError: clojure/main"</code> it is dues to the dependencies not yet having been pulled down.</p>
<p>This most often happened to me right after a <code>lein clean</code>.  Thankfully Leiningen uses the same caching strategy that Maven does so the second time you run <code>lein deps</code> it will be much quicker as all it needs to do is pull the dependencies from your <code>~/.m2/repository</code> directory.  Currently it copies the file, in the future my hope is that it will use a <a href="http://java.sun.com/docs/books/tutorial/essential/io/links.html#symLink">symlink</a>, which will be supported by <a href="http://java.sun.com/developer/technicalArticles/javase/nio/">Java7</a>.</p>
<h3><code>lein test</code></h3>
<p>You can run your <a href="http://richhickey.github.com/clojure/clojure.test-api.html"><code>clojure.test</code></a> based tests with <code>lein test</code>:</p>
<pre class="code">
kyle@indigo64 ~/personal/projects/clj-bloom[master]$ lein test
[null] Testing com.github.kyleburton.clj-bloom-test
[null] Ran 5 tests containing 21 assertions.
[null] 0 failures, 0 errors.
[null] --------------------
[null] Total:
[null] Ran 5 tests containing 21 assertions.
[null] 0 failures, 0 errors.
kyle@indigo64 ~/personal/projects/clj-bloom[master]$ echo $?
0
kyle@indigo64 ~/personal/projects/clj-bloom[master]$
</pre>
<p>As the example shows, a drawback of the pre 1.2 versions of Leiningen is that they do not set the exit code of the process on test or compilation failure to a non-zero value.  This makes those versions difficult to use from other software (like deployment or <a href="http://hudson-ci.org/">continuous integration tools</a>.</p>
<p>Thankfully this is one of the fixes in the 1.2 branch, among <a href="http://github.com/technomancy/leiningen/blob/master/NEWS">many others</a>.  You can run the 1.2 branch, or the <span class="caps">HEAD</span> pretty easily by first having a working stable release of Leiningen, building it and then either symlinking or aliasing <code>lein</code> to point to the checked out copy:</p>
<pre class="code">
kyle@indigo64 ~/personal/projects$ git clone http://github.com/technomancy/leiningen.git
kyle@indigo64 ~/personal/projects$ cd leiningen
kyle@indigo64 ~/personal/projects/leiningen[master]$ lein deps
kyle@indigo64 ~/personal/projects/leiningen[master]$ lein compile
kyle@indigo64 ~/personal/projects/leiningen[master]$ alias lein=~/personal/projects/leiningen/bin/lein
kyle@indigo64 ~/personal/projects/leiningen[master]$
</pre>
<p>After doing that, going back into the project directory, now <code>lein test</code> sets the exit code:</p>
<pre class="code">
kyle@indigo64 ~/personal/projects/clj-bloom[master]$ lein test
     [null] Testing com.github.kyleburton.clj-bloom-test
     [null] FAIL in (make-hash-fn-hash-code-test) (clj_bloom_test.clj:9)
     [null] test the hash-fn helper
     [null] expected: (not (= (.hashCode "foo1") ((bf/make-hash-fn-hash-code "1") "foo" 4294967295)))
     [null]   actual: (not (not true))
     [null] Ran 5 tests containing 21 assertions.
     [null] 1 failures, 0 errors.
     [null] --------------------
     [null] Total:
     [null] Ran 5 tests containing 21 assertions.
     [null] 1 failures, 0 errors.
kyle@indigo64 ~/personal/projects/clj-bloom[master]$ echo $?
1
kyle@indigo64 ~/personal/projects/clj-bloom[master]$
</pre>
<h2>Emacs + <span class="caps">SLIME</span> Integration</h2>
<p><img src="/images/2009-08/emacs-swank-clojure-1.png" style="float: right; padding: 1em;" /></p>
<p>Leiningen eases the integration with <a href="http://www.gnu.org/software/emacs/">Emacs</a> and <a href="http://common-lisp.net/project/slime/"><span class="caps">SLIME</span></a>.  <span class="caps">SLIME</span> provides a rich development environment for Clojure.  I&#8217;ve written previously about <span class="caps">SLIME</span> and Clojure (<a href="/2009/08/20/emacs-slime-remote-repl.html">Connecting to a remote <span class="caps">REPL</span></a>).  Leiningen provides the ability to run a swank server with the <a href="http://github.com/jochu/swank-clojure/blob/master/src/leiningen/swank.clj">lein-swank</a> plug-in which is part of <a href="http://github.com/jochu/swank-clojure">swank-clojure</a>.</p>
<p>See <a href="http://freegeek.in/blog/2009/08/setting-up-emacs-clojure-with-emacs-starter-kit/">Setting up Emacs &amp; Clojure with Emacs Starter Kit</a> or <a href="http://clojurous.posterous.com/setting-up-clojure-with-emacs-and-leiningen">Setting up Clojure with Emacs and Leiningen</a> for how to get Emacs configured for Clojure development.</p>
<p>The swank server is the back-end portion of <span class="caps">SLIME</span>.  It listens to a socket in the <span class="caps">JVM</span> where your Clojure code is running and allows Emacs to connect to and interact with it, compiling and executing code, inspecting values and providing services like code completion and documentation look-up.</p>
<p>The example <code>project.clj</code> above shows how to reference <code>swank-clojure</code> as a dev-dependency.</p>
<p>You can start a swank server for your project, with all your project&#8217;s dependencies by running:</p>
<pre class="code">
kyle@indigo64 ~/personal/projects/clj-bloom[master]$ lein swank
     [null] user=&gt; Connection opened on local port  4005
     [null] #&lt;ServerSocket ServerSocket[addr=localhost/127.0.0.1,port=0,localport=4005]&gt;
</pre>
<p>Then from Emacs, execute <code>M-x slime-connect</code> and accept the defaults (localhost and a port of 4005).</p>
<p>That runs the swank sever on the default port, 4005.  If you want to be able to run multiple swank servers on different ports (perhaps you&#8217;re working with multiple projects), just pass the additional arguments to the lein-swank plug-in, which are the port then the host (if your machine is known by more than one name or has more than one interface):</p>
<pre class="code">
kyle@indigo64 ~/personal/projects/clj-bloom[master]$ lein swank 4006
     [null] user=&gt; Connection opened on local port  4006
     [null] #&lt;ServerSocket ServerSocket[addr=localhost/127.0.0.1,port=0,localport=4006]&gt;
</pre>
<p>I&#8217;ve found Leiningen to be a simple, easy to use alternative to using Ant or Maven for building your code.</p>
<p class="meta">Kyle Burton, 03 Jun 2010 &#8211; Philadelphia PA</p>
<h5>Special Thanks</h5>
<p>Special thanks to <a href="http://technomancy.us/">technomancy</a>, for creating Leiningen.</p>
<p><br /></p>]]></description>
      <content:encoded><![CDATA[<h1>Leiningen</h1>
<p><a href="http://github.com/technomancy/leiningen">Leiningen</a> is a simpler build tool for <a href="http://clojure.org/">Clojure</a>.  It is easier to get started with than <a href="http://maven.apache.org/">Maven</a> (though you <a href="http://asymmetrical-view.com/2009/06/22/executable-clojure-jars.html">can do it</a>, as <a href="http://alexott.net/en/clojure/ClojureMaven.html">more than one</a> <a href="http://muckandbrass.com/web/display/~cemerick/2010/03/25/Why+using+Maven+for+Clojure+builds+is+a+no-brainer">post shows</a>), as well as <a href="http://ant.apache.org/">ant</a>.</p>
<p>Leiningen is, as maven is, rooted in convention over configuration to reduce the complexity of its build configuration.  Leiningen expects your Clojure source code to be in <code>&lt;project&gt;/src</code> and your tests to be in <code>&lt;project&gt;/test</code>.  These can be overridden with <code>:source-path</code> and <code>:test-path</code> respectively.</p>
<p>You create a <code>project.clj</code> in your project&#8217;s root directory to control how Leiningen builds your project.  Leiningen manages your dependencies in a brief syntax using the same dependency resolution system as maven, and it integrates with <a href="http://clojars.org/">Clojars</a>, a jar repository for Clojure projects (which is also a maven repository), both for pulling dependencies as well as allowing you to upload your own open source projects to the remote repository.</p>
<p>There is a full walk through for installing and getting started with Leiningen that is part of the <a href="http://github.com/technomancy/leiningen">Leiningen documentation</a>, so I am going to focus on what I found useful that isn&#8217;t already part of that guide and only show the basics of getting started &#8211; you should refer to <a href="http://github.com/technomancy/leiningen">that page</a> (or the <a href="http://groups.google.com/group/leiningen">google group</a>) for more information.</p>
<h2>Dependency Version Strings</h2>
<p>For those of you who have never used Maven, it is worth reading about <a href="http://github.com/technomancy/leiningen/blob/master/INTRO.md">maven version strings</a> to familiarize yourself with how they work and the effect that something like <code>SNAPSHOT</code> in the version string will have on your build.</p>
<h2><code>:warn-on-reflection</code></h2>
<p><code>:warn-on-reflection</code> is used to set the Clojure compiler option for warning on reflection.  This will point out where adding in Clojure (make this a link) type declarations will help speed up your code.</p>
<h2><code>:dependencies</code></h2>
<p><code>:dependencies</code> specifies a list of pairs of project and version string of the libraries you depend on.</p>
<h2><code>:dev-dependencies</code></h2>
<p><code>:dev-dependencies</code> is similar to <code>:dependencies</code>, but the dependencies are not considered to be run-time dependencies, they are only for use by Leiningen during the build.  The one I most commonly use is <code>swank-clojure</code>.</p>
<h2>Example project.clj</h2>
<p>This example is from the <a href="http://github.com/kyleburton/clj-bloom">clj-bloom</a> library</p>
<pre class="code">
(defproject com.github.kyleburton/clj-bloom "1.0.1"
  :description "Bloom Filter implementation in Clojure, see also: http://github.com/kyleburton/clj-bloom"
  :warn-on-reflection true
  :dependencies
  [[org.clojure/clojure "1.1.0"]
   [org.clojure/clojure-contrib "1.1.0"]]
  :dev-dependencies
  [[swank-clojure "1.2.1"]])
</pre>
<h2>Common Leiningen Commands</h2>
<h3><code>lein deps</code></h3>
<p>Prior to version 1.2 of Leiningen, it did not have a build life cycle.  With 1.2 it does, this means that it understands that <code>test</code> depends on <code>compile</code>, similar to how <a href="http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html">maven&#8217;s life-cycle works</a>.  If you&#8217;re using a version older than 1.2 and you get a message like: <code>"Exception in thread "main" java.lang.NoClassDefFoundError: clojure/main"</code> it is dues to the dependencies not yet having been pulled down.</p>
<p>This most often happened to me right after a <code>lein clean</code>.  Thankfully Leiningen uses the same caching strategy that Maven does so the second time you run <code>lein deps</code> it will be much quicker as all it needs to do is pull the dependencies from your <code>~/.m2/repository</code> directory.  Currently it copies the file, in the future my hope is that it will use a <a href="http://java.sun.com/docs/books/tutorial/essential/io/links.html#symLink">symlink</a>, which will be supported by <a href="http://java.sun.com/developer/technicalArticles/javase/nio/">Java7</a>.</p>
<h3><code>lein test</code></h3>
<p>You can run your <a href="http://richhickey.github.com/clojure/clojure.test-api.html"><code>clojure.test</code></a> based tests with <code>lein test</code>:</p>
<pre class="code">
kyle@indigo64 ~/personal/projects/clj-bloom[master]$ lein test
[null] Testing com.github.kyleburton.clj-bloom-test
[null] Ran 5 tests containing 21 assertions.
[null] 0 failures, 0 errors.
[null] --------------------
[null] Total:
[null] Ran 5 tests containing 21 assertions.
[null] 0 failures, 0 errors.
kyle@indigo64 ~/personal/projects/clj-bloom[master]$ echo $?
0
kyle@indigo64 ~/personal/projects/clj-bloom[master]$
</pre>
<p>As the example shows, a drawback of the pre 1.2 versions of Leiningen is that they do not set the exit code of the process on test or compilation failure to a non-zero value.  This makes those versions difficult to use from other software (like deployment or <a href="http://hudson-ci.org/">continuous integration tools</a>.</p>
<p>Thankfully this is one of the fixes in the 1.2 branch, among <a href="http://github.com/technomancy/leiningen/blob/master/NEWS">many others</a>.  You can run the 1.2 branch, or the <span class="caps">HEAD</span> pretty easily by first having a working stable release of Leiningen, building it and then either symlinking or aliasing <code>lein</code> to point to the checked out copy:</p>
<pre class="code">
kyle@indigo64 ~/personal/projects$ git clone http://github.com/technomancy/leiningen.git
kyle@indigo64 ~/personal/projects$ cd leiningen
kyle@indigo64 ~/personal/projects/leiningen[master]$ lein deps
kyle@indigo64 ~/personal/projects/leiningen[master]$ lein compile
kyle@indigo64 ~/personal/projects/leiningen[master]$ alias lein=~/personal/projects/leiningen/bin/lein
kyle@indigo64 ~/personal/projects/leiningen[master]$
</pre>
<p>After doing that, going back into the project directory, now <code>lein test</code> sets the exit code:</p>
<pre class="code">
kyle@indigo64 ~/personal/projects/clj-bloom[master]$ lein test
     [null] Testing com.github.kyleburton.clj-bloom-test
     [null] FAIL in (make-hash-fn-hash-code-test) (clj_bloom_test.clj:9)
     [null] test the hash-fn helper
     [null] expected: (not (= (.hashCode "foo1") ((bf/make-hash-fn-hash-code "1") "foo" 4294967295)))
     [null]   actual: (not (not true))
     [null] Ran 5 tests containing 21 assertions.
     [null] 1 failures, 0 errors.
     [null] --------------------
     [null] Total:
     [null] Ran 5 tests containing 21 assertions.
     [null] 1 failures, 0 errors.
kyle@indigo64 ~/personal/projects/clj-bloom[master]$ echo $?
1
kyle@indigo64 ~/personal/projects/clj-bloom[master]$
</pre>
<h2>Emacs + <span class="caps">SLIME</span> Integration</h2>
<p><img src="/images/2009-08/emacs-swank-clojure-1.png" style="float: right; padding: 1em;" /></p>
<p>Leiningen eases the integration with <a href="http://www.gnu.org/software/emacs/">Emacs</a> and <a href="http://common-lisp.net/project/slime/"><span class="caps">SLIME</span></a>.  <span class="caps">SLIME</span> provides a rich development environment for Clojure.  I&#8217;ve written previously about <span class="caps">SLIME</span> and Clojure (<a href="/2009/08/20/emacs-slime-remote-repl.html">Connecting to a remote <span class="caps">REPL</span></a>).  Leiningen provides the ability to run a swank server with the <a href="http://github.com/jochu/swank-clojure/blob/master/src/leiningen/swank.clj">lein-swank</a> plug-in which is part of <a href="http://github.com/jochu/swank-clojure">swank-clojure</a>.</p>
<p>See <a href="http://freegeek.in/blog/2009/08/setting-up-emacs-clojure-with-emacs-starter-kit/">Setting up Emacs &amp; Clojure with Emacs Starter Kit</a> or <a href="http://clojurous.posterous.com/setting-up-clojure-with-emacs-and-leiningen">Setting up Clojure with Emacs and Leiningen</a> for how to get Emacs configured for Clojure development.</p>
<p>The swank server is the back-end portion of <span class="caps">SLIME</span>.  It listens to a socket in the <span class="caps">JVM</span> where your Clojure code is running and allows Emacs to connect to and interact with it, compiling and executing code, inspecting values and providing services like code completion and documentation look-up.</p>
<p>The example <code>project.clj</code> above shows how to reference <code>swank-clojure</code> as a dev-dependency.</p>
<p>You can start a swank server for your project, with all your project&#8217;s dependencies by running:</p>
<pre class="code">
kyle@indigo64 ~/personal/projects/clj-bloom[master]$ lein swank
     [null] user=&gt; Connection opened on local port  4005
     [null] #&lt;ServerSocket ServerSocket[addr=localhost/127.0.0.1,port=0,localport=4005]&gt;
</pre>
<p>Then from Emacs, execute <code>M-x slime-connect</code> and accept the defaults (localhost and a port of 4005).</p>
<p>That runs the swank sever on the default port, 4005.  If you want to be able to run multiple swank servers on different ports (perhaps you&#8217;re working with multiple projects), just pass the additional arguments to the lein-swank plug-in, which are the port then the host (if your machine is known by more than one name or has more than one interface):</p>
<pre class="code">
kyle@indigo64 ~/personal/projects/clj-bloom[master]$ lein swank 4006
     [null] user=&gt; Connection opened on local port  4006
     [null] #&lt;ServerSocket ServerSocket[addr=localhost/127.0.0.1,port=0,localport=4006]&gt;
</pre>
<p>I&#8217;ve found Leiningen to be a simple, easy to use alternative to using Ant or Maven for building your code.</p>
<p class="meta">Kyle Burton, 03 Jun 2010 &#8211; Philadelphia PA</p>
<h5>Special Thanks</h5>
<p>Special thanks to <a href="http://technomancy.us/">technomancy</a>, for creating Leiningen.</p>
<p><br /></p>]]></content:encoded>
    </item>
    
    <item>
      <title>From the Agony of JUnit to the Ecstasy of RSpec</title>
      <link>http://blog.asymmetrical-view.com/2010/02/19/maven-rspec.html</link>
      <comments>http://blog.asymmetrical-view.com/2010/02/19/maven-rspec.html#comments</comments>

      <pubDate>2010-02-19T00:00:00-05:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2010/02/19/maven-rspec.html</guid>

      <id>http://blog.asymmetrical-view.com/2010/02/19/maven-rspec</id>
      <description><![CDATA[<h1>From the Agony of JUnit to the Ecstasy of RSpec</h1>
<p><img src="/images/2010-02/boxer.gif" style="float: left; padding: 1em; " /></p>
<p>In the past I have had a love hate relationship with unit testing and testing tools in general.  I have had a long, healthy, even dreamy relationship with test driven development though.  Aahh how it improves design and prevents issues from reaching users!</p>
<p><img src="/images/2010-02/Gun-223x150.jpg" style="float: right; padding: 1em; " /></p>
<p>I am often unhappy with the amount of effort it takes to write tests using some of the tools and libraries out there.  I&#8217;ve been around the block from Perl to Lisp to Java, even C++ and C (I found using <a href="http://www.call-with-current-continuation.org/">Chicken</a> to be an easy way to write tests for C libraries, but I digress&#8230;)  I have found, both with myself and with teams I&#8217;ve worked with, that if the effort of writing tests is high enough, less (or no) tests will be written.  This is partly because test themselves do not represent business value or end-user features, so most things you can do to reduce the effort of writing or running tests will cause more tests to be written.  This includes not just the boilerplate set up and typing you have to do, but the amount of time it takes to run your tests (long running tests unfortunately re-introduce the flow destroying edit-compile-debug cycle back into modern dynamic application development).  Reducing effort is, of course, dependent on <span class="caps">ROI</span>, which is different for each person and team.</p>
<p>A good friend of mine, <a href="http://plpatterns.com/">Jon Tran</a>, pushes the idea that if you can make something abundant (nearly free) you haven&#8217;t just made something better, you&#8217;ve made something entirely different.  I love this idea and try to use it to guide process and tool improvements for myself and my team.</p>
<p><img src="/images/2010-02/BouncingDuke-small.gif" style="float: left; padding: 1em; " /></p>
<p>When I started working with <a href="http://rubyonrails.org/">Ruby on Rails</a> I found testing to be so well integrated into how you worked on your Rails project that it was, in fact, abundant.  It was so much easier to test your code that writing tests was no longer a chore, but it fit easily, even joyfully into the work-flow.  Working more recently with a Rails expert, <a href="http://trottercashion.com/">Trotter Cashion</a>, I was introduced to <a href="http://rspec.info/">RSpec</a>.  Our team was also blessed one fine day by a visit from <a href="http://apprentice.kfitz.me/">Kevin Fitzpatrick</a> who bootstrapped our use of <a href="http://cukes.info/">Cucumber</a> in a single afternoon pairing session.</p>
<p>These two tools were pure love.  They gave me the same kind of feelings that declarative and functional programming give me &#8211; you say what you want it to be, not just how you want it to get there.  RSpec made unit testing even more abundant, Cucumber made front end or integration testing abundant.  Those two tools went a long way to helping our team write more tests and more effective tests, improving the design of our code, applications and ultimately reducing the number of issues (especially regressions) that made it both to and past our excellent QA testers (we&#8217;re only human after all).</p>
<p>Writing unit tests for the Java portions of our systems I have really started to miss the clarity and abundance that RSpec provided.  Then I stumbled across the <a href="http://www.fnokd.com/2008/09/18/maven-java-and-rspec/">maven-rspec-plugin</a> which uses JRuby to execute rspec base tests during the test phase of the maven life cycle.</p>
<p>The storm clouds have parted and the sun is shining again.  This is exactly what I was looking for; I just hadn&#8217;t known it until I found it.</p>
<div><img src="/images/2010-02/testing-venn.png" style="padding: 1em; " /></div>
<p>We&#8217;re already using <a href="http://jruby.org/">JRuby</a> within the project and have been happy with the access to all of the <span class="caps">JVM</span> based libraries it provides to us (not to mention easy integration with our <a href="http://clojure.org/">Clojure</a> code, but that&#8217;s another post altogether).  The tools are a great fit for our team, we&#8217;re already familiar with Ruby, RSpec and writing those kinds of tests &#8211; just not yet in our Java portions of the application.</p>
<p>On your mark, get set&#8230;I followed the instructions in that post, but ended up with a NullPointerException when the plugin tried to write out the runner shell script.  I checked out the code from the CodeHaus svn repository and poked around until I found a work around, it seems that the plugin requires a <code>systemProperties</code> tag in its configuration, even if it&#8217;s not used, to prevent the <code>NPE</code>.  It just has to be present with at least one property present.</p>
<p><a href="http://www.innovationontherun.com/">Rob DiMarco</a> discovered that the plugin, rspec or something about this confluence of tools and libraries doesn&#8217;t work on JRuby 1.4 (see <a href="http://github.com/kyleburton/sandbox/issues/#issue/1">the stacktrace</a> for more information), so make sure you download and install JRuby 1.3.1 for now.</p>
<p>To get started you&#8217;ll need <a href="http://jruby.org/download">JRuby</a> installed, make sure you get <a href="http://jruby.kenai.com/downloads/1.3.1/jruby-bin-1.3.1.tar.gz">1.3.1</a> and you&#8217;ll have to set the <code>JRUBY_HOME</code> environment variable to point to your installation.  You&#8217;ll need <a href="http://maven.apache.org/">maven</a> of course as well.</p>
<p>The plugin configuration we were able to get working is the <code>pom.xml</code> fragment you see here:</p>
<pre class="code">
   &lt;plugin&gt;
     &lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;
     &lt;artifactId&gt;rspec-maven-plugin&lt;/artifactId&gt;
     &lt;configuration&gt;
       &lt;jrubyHome&gt;${env.JRUBY_HOME}&lt;/jrubyHome&gt;
       &lt;sourceDirectory&gt;${basedir}/src/test/specs&lt;/sourceDirectory&gt;
       &lt;outputDirectory&gt;${basedir}/target&lt;/outputDirectory&gt;
       &lt;systemProperties&gt;
         &lt;property&gt;&lt;name&gt;testProp&lt;/name&gt;&lt;value&gt;testValue&lt;/value&gt;&lt;/property&gt;
       &lt;/systemProperties&gt;
     &lt;/configuration&gt;
     &lt;executions&gt;
       &lt;execution&gt;
         &lt;id&gt;test&lt;/id&gt;
         &lt;phase&gt;test&lt;/phase&gt;
         &lt;goals&gt;
           &lt;goal&gt;spec&lt;/goal&gt;
         &lt;/goals&gt;
       &lt;/execution&gt;
     &lt;/executions&gt;
   &lt;/plugin&gt;
</pre>
<p><img src="/images/2010-02/Juggler-268x310.gif" style="float: right; padding: 1em; " /></p>
<p>This configures rspec to be run during the test phase of the maven build.  It also configures the plugin to look for spec tests within the src/test/specs directory.  When first executed, the plugin will create two helper scripts in the project&#8217;s <code>target/</code> directory: <code>rspec-runner.rb</code> and <code>run-rspecs.sh</code>.  The <code>run-rspecs.sh</code> can be used to run the tests more quickly and succinctly from the command line, as opposed to relying on <code>mvn test</code> to execute the tests.  The runner shell script passes its arguments through to rspec, so you can use all the <a href="http://rspec.info/documentation/tools/spec.html">features the rspec runner supports</a>, like running a single spec file or a single test within a spec (by line number or name).</p>
<h2>Example Maven Project</h2>
<p>I&#8217;ve created an example Maven project in my <a href="http://github.com/kyleburton/sandbox/tree/master/examples/maven/rspec/">github sandbox</a> that you should be able to use as a reference or starting point for your own project.  If it doesn&#8217;t work for you, after following the instructions, please let me know and I&#8217;ll try to work through any issues with you.</p>
<p>The sample project includes a single java class (<code>SomeClass</code>) and a single spec test which exercises it.  It is meant as a minimal working example at the moment, as I explore using RSpec for our Java testing I&#8217;ll try to keep it up to date with any new findings (and I hope to figure out how to get it working with JRuby 1.4).</p>
<p>The Java code is a simple class with a few members including a method to fetch a url:</p>
<pre class="code">

package com.github.kyleburton;

import org.apache.commons.io.IOUtils;

import java.net.*;
import java.io.*;

public class SomeClass {
  private String _userName;
  private String _remoteUrl;
  private String _theContent = null;
  private Downloader _downloader;

  public SomeClass() {
    _userName = "*a default*";
    _remoteUrl = "http://localhost/";
    _downloader = new Downloader(_remoteUrl);
  }

  public SomeClass(String name, String url) {
    _userName = name;
    _remoteUrl = url;
    _downloader = new Downloader(url);
  }

  public String getContent() throws IOException {
    if ( null == _theContent )
      _theContent = _downloader.download();

    return _theContent;
  }

  public String getUserName() {
    return _userName;
  }

  public void setUserName(String userName) {
    _userName = userName;
  }

  public String getRemoteUrl() {
    return _remoteUrl;
  }

  public void setRemoteUrl(String remoteUrl) {
    _remoteUrl = remoteUrl;
    _downloader = new Downloader(_remoteUrl);
  }

  public void setDownloader(Downloader downloader) {
    _downloader = downloader;
  }

  public static class Downloader {

    private String url;
    public Downloader(String url) {
      this.url = url;
    }

    public String download() throws IOException {
      return IOUtils.toString(new URL(url).openStream());
    }
  }

}
</pre>
<p>The rspec test exercises the class, including using <a href="http://mockito.org/">Mockito</a> to ensure that <code>getContent</code> actually delegates to the <code>Downloader</code> class to fetch the remote data (without it actually going out and hitting a website).</p>
<pre class="code">
import com.github.kyleburton.SomeClass
import org.mockito.Mockito

describe SomeClass do
  before(:each) do
    @the_name = "a user"
    @the_url = "http://asymmetrical-view.com/"
    @some_class = SomeClass.new @the_name, @the_url
  end

  it "should accept constructor parameters" do
    @some_class.user_name.should == @the_name
    @some_class.remote_url.should == @the_url
  end

  it "should download the conten when content is accessedt" do
    some_content = "this is some content"
    downloader = Mockito.mock(SomeClass::Downloader.java_class)
    Mockito.when(downloader.download()).then_return(some_content)
    @some_class.downloader = downloader
    @some_class.content.should_not be_empty
    @some_class.content.should == some_content
  end
end
</pre>
<p>Finally here is an exmaple of how you can run <code>irb</code> to get a Ruby <span class="caps">REPL</span> for your project with all of your project dependencies on the classpath and available in <code>irb</code> (assuming you&#8217;ve compiled it with maven first):</p>
<pre class="code">
# run-jirb.sh
CLASSPATH="target/test-classes:target/classes"
CLASSPATH="$CLASSPATH:`mvn -Dmdep.outputFile=/dev/stderr dependency:build-classpath 2&gt;&amp;1 &gt; /dev/null`"
export CLASSPATH

jirb "$@"
</pre>
<p><img src="/images/2010-02/jruby-rspec.png" style="float: right; padding: 1em; " /></p>
<h2>Conclusion</h2>
<p>Being able to use RSpec to test our Java and Clojure code-bases is going to help our team be more productive, it will bring the same sense of fun to working on these parts of our system &#8211; reduce the effort it takes and leading to more tests.  I am quite satisfied with the improvement in morale it has brought to the team when we&#8217;re working in these areas just in the first few days we&#8217;ve had it.</p>
<p><img src="/images/2010-02/NyaNya-240x273.jpg" style="right: left; padding: 1em; " /></p>
<p class="meta">Kyle Burton, 03 Feb 2010 &#8211; Philadelphia PA</p>
<h5>Special Thanks</h5>
<p>Special thanks to <a href="http://plpatterns.com/">Jon Tran</a> for reading drafts of this post.</p>
<h5>Image and Photo Credits</h5>
<ul>
	<li>&#8220;Duke&#8221; Pictures Courtesy of <a href="http://kenai.com/projects/duke/pages/Home">Project Kenai</a></li>
	<li><a href="http://asymmetrical-view.com/">Diagrams</a></li>
</ul>
<p><br /></p>]]></description>
      <content:encoded><![CDATA[<h1>From the Agony of JUnit to the Ecstasy of RSpec</h1>
<p><img src="/images/2010-02/boxer.gif" style="float: left; padding: 1em; " /></p>
<p>In the past I have had a love hate relationship with unit testing and testing tools in general.  I have had a long, healthy, even dreamy relationship with test driven development though.  Aahh how it improves design and prevents issues from reaching users!</p>
<p><img src="/images/2010-02/Gun-223x150.jpg" style="float: right; padding: 1em; " /></p>
<p>I am often unhappy with the amount of effort it takes to write tests using some of the tools and libraries out there.  I&#8217;ve been around the block from Perl to Lisp to Java, even C++ and C (I found using <a href="http://www.call-with-current-continuation.org/">Chicken</a> to be an easy way to write tests for C libraries, but I digress&#8230;)  I have found, both with myself and with teams I&#8217;ve worked with, that if the effort of writing tests is high enough, less (or no) tests will be written.  This is partly because test themselves do not represent business value or end-user features, so most things you can do to reduce the effort of writing or running tests will cause more tests to be written.  This includes not just the boilerplate set up and typing you have to do, but the amount of time it takes to run your tests (long running tests unfortunately re-introduce the flow destroying edit-compile-debug cycle back into modern dynamic application development).  Reducing effort is, of course, dependent on <span class="caps">ROI</span>, which is different for each person and team.</p>
<p>A good friend of mine, <a href="http://plpatterns.com/">Jon Tran</a>, pushes the idea that if you can make something abundant (nearly free) you haven&#8217;t just made something better, you&#8217;ve made something entirely different.  I love this idea and try to use it to guide process and tool improvements for myself and my team.</p>
<p><img src="/images/2010-02/BouncingDuke-small.gif" style="float: left; padding: 1em; " /></p>
<p>When I started working with <a href="http://rubyonrails.org/">Ruby on Rails</a> I found testing to be so well integrated into how you worked on your Rails project that it was, in fact, abundant.  It was so much easier to test your code that writing tests was no longer a chore, but it fit easily, even joyfully into the work-flow.  Working more recently with a Rails expert, <a href="http://trottercashion.com/">Trotter Cashion</a>, I was introduced to <a href="http://rspec.info/">RSpec</a>.  Our team was also blessed one fine day by a visit from <a href="http://apprentice.kfitz.me/">Kevin Fitzpatrick</a> who bootstrapped our use of <a href="http://cukes.info/">Cucumber</a> in a single afternoon pairing session.</p>
<p>These two tools were pure love.  They gave me the same kind of feelings that declarative and functional programming give me &#8211; you say what you want it to be, not just how you want it to get there.  RSpec made unit testing even more abundant, Cucumber made front end or integration testing abundant.  Those two tools went a long way to helping our team write more tests and more effective tests, improving the design of our code, applications and ultimately reducing the number of issues (especially regressions) that made it both to and past our excellent QA testers (we&#8217;re only human after all).</p>
<p>Writing unit tests for the Java portions of our systems I have really started to miss the clarity and abundance that RSpec provided.  Then I stumbled across the <a href="http://www.fnokd.com/2008/09/18/maven-java-and-rspec/">maven-rspec-plugin</a> which uses JRuby to execute rspec base tests during the test phase of the maven life cycle.</p>
<p>The storm clouds have parted and the sun is shining again.  This is exactly what I was looking for; I just hadn&#8217;t known it until I found it.</p>
<div><img src="/images/2010-02/testing-venn.png" style="padding: 1em; " /></div>
<p>We&#8217;re already using <a href="http://jruby.org/">JRuby</a> within the project and have been happy with the access to all of the <span class="caps">JVM</span> based libraries it provides to us (not to mention easy integration with our <a href="http://clojure.org/">Clojure</a> code, but that&#8217;s another post altogether).  The tools are a great fit for our team, we&#8217;re already familiar with Ruby, RSpec and writing those kinds of tests &#8211; just not yet in our Java portions of the application.</p>
<p>On your mark, get set&#8230;I followed the instructions in that post, but ended up with a NullPointerException when the plugin tried to write out the runner shell script.  I checked out the code from the CodeHaus svn repository and poked around until I found a work around, it seems that the plugin requires a <code>systemProperties</code> tag in its configuration, even if it&#8217;s not used, to prevent the <code>NPE</code>.  It just has to be present with at least one property present.</p>
<p><a href="http://www.innovationontherun.com/">Rob DiMarco</a> discovered that the plugin, rspec or something about this confluence of tools and libraries doesn&#8217;t work on JRuby 1.4 (see <a href="http://github.com/kyleburton/sandbox/issues/#issue/1">the stacktrace</a> for more information), so make sure you download and install JRuby 1.3.1 for now.</p>
<p>To get started you&#8217;ll need <a href="http://jruby.org/download">JRuby</a> installed, make sure you get <a href="http://jruby.kenai.com/downloads/1.3.1/jruby-bin-1.3.1.tar.gz">1.3.1</a> and you&#8217;ll have to set the <code>JRUBY_HOME</code> environment variable to point to your installation.  You&#8217;ll need <a href="http://maven.apache.org/">maven</a> of course as well.</p>
<p>The plugin configuration we were able to get working is the <code>pom.xml</code> fragment you see here:</p>
<pre class="code">
   &lt;plugin&gt;
     &lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;
     &lt;artifactId&gt;rspec-maven-plugin&lt;/artifactId&gt;
     &lt;configuration&gt;
       &lt;jrubyHome&gt;${env.JRUBY_HOME}&lt;/jrubyHome&gt;
       &lt;sourceDirectory&gt;${basedir}/src/test/specs&lt;/sourceDirectory&gt;
       &lt;outputDirectory&gt;${basedir}/target&lt;/outputDirectory&gt;
       &lt;systemProperties&gt;
         &lt;property&gt;&lt;name&gt;testProp&lt;/name&gt;&lt;value&gt;testValue&lt;/value&gt;&lt;/property&gt;
       &lt;/systemProperties&gt;
     &lt;/configuration&gt;
     &lt;executions&gt;
       &lt;execution&gt;
         &lt;id&gt;test&lt;/id&gt;
         &lt;phase&gt;test&lt;/phase&gt;
         &lt;goals&gt;
           &lt;goal&gt;spec&lt;/goal&gt;
         &lt;/goals&gt;
       &lt;/execution&gt;
     &lt;/executions&gt;
   &lt;/plugin&gt;
</pre>
<p><img src="/images/2010-02/Juggler-268x310.gif" style="float: right; padding: 1em; " /></p>
<p>This configures rspec to be run during the test phase of the maven build.  It also configures the plugin to look for spec tests within the src/test/specs directory.  When first executed, the plugin will create two helper scripts in the project&#8217;s <code>target/</code> directory: <code>rspec-runner.rb</code> and <code>run-rspecs.sh</code>.  The <code>run-rspecs.sh</code> can be used to run the tests more quickly and succinctly from the command line, as opposed to relying on <code>mvn test</code> to execute the tests.  The runner shell script passes its arguments through to rspec, so you can use all the <a href="http://rspec.info/documentation/tools/spec.html">features the rspec runner supports</a>, like running a single spec file or a single test within a spec (by line number or name).</p>
<h2>Example Maven Project</h2>
<p>I&#8217;ve created an example Maven project in my <a href="http://github.com/kyleburton/sandbox/tree/master/examples/maven/rspec/">github sandbox</a> that you should be able to use as a reference or starting point for your own project.  If it doesn&#8217;t work for you, after following the instructions, please let me know and I&#8217;ll try to work through any issues with you.</p>
<p>The sample project includes a single java class (<code>SomeClass</code>) and a single spec test which exercises it.  It is meant as a minimal working example at the moment, as I explore using RSpec for our Java testing I&#8217;ll try to keep it up to date with any new findings (and I hope to figure out how to get it working with JRuby 1.4).</p>
<p>The Java code is a simple class with a few members including a method to fetch a url:</p>
<pre class="code">

package com.github.kyleburton;

import org.apache.commons.io.IOUtils;

import java.net.*;
import java.io.*;

public class SomeClass {
  private String _userName;
  private String _remoteUrl;
  private String _theContent = null;
  private Downloader _downloader;

  public SomeClass() {
    _userName = "*a default*";
    _remoteUrl = "http://localhost/";
    _downloader = new Downloader(_remoteUrl);
  }

  public SomeClass(String name, String url) {
    _userName = name;
    _remoteUrl = url;
    _downloader = new Downloader(url);
  }

  public String getContent() throws IOException {
    if ( null == _theContent )
      _theContent = _downloader.download();

    return _theContent;
  }

  public String getUserName() {
    return _userName;
  }

  public void setUserName(String userName) {
    _userName = userName;
  }

  public String getRemoteUrl() {
    return _remoteUrl;
  }

  public void setRemoteUrl(String remoteUrl) {
    _remoteUrl = remoteUrl;
    _downloader = new Downloader(_remoteUrl);
  }

  public void setDownloader(Downloader downloader) {
    _downloader = downloader;
  }

  public static class Downloader {

    private String url;
    public Downloader(String url) {
      this.url = url;
    }

    public String download() throws IOException {
      return IOUtils.toString(new URL(url).openStream());
    }
  }

}
</pre>
<p>The rspec test exercises the class, including using <a href="http://mockito.org/">Mockito</a> to ensure that <code>getContent</code> actually delegates to the <code>Downloader</code> class to fetch the remote data (without it actually going out and hitting a website).</p>
<pre class="code">
import com.github.kyleburton.SomeClass
import org.mockito.Mockito

describe SomeClass do
  before(:each) do
    @the_name = "a user"
    @the_url = "http://asymmetrical-view.com/"
    @some_class = SomeClass.new @the_name, @the_url
  end

  it "should accept constructor parameters" do
    @some_class.user_name.should == @the_name
    @some_class.remote_url.should == @the_url
  end

  it "should download the conten when content is accessedt" do
    some_content = "this is some content"
    downloader = Mockito.mock(SomeClass::Downloader.java_class)
    Mockito.when(downloader.download()).then_return(some_content)
    @some_class.downloader = downloader
    @some_class.content.should_not be_empty
    @some_class.content.should == some_content
  end
end
</pre>
<p>Finally here is an exmaple of how you can run <code>irb</code> to get a Ruby <span class="caps">REPL</span> for your project with all of your project dependencies on the classpath and available in <code>irb</code> (assuming you&#8217;ve compiled it with maven first):</p>
<pre class="code">
# run-jirb.sh
CLASSPATH="target/test-classes:target/classes"
CLASSPATH="$CLASSPATH:`mvn -Dmdep.outputFile=/dev/stderr dependency:build-classpath 2&gt;&amp;1 &gt; /dev/null`"
export CLASSPATH

jirb "$@"
</pre>
<p><img src="/images/2010-02/jruby-rspec.png" style="float: right; padding: 1em; " /></p>
<h2>Conclusion</h2>
<p>Being able to use RSpec to test our Java and Clojure code-bases is going to help our team be more productive, it will bring the same sense of fun to working on these parts of our system &#8211; reduce the effort it takes and leading to more tests.  I am quite satisfied with the improvement in morale it has brought to the team when we&#8217;re working in these areas just in the first few days we&#8217;ve had it.</p>
<p><img src="/images/2010-02/NyaNya-240x273.jpg" style="right: left; padding: 1em; " /></p>
<p class="meta">Kyle Burton, 03 Feb 2010 &#8211; Philadelphia PA</p>
<h5>Special Thanks</h5>
<p>Special thanks to <a href="http://plpatterns.com/">Jon Tran</a> for reading drafts of this post.</p>
<h5>Image and Photo Credits</h5>
<ul>
	<li>&#8220;Duke&#8221; Pictures Courtesy of <a href="http://kenai.com/projects/duke/pages/Home">Project Kenai</a></li>
	<li><a href="http://asymmetrical-view.com/">Diagrams</a></li>
</ul>
<p><br /></p>]]></content:encoded>
    </item>
    
    <item>
      <title>Influential Books</title>
      <link>http://blog.asymmetrical-view.com/2009/11/30/influenced-by-books.html</link>
      <comments>http://blog.asymmetrical-view.com/2009/11/30/influenced-by-books.html#comments</comments>

      <pubDate>2009-11-30T00:00:00-05:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2009/11/30/influenced-by-books.html</guid>

      <id>http://blog.asymmetrical-view.com/2009/11/30/influenced-by-books</id>
      <description><![CDATA[<h1>Influential Books</h1>
<p>I started with a new team in the middle of this year and as I get to know the other members of the team and share our skills and experiences, the books that each of us has found influential has come up.  This has given me the opportunity to reflect a bit on which ones I still find worthy of suggesting that others read.  Over my career, and as my family has grown, I have become acutely aware of the value of my free time and that of my co-workers.  With that in mind, I&#8217;m recommending and sharing a lot less than I used to, and since a coworker (Aaron Feng) recently made a point of thanking me for my recommendations I thought I&#8217;d journal what I&#8217;ve been pushing at this new team.</p>
<p><a href="/images/2009-11/bshelf-left1.jpg"><img src="/images/2009-11/bshelf-left1-400x300.jpg" style="float: left; padding: 1em; " /></a></p>
<p>My current bookshelf contains the books it does after several rounds of being distilled over the past ten years or so.  Even so, there is a mix of titles that have been there for years as well as some recent acquisitions that I suspect will have longevity.</p>
<h2><a href="http://www.amazon.com/gp/product/1558607013?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=1558607013">Higher-Order Perl: Transforming Programs with Programs</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=1558607013" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, by Mark Jason Dominus</h2>
<p>If you program in Java, C#, Python, Ruby or another imperative, stateful language, this is perhaps the best book you can pick up to learn several core fundamentals of functional programming.  It is a great introduction to performing functional programming in an imperative, stateful language.  Mark goes through the process of showing you how to implement things like Haskell&#8217;s infinite sequences, the use of higher order functions, and several other fundamental tenants of functional programming.</p>
<p>I lent my copy to Aaron and it was him that started to tell me where in the book he is seeing some of the techniques that I use on a regular basis.  Mark is a great developer and more than just functional programming comes across in the book, a lot of his skill and clarity of thought does as well.</p>
<p>I feel very sorry for any of you that can not get over the fact that this book&#8217;s code examples are in Perl.</p>
<p><a href="/images/2009-11/bshelf-right1.jpg"><img src="/images/2009-11/bshelf-right1-400x300.jpg" style="float: right; padding: 1em; " /></a></p>
<h2><a href="http://www.amazon.com/gp/product/1558601910?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=1558601910">Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=1558601910" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /><br />
, by Peter Norvig</h2>
<p>I picked up <span class="caps">PAIP</span> along with <span class="caps">ANSI</span> Common Lisp (by Paul Graham) with the intention of learning Common Lisp.  I wasn&#8217;t prepared for what was in <span class="caps">PAIP</span> when I first struggled through the book.  I started with an expectation of learning about AI, with little expectation of picking up practical techniques that I&#8217;d be able to apply in my day job developing web applications.   What I got out of the book was much more than I anticipated.  I&#8217;ve gone back to it multiple times and it sits on the top shelf in my book case.  <span class="caps">PAIP</span> was my first introduction to how deep a subject search really was, it jump started my knowledge about lisp, continuations, functional programming, declarative programming, domain specific languages and teased me with <span class="caps">CLOS</span>.  Each of these topics is deep enough to warrant its own book, Dr. Norvig introduces each, often including implementations, in a single book.</p>
<h2><a href="http://www.xs4all.nl/~hipster/lib/scheme/gauche/define-syntax-primer.txt">JRM&#8217;s syntax-rules primer for the merely eccentric</a></h2>
<p>After being introduced to and exploring common lisp from <span class="caps">PAIP</span> and <span class="caps">ANSI</span> Common Lisp, I had started to use, but not completely understand Lisp macros.  I was only beginning to understand the implementation of, and recognize the appropriate application of the <code>with-gensyms</code> and <code>once-only</code> macros.  I had a fuzzy conception of hygiene with respect to what it meant for macros.  JRM&#8217;s syntax primer introduces R5RS&#8217;s alternate macro system: <code>define-syntax</code> and <code>syntax-rules</code>.  <code>syntax-rules</code> is based on pattern matching and recursive expansions, and it was <u>automatically</u> hygienic.  This seemed like magic and seemed to eliminate many of the hygiene problems that you encounter with the traditional Lisp style macros.  It forced me to think about code generation in a completely different light.  The primer is fairly short for the topic it introduces and the material helped me with some fundamental understanding.  The greatest influence this had was to introduce to me new ways to develop and maintain DSLs and code generators.</p>
<h2><a href="http://www.amazon.com/gp/product/193435600X?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=193435600X">Programming Erlang: Software for a Concurrent World</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=193435600X" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></h2>
<p>Joe Armstrong said that when Ericson was creating Erlang, they decided their primary concern was robustness, that to have robustness you needed at least two computers and that most of the rest of the features in Erlang flowed forth from there.  To me Erlang has come to embody what robustness really means: a platform that is capable of achieving nine 9&#8217;s, that concentrates on fail-fast or crash early so that you have more hope of recovery, supervision trees of processes so you know when things go awry and can handle them from a safe distance, the ability to update code live in a running system so that you never have to bring it down.  Erlang is the only platform and language that I&#8217;ve encountered that has internalized these principles into its core.</p>
<p>The book increased my exposure to pattern matching, introduced me to list comprehensions and message passing concurrency (gave me the name for the actors model of concurrency).</p>
<h2><a href="http://www.amazon.com/gp/product/0887306667?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0887306667">The 22 Immutable Laws of Marketing:  Violate Them at Your Own Risk!</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0887306667" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, and <a href="http://www.amazon.com/gp/product/0060007737?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0060007737">The 22 Immutable Laws of Branding</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0060007737" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, by Al Reis</h2>
<p><a href="http://www.innovationontherun.com/">Rob Di Marco</a> recommended this to me when I had the privilege of working directly with him.  It was something that was outside my core area of expertise and interest (technology, software development in specific).  I keep seeing the principles they detail show up all around me &#8211; they gave me another model for observing interactions between people, the purpose of blogs, twitter, and how you can use all of communication and points of contact to help shape how people perceive you.  They made me realize, and gave me a starting guide, for how to market and brand myself.  Mostly as a developer and technologist, but also in a few other ways.  Given that IT folks tend to be introverted and not understand the power that how others perceive them has over their interactions, this is something I try to repeatedly recommend to those that I work with.</p>
<h2><a href="http://www.amazon.com/gp/product/0471117099?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0471117099">Applied Cryptography: Protocols, Algorithms, and Source Code in C, Second Edition</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0471117099" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, by Bruce Schneier</h2>
<p>I read Applied Cryptography from cover to cover as fast as I could manage to.  At the time I read it there was a lot that was new to me: the historic context, some of the information theory, the idea that there were known best ways to attack the best known algorithms that reduced the effectiveness but did not outright invalidate the approaches, and it drove home the idea that security can not be absolute, that it is a balance between usability and restrictiveness.  This helped hone my sense of information leakage in my own development, from what is stored in files and databases, to log statements to what is exposed thorough error messages and stack traces, where user input comes from and goes to.</p>
<h2><a href="http://www.amazon.com/gp/product/0201633612?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0201633612">Design Patterns: Elements of Reusable Object-Oriented Software</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0201633612" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, by the Gang of Four (Erich Gamma, Richard Helm, Ralph Johnson, John M. Vlissides)</h2>
<p>The gang of four book was at first a set of design guidelines, over the years its importance as a design guide has waned and, for me, it has shifted more towards being important because it establishes a shared vocabulary with other developers.  Having the vocabulary allows us to describe the systems and frameworks we&#8217;re using and creating in a way that increases understanding and minimizes misconceptions.</p>
<p><a href="/images/2009-11/bshelf-left2.jpg"><img src="/images/2009-11/bshelf-left2-400x300.jpg" style="float: left; padding: 1em; " /></a></p>
<h2><a href="http://www.amazon.com/gp/product/0201485672?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0201485672">Refactoring: Improving the Design of Existing Code</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0201485672" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, by Martin Fowler</h2>
<p>This emphasized the importance of unit testing in the ability to effectively maintain and improve an existing codebase.  It introduced me to the ideas of test driven development along with the pragmatic programmer.</p>
<h2><a href="http://www.amazon.com/gp/product/0201633469?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0201633469"><span class="caps">TCP</span>/IP Illustrated, Volume 1: The Protocols</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0201633469" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, and <a href="http://www.amazon.com/gp/product/013490012X?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=013490012X"><span class="caps">UNIX</span> Network Programming: Networking APIs: Sockets and <span class="caps">XTI</span>; Volume 1</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=013490012X" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /> by Richard Stevens</h2>
<p>Having read these books has served my career well over the years.  The introduction to the protocols, and the networking APIs, has been invaluable.  The single most important thing I took away from this book was how I/O Multiplexing (select/poll, non-blocking IO) worked and how efficient it could be.</p>
<h2><a href="http://www.amazon.com/gp/product/0596000278?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0596000278">Programming Perl (3rd Edition)</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0596000278" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, by Larry Wall, Tom Christiansen, and Jon Orwant</h2>
<p>Perl was the first dynamic language I learned (having programmed only in compiled languages before it).  I think the camel book was my first O&#8217;Reilly title &#8211; many, many more followed.  O&#8217;Reilly as a publisher deserves a lot of credit for helping to bootstrap my programming career.  Programming Perl showed me that a language, its creators and practitioners, and especially its community could have character.  It emphasized that programming should be enjoyable and fun.   &#8220;Easy things should be easy and hard things should be possible&#8221; is a great slogan for a language &#8211; a language that had a slogan!</p>
<h2><a href="http://www.amazon.com/gp/product/0201350882?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0201350882">Algorithms in C++, Parts 1-4: Fundamentals, Data Structure, Sorting, Searching (3rd Edition) (Pts. 1-4)</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0201350882" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, by Robert Sedgewick</h2>
<p>Sedgewick provided me with my first introduction to &#8216;Big Oh&#8217; notation.  His examples displayed an enormous amount of thrift, some of the best examples I&#8217;ve seen of using the minimum necessary to implement the chosen algorithm.  This was not minimalism to the point of terseness, it exemplified that with a clear understanding of the problem, the choice of an algorithm that closely fit the problem, implementations should be clear and uncluttered.  The aesthetic of using minimal language features so as to be as clear as possible was a clear influence on me.</p>
<h2><a href="http://www.amazon.com/gp/product/1565923987?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=1565923987">Mastering Algorithms with Perl</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=1565923987" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></h2>
<p>I was first introduced to fuzzy string matching through this book, which turned out to be an interesting problem domain.  I spent about eight years working for a data integration company applying many of the things I first discovered from these algorithms books.</p>
<h2><a href="http://www.amazon.com/gp/product/020161622X?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=020161622X">The Pragmatic Programmer: From Journeyman to Master</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=020161622X" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, by Andrew Hunt and David Thomas</h2>
<p>Continual improvement.  Keep questioning and seeking better processes, techniques, solutions.  Learning a new programming language on a regular basis was the single most memorable part of that book for me.  That particular advice has worked particularly well for me.  I believe that each programming language was created to address a core issue or difficulty that its creator was experiencing.  The language is a manifestation of their understanding of the issue and a simplified design that makes that issue easier to contend with.  Some address multiple issues.  My impression of C is that it made for more structured interaction with the hardware&#8217;s basic features (at a time when there was little).  C++ improved the expressiveness of C, introducing OO without moving too far away from the machine.  Java eliminated memory management and pointer manipulation mistakes that programmers were so often tripped up by in C and C++ applications, simplified platform dependency issues, and smoothed over some of the complexity of the OO features in C++.  Perl worked to integrate other tools, most often that produced or consumed text, it was an integration toolbox and grew from there towards a powerful and terse high level language.  Lisp removed all barriers to abstraction, it eliminated the sacred parts of the language and put all their power into the hands of the developer: to do their best, or their worst.</p>
<h2><a href="http://www.amazon.com/gp/product/020161586X?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=020161586X">The Practice of Programming</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=020161586X" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, by Brian Khernagin and Rob Pike</h2>
<p>They tell you to continue to hone your skills, develop your craft, continually improve.  Develop your vocabulary and ability to name things clearly and concisely as it very much matters in the clarity of your software.  Learn your tools.  This is one of the books I have to thank for my never-ending stream of reading and continued exploration of this field.</p>
<p><a href="/images/2009-11/bshelf-right2.jpg"><img src="/images/2009-11/bshelf-right2-400x300.jpg" style="float: right; padding: 1em; " /></a></p>
<h2><a href="http://www.amazon.com/gp/product/0393316041?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0393316041">Surely You&#8217;re Joking, Mr. Feynman! (Adventures of a Curious Character)</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0393316041" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, Richard P. Feynman</h2>
<p>Intellectual curiosity.  Looking outside the box.  There is another way to view things.  Trust your intuition and be tenacious &#8211; if there are only 2 possibilities and the evidence is inconclusive, discover new evidence, don&#8217;t just discard the original axioms &#8211; this attitude has been a huge help in debugging.  In some ways it comes down to having faith in yourself.  I hope my children choose to read and are inspired by Feynman&#8217;s writing.</p>
<h2><a href="http://www.amazon.com/gp/product/0553380966?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0553380966">The Diamond Age: Or, a Young Lady&#8217;s Illustrated Primer (Bantam Spectra Book)</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0553380966" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, Neal Stephenson</h2>
<p>Though I enjoyed both Snow Crash and The Diamond Age, I was more inspired by his vision of a young lady&#8217;s illustrated primer.  You see the ideas he was exploring in the primer continuing to manifest themselves over time.  How the Internet is permeating all our devices and experiences, the collaborative nature of how Wikipedia and other crowd sourced assets are being created, Amazon&#8217;s Kindle ebook reader (with on-line access to new content) and discritized task sites like the Mechanical Turk.  I want to be able to gift my own children with their own primers.</p>
<h2><a href="http://www.amazon.com/gp/product/0679743111?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0679743111">Penn and Teller&#8217;s How to Play with Your Food</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0679743111" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, Penn Jillette and Teller</h2>
<p>Thinking outside the box.  Looking at things for what they are, not just for what they seem.  Seeing alternate, unexpected, uses for common things.  In showing how effectively you can deceive your senses, the book helped give me a good sense of skepticism &#8211; not taking something at face value if it didn&#8217;t seem right (I tie this to debugging believe it or not).</p>
<h1>Conclusion</h1>
<p>These are books that have had staying power in my bookshelf.  I&#8217;d love to hear your own thoughts if you do decide to pick any of these up, or even if you&#8217;ve already been through their pages.  I always ask people what books they&#8217;ve found influential as a standard question when I interview developers.  What do you recommend?</p>
<p class="meta">Kyle Burton, 30th November 2009 &#8211; Philadelphia PA</p>
<h3>Thanks</h3>
<p>Special thanks to <a href="http://plpatterns.com/">Jonathan Tran</a>, <a href="http://www.leftrightfold.com/">Aaron Feng</a>, <a href="http://www.innovationontherun.com/">Rob Di Marco</a> and others who have lent and recommended books to me over the years.  A second thanks to both Jonathan and Aaron for reading drafts of this post.</p>]]></description>
      <content:encoded><![CDATA[<h1>Influential Books</h1>
<p>I started with a new team in the middle of this year and as I get to know the other members of the team and share our skills and experiences, the books that each of us has found influential has come up.  This has given me the opportunity to reflect a bit on which ones I still find worthy of suggesting that others read.  Over my career, and as my family has grown, I have become acutely aware of the value of my free time and that of my co-workers.  With that in mind, I&#8217;m recommending and sharing a lot less than I used to, and since a coworker (Aaron Feng) recently made a point of thanking me for my recommendations I thought I&#8217;d journal what I&#8217;ve been pushing at this new team.</p>
<p><a href="/images/2009-11/bshelf-left1.jpg"><img src="/images/2009-11/bshelf-left1-400x300.jpg" style="float: left; padding: 1em; " /></a></p>
<p>My current bookshelf contains the books it does after several rounds of being distilled over the past ten years or so.  Even so, there is a mix of titles that have been there for years as well as some recent acquisitions that I suspect will have longevity.</p>
<h2><a href="http://www.amazon.com/gp/product/1558607013?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=1558607013">Higher-Order Perl: Transforming Programs with Programs</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=1558607013" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, by Mark Jason Dominus</h2>
<p>If you program in Java, C#, Python, Ruby or another imperative, stateful language, this is perhaps the best book you can pick up to learn several core fundamentals of functional programming.  It is a great introduction to performing functional programming in an imperative, stateful language.  Mark goes through the process of showing you how to implement things like Haskell&#8217;s infinite sequences, the use of higher order functions, and several other fundamental tenants of functional programming.</p>
<p>I lent my copy to Aaron and it was him that started to tell me where in the book he is seeing some of the techniques that I use on a regular basis.  Mark is a great developer and more than just functional programming comes across in the book, a lot of his skill and clarity of thought does as well.</p>
<p>I feel very sorry for any of you that can not get over the fact that this book&#8217;s code examples are in Perl.</p>
<p><a href="/images/2009-11/bshelf-right1.jpg"><img src="/images/2009-11/bshelf-right1-400x300.jpg" style="float: right; padding: 1em; " /></a></p>
<h2><a href="http://www.amazon.com/gp/product/1558601910?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=1558601910">Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=1558601910" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /><br />
, by Peter Norvig</h2>
<p>I picked up <span class="caps">PAIP</span> along with <span class="caps">ANSI</span> Common Lisp (by Paul Graham) with the intention of learning Common Lisp.  I wasn&#8217;t prepared for what was in <span class="caps">PAIP</span> when I first struggled through the book.  I started with an expectation of learning about AI, with little expectation of picking up practical techniques that I&#8217;d be able to apply in my day job developing web applications.   What I got out of the book was much more than I anticipated.  I&#8217;ve gone back to it multiple times and it sits on the top shelf in my book case.  <span class="caps">PAIP</span> was my first introduction to how deep a subject search really was, it jump started my knowledge about lisp, continuations, functional programming, declarative programming, domain specific languages and teased me with <span class="caps">CLOS</span>.  Each of these topics is deep enough to warrant its own book, Dr. Norvig introduces each, often including implementations, in a single book.</p>
<h2><a href="http://www.xs4all.nl/~hipster/lib/scheme/gauche/define-syntax-primer.txt">JRM&#8217;s syntax-rules primer for the merely eccentric</a></h2>
<p>After being introduced to and exploring common lisp from <span class="caps">PAIP</span> and <span class="caps">ANSI</span> Common Lisp, I had started to use, but not completely understand Lisp macros.  I was only beginning to understand the implementation of, and recognize the appropriate application of the <code>with-gensyms</code> and <code>once-only</code> macros.  I had a fuzzy conception of hygiene with respect to what it meant for macros.  JRM&#8217;s syntax primer introduces R5RS&#8217;s alternate macro system: <code>define-syntax</code> and <code>syntax-rules</code>.  <code>syntax-rules</code> is based on pattern matching and recursive expansions, and it was <u>automatically</u> hygienic.  This seemed like magic and seemed to eliminate many of the hygiene problems that you encounter with the traditional Lisp style macros.  It forced me to think about code generation in a completely different light.  The primer is fairly short for the topic it introduces and the material helped me with some fundamental understanding.  The greatest influence this had was to introduce to me new ways to develop and maintain DSLs and code generators.</p>
<h2><a href="http://www.amazon.com/gp/product/193435600X?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=193435600X">Programming Erlang: Software for a Concurrent World</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=193435600X" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></h2>
<p>Joe Armstrong said that when Ericson was creating Erlang, they decided their primary concern was robustness, that to have robustness you needed at least two computers and that most of the rest of the features in Erlang flowed forth from there.  To me Erlang has come to embody what robustness really means: a platform that is capable of achieving nine 9&#8217;s, that concentrates on fail-fast or crash early so that you have more hope of recovery, supervision trees of processes so you know when things go awry and can handle them from a safe distance, the ability to update code live in a running system so that you never have to bring it down.  Erlang is the only platform and language that I&#8217;ve encountered that has internalized these principles into its core.</p>
<p>The book increased my exposure to pattern matching, introduced me to list comprehensions and message passing concurrency (gave me the name for the actors model of concurrency).</p>
<h2><a href="http://www.amazon.com/gp/product/0887306667?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0887306667">The 22 Immutable Laws of Marketing:  Violate Them at Your Own Risk!</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0887306667" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, and <a href="http://www.amazon.com/gp/product/0060007737?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0060007737">The 22 Immutable Laws of Branding</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0060007737" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, by Al Reis</h2>
<p><a href="http://www.innovationontherun.com/">Rob Di Marco</a> recommended this to me when I had the privilege of working directly with him.  It was something that was outside my core area of expertise and interest (technology, software development in specific).  I keep seeing the principles they detail show up all around me &#8211; they gave me another model for observing interactions between people, the purpose of blogs, twitter, and how you can use all of communication and points of contact to help shape how people perceive you.  They made me realize, and gave me a starting guide, for how to market and brand myself.  Mostly as a developer and technologist, but also in a few other ways.  Given that IT folks tend to be introverted and not understand the power that how others perceive them has over their interactions, this is something I try to repeatedly recommend to those that I work with.</p>
<h2><a href="http://www.amazon.com/gp/product/0471117099?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0471117099">Applied Cryptography: Protocols, Algorithms, and Source Code in C, Second Edition</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0471117099" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, by Bruce Schneier</h2>
<p>I read Applied Cryptography from cover to cover as fast as I could manage to.  At the time I read it there was a lot that was new to me: the historic context, some of the information theory, the idea that there were known best ways to attack the best known algorithms that reduced the effectiveness but did not outright invalidate the approaches, and it drove home the idea that security can not be absolute, that it is a balance between usability and restrictiveness.  This helped hone my sense of information leakage in my own development, from what is stored in files and databases, to log statements to what is exposed thorough error messages and stack traces, where user input comes from and goes to.</p>
<h2><a href="http://www.amazon.com/gp/product/0201633612?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0201633612">Design Patterns: Elements of Reusable Object-Oriented Software</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0201633612" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, by the Gang of Four (Erich Gamma, Richard Helm, Ralph Johnson, John M. Vlissides)</h2>
<p>The gang of four book was at first a set of design guidelines, over the years its importance as a design guide has waned and, for me, it has shifted more towards being important because it establishes a shared vocabulary with other developers.  Having the vocabulary allows us to describe the systems and frameworks we&#8217;re using and creating in a way that increases understanding and minimizes misconceptions.</p>
<p><a href="/images/2009-11/bshelf-left2.jpg"><img src="/images/2009-11/bshelf-left2-400x300.jpg" style="float: left; padding: 1em; " /></a></p>
<h2><a href="http://www.amazon.com/gp/product/0201485672?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0201485672">Refactoring: Improving the Design of Existing Code</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0201485672" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, by Martin Fowler</h2>
<p>This emphasized the importance of unit testing in the ability to effectively maintain and improve an existing codebase.  It introduced me to the ideas of test driven development along with the pragmatic programmer.</p>
<h2><a href="http://www.amazon.com/gp/product/0201633469?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0201633469"><span class="caps">TCP</span>/IP Illustrated, Volume 1: The Protocols</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0201633469" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, and <a href="http://www.amazon.com/gp/product/013490012X?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=013490012X"><span class="caps">UNIX</span> Network Programming: Networking APIs: Sockets and <span class="caps">XTI</span>; Volume 1</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=013490012X" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /> by Richard Stevens</h2>
<p>Having read these books has served my career well over the years.  The introduction to the protocols, and the networking APIs, has been invaluable.  The single most important thing I took away from this book was how I/O Multiplexing (select/poll, non-blocking IO) worked and how efficient it could be.</p>
<h2><a href="http://www.amazon.com/gp/product/0596000278?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0596000278">Programming Perl (3rd Edition)</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0596000278" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, by Larry Wall, Tom Christiansen, and Jon Orwant</h2>
<p>Perl was the first dynamic language I learned (having programmed only in compiled languages before it).  I think the camel book was my first O&#8217;Reilly title &#8211; many, many more followed.  O&#8217;Reilly as a publisher deserves a lot of credit for helping to bootstrap my programming career.  Programming Perl showed me that a language, its creators and practitioners, and especially its community could have character.  It emphasized that programming should be enjoyable and fun.   &#8220;Easy things should be easy and hard things should be possible&#8221; is a great slogan for a language &#8211; a language that had a slogan!</p>
<h2><a href="http://www.amazon.com/gp/product/0201350882?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0201350882">Algorithms in C++, Parts 1-4: Fundamentals, Data Structure, Sorting, Searching (3rd Edition) (Pts. 1-4)</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0201350882" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, by Robert Sedgewick</h2>
<p>Sedgewick provided me with my first introduction to &#8216;Big Oh&#8217; notation.  His examples displayed an enormous amount of thrift, some of the best examples I&#8217;ve seen of using the minimum necessary to implement the chosen algorithm.  This was not minimalism to the point of terseness, it exemplified that with a clear understanding of the problem, the choice of an algorithm that closely fit the problem, implementations should be clear and uncluttered.  The aesthetic of using minimal language features so as to be as clear as possible was a clear influence on me.</p>
<h2><a href="http://www.amazon.com/gp/product/1565923987?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=1565923987">Mastering Algorithms with Perl</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=1565923987" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></h2>
<p>I was first introduced to fuzzy string matching through this book, which turned out to be an interesting problem domain.  I spent about eight years working for a data integration company applying many of the things I first discovered from these algorithms books.</p>
<h2><a href="http://www.amazon.com/gp/product/020161622X?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=020161622X">The Pragmatic Programmer: From Journeyman to Master</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=020161622X" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, by Andrew Hunt and David Thomas</h2>
<p>Continual improvement.  Keep questioning and seeking better processes, techniques, solutions.  Learning a new programming language on a regular basis was the single most memorable part of that book for me.  That particular advice has worked particularly well for me.  I believe that each programming language was created to address a core issue or difficulty that its creator was experiencing.  The language is a manifestation of their understanding of the issue and a simplified design that makes that issue easier to contend with.  Some address multiple issues.  My impression of C is that it made for more structured interaction with the hardware&#8217;s basic features (at a time when there was little).  C++ improved the expressiveness of C, introducing OO without moving too far away from the machine.  Java eliminated memory management and pointer manipulation mistakes that programmers were so often tripped up by in C and C++ applications, simplified platform dependency issues, and smoothed over some of the complexity of the OO features in C++.  Perl worked to integrate other tools, most often that produced or consumed text, it was an integration toolbox and grew from there towards a powerful and terse high level language.  Lisp removed all barriers to abstraction, it eliminated the sacred parts of the language and put all their power into the hands of the developer: to do their best, or their worst.</p>
<h2><a href="http://www.amazon.com/gp/product/020161586X?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=020161586X">The Practice of Programming</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=020161586X" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, by Brian Khernagin and Rob Pike</h2>
<p>They tell you to continue to hone your skills, develop your craft, continually improve.  Develop your vocabulary and ability to name things clearly and concisely as it very much matters in the clarity of your software.  Learn your tools.  This is one of the books I have to thank for my never-ending stream of reading and continued exploration of this field.</p>
<p><a href="/images/2009-11/bshelf-right2.jpg"><img src="/images/2009-11/bshelf-right2-400x300.jpg" style="float: right; padding: 1em; " /></a></p>
<h2><a href="http://www.amazon.com/gp/product/0393316041?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0393316041">Surely You&#8217;re Joking, Mr. Feynman! (Adventures of a Curious Character)</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0393316041" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, Richard P. Feynman</h2>
<p>Intellectual curiosity.  Looking outside the box.  There is another way to view things.  Trust your intuition and be tenacious &#8211; if there are only 2 possibilities and the evidence is inconclusive, discover new evidence, don&#8217;t just discard the original axioms &#8211; this attitude has been a huge help in debugging.  In some ways it comes down to having faith in yourself.  I hope my children choose to read and are inspired by Feynman&#8217;s writing.</p>
<h2><a href="http://www.amazon.com/gp/product/0553380966?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0553380966">The Diamond Age: Or, a Young Lady&#8217;s Illustrated Primer (Bantam Spectra Book)</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0553380966" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, Neal Stephenson</h2>
<p>Though I enjoyed both Snow Crash and The Diamond Age, I was more inspired by his vision of a young lady&#8217;s illustrated primer.  You see the ideas he was exploring in the primer continuing to manifest themselves over time.  How the Internet is permeating all our devices and experiences, the collaborative nature of how Wikipedia and other crowd sourced assets are being created, Amazon&#8217;s Kindle ebook reader (with on-line access to new content) and discritized task sites like the Mechanical Turk.  I want to be able to gift my own children with their own primers.</p>
<h2><a href="http://www.amazon.com/gp/product/0679743111?ie=UTF8&tag=asymmview-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0679743111">Penn and Teller&#8217;s How to Play with Your Food</a><img src="http://www.assoc-amazon.com/e/ir?t=asymmview-20&l=as2&o=1&a=0679743111" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, Penn Jillette and Teller</h2>
<p>Thinking outside the box.  Looking at things for what they are, not just for what they seem.  Seeing alternate, unexpected, uses for common things.  In showing how effectively you can deceive your senses, the book helped give me a good sense of skepticism &#8211; not taking something at face value if it didn&#8217;t seem right (I tie this to debugging believe it or not).</p>
<h1>Conclusion</h1>
<p>These are books that have had staying power in my bookshelf.  I&#8217;d love to hear your own thoughts if you do decide to pick any of these up, or even if you&#8217;ve already been through their pages.  I always ask people what books they&#8217;ve found influential as a standard question when I interview developers.  What do you recommend?</p>
<p class="meta">Kyle Burton, 30th November 2009 &#8211; Philadelphia PA</p>
<h3>Thanks</h3>
<p>Special thanks to <a href="http://plpatterns.com/">Jonathan Tran</a>, <a href="http://www.leftrightfold.com/">Aaron Feng</a>, <a href="http://www.innovationontherun.com/">Rob Di Marco</a> and others who have lent and recommended books to me over the years.  A second thanks to both Jonathan and Aaron for reading drafts of this post.</p>]]></content:encoded>
    </item>
    
    <item>
      <title>Connecting SLIME to a remote Clojure Repl</title>
      <link>http://blog.asymmetrical-view.com/2009/08/20/emacs-slime-remote-repl.html</link>
      <comments>http://blog.asymmetrical-view.com/2009/08/20/emacs-slime-remote-repl.html#comments</comments>

      <pubDate>2009-08-20T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2009/08/20/emacs-slime-remote-repl.html</guid>

      <id>http://blog.asymmetrical-view.com/2009/08/20/emacs-slime-remote-repl</id>
      <description><![CDATA[<p><img src="/images/2009-08/emacs-swank-clojure-1.png" style="float: left; padding: 1em; " /></p>
<h1>Connecting <span class="caps">SLIME</span> to a remote Clojure Repl</h1>
<p><a href="http://common-lisp.net/project/slime/"><span class="caps">SLIME</span></a> is a powerful extension for <a href="http://www.gnu.org/software/emacs/">Emacs</a> that transforms Emacs into an <span class="caps">IDE</span> for Lisp.  It sets up Emacs so that it can connect to and interact with a Lisp running as a separate process &#8211; even on a separate server.  This configuration allows you to connect to a running application with Emacs, allowing you to inspect the state of and debug a running application.  In this post I will walk you through how to set up and use this scenario using Emacs, <span class="caps">SLIME</span> and <a href="http://www.openssh.com/"><span class="caps">SSH</span></a> to connect to a remote <a href="http://en.wikipedia.org/wiki/Java_Virtual_Machine"><span class="caps">JVM</span></a> running <a href="http://clojure.org/">Clojure</a>.</p>
<h2><span class="caps">SLIME</span> and Swank</h2>
<p>Slime largely provides the &#8216;<span class="caps">IDE</span>&#8217; portion of the extension, where Swank provides the inter-process communication between Emacs and the running Lisp image.  Swank is broken into two parts, a layer run within Emacs and a server which runs within the Lisp image.  This provides Emacs the ability to execute forms (expressions) within the running Lisp instance, query it for information and otherwise interact with it in a structured manner.</p>
<h2>Clojure</h2>
<p>Slime was extended by <a href="http://github.com/jochu/">Jeffery Chu</a> to support Clojure through <a href="http://github.com/jochu/swank-clojure/tree/master">swank-clojure</a>.  Swank-clojure creates a server within the <span class="caps">JVM</span> running in its own thread to handle connections from the Emacs part of Swank.</p>
<p>Getting Emacs, <span class="caps">SLIME</span>, Clojure and clojure-swank set up is covered by others; <a href="http://technomancy.us/126">technomancy.us</a> has a good getting started guide.  My own configuration is available as an example in my <a href="http://github.com/kyleburton/krbemacs/tree/master">GitHub</a> account.</p>
<h2>Giving your <span class="caps">JVM</span> some Swank</h2>
<p>Before you can connect to your running image, you&#8217;ll first need to start up Clojure (the Repl) and run the swank-server.  You will need to ensure the <code>swank-clojure</code> directory is on your class-path as well as the clojure and clojure-contrib jar files.  I use a bash script like the following to run a Clojure Repl.  This script sets up a class-path that includes the clojure and clojure-contrib jar files as well as swank-clojure, which we&#8217;ll be using in a minute.  It also adds all of the files in my <code>$HOME/.clojure</code> directory.  I keep commonly used jar files in that directory so this is a convenient way to pull in multiple dependencies.</p>
<pre class="code">
CLOJURE_JAR="$HOME/.clojure/clojure.jar"
CONTRIB_JAR="$HOME/.clojure/clojure-contrib.jar"
CLASSPATH="$CLOJURE_JAR:$CONTRIB_JAR:$HOME/personal/projects/krbemacs/swank-clojure" 
for f in $HOME/.clojure/*; do CLASSPATH="$CLASSPATH:$f" done
java -server -cp "$CLASSPATH" clojure.lang.Repl "$@"
</pre>
<p>In addition to the above script, I have the following in a &#8216;run-swank.clj&#8217; file.  It requires swank, sets a required protocol version and finally starts swank in its own thread.</p>
<pre class="code">
(require 'swank.swank)
(swank.swank/ignore-protocol-version "2009-08-19")
(swank.swank/start-server "/tmp/slime.krb" 
                          :encoding "iso-latin-1-unix"
                          :port 4005)
</pre>
<p>The ignore-protocol-version is needed by swank-clojure to ensure that the swank-elisp and swank-clojure are in sync (I realize it is named confusingly).  The first argument to <code>start-server</code> is a path to which the port swank is listening on will be written to.  When you run Lisp from within Emacs these functions are executed by swank-elisp and this file is used so that both sides know what the port is.  I run this from either the clojure script or from a clojure repl (outside of Emacs) with <code>load-file</code>:</p>
<pre class="code">
kyle@indigo64 ~/personal/projects/krbemacs[master]$ clojure
Clojure 1.1.0-alpha-SNAPSHOT
user=&gt; (load-file "run-swank.clj")
Connection opened on local port  4005
4005
user=&gt; 
</pre>
<p><img src="/images/2009-08/emacs-slime-swank-internet.png" style="float: right; padding: 1em; " /></p>
<p>Swank is now running within this lisp image.</p>
<p>The current version of swank-clojure (as of August 20th 2009) does not bind to only localhost, allowing connections from external hosts.  Ensure you have either firewalled off the swank port (4005 is the default) or patch swank-clojure to bind only to localhost (there is a swank-clojure in my <a href="http://github.com/kyleburton/krbemacs">Emacs GitHub</a> repository with this modification).</p>
<p>Since I can&#8217;t connect directly to this remote-host (the port is not exposed to the network).  I need to use ssh to securely forward a port from my local workstation through an ssh-tunnel to the other machine:</p>
<pre class="code">
kyle@macbook ~/$ ssh -L1099:localhost:4005 indigo64
Linux indigo64 2.6.18.8-x86_64-ubuntu #1 SMP Thu Apr 10 11:20:13 EDT 2008 x86_64
Last login: Fri Aug 21 01:50:59 2009 from macbook
kyle@indigo64 ~$ 
</pre>
<p>I can now connect to this from my Emacs by executing <code>M-x slime-connect</code>, providing localhost or 127.0.0.1 as the Host-name and 1099 as the port. I chose 1099 arbitrarily, you can use any unused port &#8212; 4005 is a fine choice especially since it is the swank default.</p>
<p>At this point, with emacs connected, forms evaluated at the repl within Emacs, or from Clojure buffers will actually be run within the remote <span class="caps">JVM</span>.</p>
<p>Executing a print-line from Emacs running on my laptop:</p>
<p><img class="centered-img" src="/images/2009-08/emacs-slime-connected.png" style="padding: 1em; " /></p>
<p>Produces output on the remote Clojure image:</p>
<p><img class="centered-img" src="/images/2009-08/terminal-clojure-repl.png" style="padding: 1em; " /></p>
<h2>Conclusion</h2>
<p>Being able to connect to a remote running image can be useful &#8211; especially for times when you can&#8217;t have your development environment present on the remote server and still need to introspect the running process.</p>
<p class="meta">Kyle Burton, 20th August 2009 &#8211; Philadelphia PA</p>
<h3>Thanks</h3>
<p>Special thanks to <a href="http://plpatterns.com/">Jonathan Tran</a>, and <a href="http://innovationontherun.com/">Rob DiMarco</a> for reading drafts and providing valuable feedback and suggestions.</p>]]></description>
      <content:encoded><![CDATA[<p><img src="/images/2009-08/emacs-swank-clojure-1.png" style="float: left; padding: 1em; " /></p>
<h1>Connecting <span class="caps">SLIME</span> to a remote Clojure Repl</h1>
<p><a href="http://common-lisp.net/project/slime/"><span class="caps">SLIME</span></a> is a powerful extension for <a href="http://www.gnu.org/software/emacs/">Emacs</a> that transforms Emacs into an <span class="caps">IDE</span> for Lisp.  It sets up Emacs so that it can connect to and interact with a Lisp running as a separate process &#8211; even on a separate server.  This configuration allows you to connect to a running application with Emacs, allowing you to inspect the state of and debug a running application.  In this post I will walk you through how to set up and use this scenario using Emacs, <span class="caps">SLIME</span> and <a href="http://www.openssh.com/"><span class="caps">SSH</span></a> to connect to a remote <a href="http://en.wikipedia.org/wiki/Java_Virtual_Machine"><span class="caps">JVM</span></a> running <a href="http://clojure.org/">Clojure</a>.</p>
<h2><span class="caps">SLIME</span> and Swank</h2>
<p>Slime largely provides the &#8216;<span class="caps">IDE</span>&#8217; portion of the extension, where Swank provides the inter-process communication between Emacs and the running Lisp image.  Swank is broken into two parts, a layer run within Emacs and a server which runs within the Lisp image.  This provides Emacs the ability to execute forms (expressions) within the running Lisp instance, query it for information and otherwise interact with it in a structured manner.</p>
<h2>Clojure</h2>
<p>Slime was extended by <a href="http://github.com/jochu/">Jeffery Chu</a> to support Clojure through <a href="http://github.com/jochu/swank-clojure/tree/master">swank-clojure</a>.  Swank-clojure creates a server within the <span class="caps">JVM</span> running in its own thread to handle connections from the Emacs part of Swank.</p>
<p>Getting Emacs, <span class="caps">SLIME</span>, Clojure and clojure-swank set up is covered by others; <a href="http://technomancy.us/126">technomancy.us</a> has a good getting started guide.  My own configuration is available as an example in my <a href="http://github.com/kyleburton/krbemacs/tree/master">GitHub</a> account.</p>
<h2>Giving your <span class="caps">JVM</span> some Swank</h2>
<p>Before you can connect to your running image, you&#8217;ll first need to start up Clojure (the Repl) and run the swank-server.  You will need to ensure the <code>swank-clojure</code> directory is on your class-path as well as the clojure and clojure-contrib jar files.  I use a bash script like the following to run a Clojure Repl.  This script sets up a class-path that includes the clojure and clojure-contrib jar files as well as swank-clojure, which we&#8217;ll be using in a minute.  It also adds all of the files in my <code>$HOME/.clojure</code> directory.  I keep commonly used jar files in that directory so this is a convenient way to pull in multiple dependencies.</p>
<pre class="code">
CLOJURE_JAR="$HOME/.clojure/clojure.jar"
CONTRIB_JAR="$HOME/.clojure/clojure-contrib.jar"
CLASSPATH="$CLOJURE_JAR:$CONTRIB_JAR:$HOME/personal/projects/krbemacs/swank-clojure" 
for f in $HOME/.clojure/*; do CLASSPATH="$CLASSPATH:$f" done
java -server -cp "$CLASSPATH" clojure.lang.Repl "$@"
</pre>
<p>In addition to the above script, I have the following in a &#8216;run-swank.clj&#8217; file.  It requires swank, sets a required protocol version and finally starts swank in its own thread.</p>
<pre class="code">
(require 'swank.swank)
(swank.swank/ignore-protocol-version "2009-08-19")
(swank.swank/start-server "/tmp/slime.krb" 
                          :encoding "iso-latin-1-unix"
                          :port 4005)
</pre>
<p>The ignore-protocol-version is needed by swank-clojure to ensure that the swank-elisp and swank-clojure are in sync (I realize it is named confusingly).  The first argument to <code>start-server</code> is a path to which the port swank is listening on will be written to.  When you run Lisp from within Emacs these functions are executed by swank-elisp and this file is used so that both sides know what the port is.  I run this from either the clojure script or from a clojure repl (outside of Emacs) with <code>load-file</code>:</p>
<pre class="code">
kyle@indigo64 ~/personal/projects/krbemacs[master]$ clojure
Clojure 1.1.0-alpha-SNAPSHOT
user=&gt; (load-file "run-swank.clj")
Connection opened on local port  4005
4005
user=&gt; 
</pre>
<p><img src="/images/2009-08/emacs-slime-swank-internet.png" style="float: right; padding: 1em; " /></p>
<p>Swank is now running within this lisp image.</p>
<p>The current version of swank-clojure (as of August 20th 2009) does not bind to only localhost, allowing connections from external hosts.  Ensure you have either firewalled off the swank port (4005 is the default) or patch swank-clojure to bind only to localhost (there is a swank-clojure in my <a href="http://github.com/kyleburton/krbemacs">Emacs GitHub</a> repository with this modification).</p>
<p>Since I can&#8217;t connect directly to this remote-host (the port is not exposed to the network).  I need to use ssh to securely forward a port from my local workstation through an ssh-tunnel to the other machine:</p>
<pre class="code">
kyle@macbook ~/$ ssh -L1099:localhost:4005 indigo64
Linux indigo64 2.6.18.8-x86_64-ubuntu #1 SMP Thu Apr 10 11:20:13 EDT 2008 x86_64
Last login: Fri Aug 21 01:50:59 2009 from macbook
kyle@indigo64 ~$ 
</pre>
<p>I can now connect to this from my Emacs by executing <code>M-x slime-connect</code>, providing localhost or 127.0.0.1 as the Host-name and 1099 as the port. I chose 1099 arbitrarily, you can use any unused port &#8212; 4005 is a fine choice especially since it is the swank default.</p>
<p>At this point, with emacs connected, forms evaluated at the repl within Emacs, or from Clojure buffers will actually be run within the remote <span class="caps">JVM</span>.</p>
<p>Executing a print-line from Emacs running on my laptop:</p>
<p><img class="centered-img" src="/images/2009-08/emacs-slime-connected.png" style="padding: 1em; " /></p>
<p>Produces output on the remote Clojure image:</p>
<p><img class="centered-img" src="/images/2009-08/terminal-clojure-repl.png" style="padding: 1em; " /></p>
<h2>Conclusion</h2>
<p>Being able to connect to a remote running image can be useful &#8211; especially for times when you can&#8217;t have your development environment present on the remote server and still need to introspect the running process.</p>
<p class="meta">Kyle Burton, 20th August 2009 &#8211; Philadelphia PA</p>
<h3>Thanks</h3>
<p>Special thanks to <a href="http://plpatterns.com/">Jonathan Tran</a>, and <a href="http://innovationontherun.com/">Rob DiMarco</a> for reading drafts and providing valuable feedback and suggestions.</p>]]></content:encoded>
    </item>
    
    <item>
      <title>Safer Bash Scripting</title>
      <link>http://blog.asymmetrical-view.com/2009/08/07/bash-argument-handling.html</link>
      <comments>http://blog.asymmetrical-view.com/2009/08/07/bash-argument-handling.html#comments</comments>

      <pubDate>2009-08-07T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2009/08/07/bash-argument-handling.html</guid>

      <id>http://blog.asymmetrical-view.com/2009/08/07/bash-argument-handling</id>
      <description><![CDATA[<p><img src="/images/2009-08/B-2806644149_6cff9a07ee_b-scaled.jpg" style="float: left; padding: 1em; " /></p>
<h1>Safer Bash Scripting</h1>
<p>I was pairing with a colleague today writing a moderately sized <a href="http://en.wikipedia.org/wiki/Shell_script">shell script</a>, during the session some of the best practices I try to follow came up.  There are some best practices I try to follow when programming, be it in <a href="http://en.wikipedia.org/wiki/Shell_script">shell</a> or any other language.  We took a little time to talk about two of the habits I picked up which encouraged me to share them here.  The first has two parts: treating warnings as errors and logging what happens.  The second best practice has to do with clean argument and variable handling in Unix (<a href="http://www.gnu.org/software/bash/">bash</a>) shell scripts.</p>
<h2>Enable <i><b>All</b></i> Warnings</h2>
<p>This is a universal best practice for all my software development.  For <a href="http://gcc.gnu.org/">gcc</a> you can do this by adding <code>-Wall</code> and <code>-Werror</code> which enables all warnings and treats them as errors.  For <a href="http://www.perl.org/">perl</a> you use <code>-w</code>, or within the code, the <code>warnings</code> and <code>strict</code> pragmas.  The additional strictness is more work up front but pays off in not having to debug later.  gcc even goes so far as to ensure your <code>printf</code> format strings have corresponding arguments of the correct type!  As you learn what constitutes an error or warning to the compiler or run-time you will write cleaner code and it will no longer feel like a burden, and whole classes of errors will cease to happen in your software.</p>
<h3>&#8216;<code>set -e</code>&#8217;</h3>
<p><a href="http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html">Bash</a> supports a setting, enabled via <code>set -e</code>, that causes your shell-script to immediately cease if any of the commands you&#8217;ve called return a non-zero exit value back to the shell (a zero exit value is the standard indication of success for a program or command).  Enabling this feature is similar to exception handling, like getting a free &#8216;if this errors, abort the program&#8217;.</p>
<p>As pedagogical example, if you were writing a shell script to create a sub-directory and create a file with the current date and time as its contents, you could easily write:</p>
<pre class="code">
kyleburton@indigo64 ~/tmp$ rm -rf logs/
kyleburton@indigo64 ~/tmp$ cat dlog.sh 
mkdir logs
date &gt;&gt; logs/uptime.log
kyleburton@indigo64 ~/tmp$ bash dlog.sh 
kyleburton@indigo64 ~/tmp$ cat logs/uptime.log 
Fri Aug  7 22:30:18 EDT 2009
kyleburton@indigo64 ~/tmp$ bash dlog.sh 
mkdir: cannot create directory `logs': File exists
kyleburton@indigo64 ~/tmp$ cat logs/uptime.log 
Fri Aug  7 22:30:18 EDT 2009
Fri Aug  7 22:30:21 EDT 2009
kyleburton@indigo64 ~/tmp$ 
</pre>
<p>This would work every time it was run (permissions problems and insufficient disk space not withstanding).  The second time it was run though, and every subsequent time, the <code>mkdir</code> program will error informing you the logs directory already exists.  With the same script, with <code>set -e</code> set, this line will fail immediately, and not append the current date and time to the log file:</p>
<pre class="code">
kyleburton@indigo64 ~/tmp$ cat dlog.sh 
set -e
mkdir logs
date &gt;&gt; logs/uptime.log
kyleburton@indigo64 ~/tmp$ bash dlog.sh 
kyleburton@indigo64 ~/tmp$ cat logs/uptime.log 
Fri Aug  7 22:31:07 EDT 2009
kyleburton@indigo64 ~/tmp$ bash dlog.sh 
mkdir: cannot create directory `logs': File exists
kyleburton@indigo64 ~/tmp$ cat logs/uptime.log 
Fri Aug  7 22:31:07 EDT 2009
kyleburton@indigo64 ~/tmp$ 
</pre>
<p>This protects us against the script continuing and, depending on the behavior and goals of the script, potentially causing damage or corruption.  You could wrap each command in an if/else branch, exiting in the case when the command fails, but the <code>set -e</code> effectively inverts that from having to check for errors as the default behavior to errors aborting processing as the default behavior.</p>
<h3>&#8216;<code>set -x</code>&#8217;</h3>
<p>The second declaration I often use at the top of my scripts is <code>set -x</code>, which causes bash to echo each command that it executes:</p>
<pre class="code">
kyleburton@indigo64 ~/tmp$ cat dlog.sh 
set -x
set -e
mkdir logs
date &gt;&gt; logs/uptime.log
kyleburton@indigo64 ~/tmp$ bash dlog.sh 
+ set -e
+ mkdir logs
+ date
kyleburton@indigo64 ~/tmp$ 
</pre>
<p>Combined with the <a href="http://www.gnu.org/manual/gawk/html_node/Tee-Program.html">tee</a> command, <code>set -x</code> gives you a log of what your bash script (which is a program after all) was trying to do.  These are often invaluable in determining where and why failures have occurred.</p>
<h2>Safe-r Variable Handling</h2>
<p>Bash scripts, almost by definition, call other programs, some of them bash scripts.  With any but the most trivial bash scripts, you will also encounter variables.  The main gotcha with variables and the shell is the way argument parsing takes place.  The default is to use spaces to separate arguments, which if you&#8217;re not careful about how you handle your variables, can cause them to be parsed in unexpected ways.  You protect against this by wrapping your variable usage with double quotes.  You must be diligent about this, anywhere you see a dollar-sign, it should be wrapped in double quotes.</p>
<p><img src="/images/2009-08/shell.png" style="float: right; padding: 1em; " /></p>
<p>In the case of a bash script wanting to pass its arguments on to another program without modification (perhaps you&#8217;re writing a wrapper script to log timing information or log other information about the execution), you use <code>$@</code> to refer to all of the command line arguments.  To pass them on with no additional accidental parsing, you just surround it with double quotes (<code>"$@"</code>) as in the following example.  Here we have 2 scripts, the first calls the second, first without the double quotes and then again with the double quotes:</p>
<pre class="code">

kyleburton@indigo64 ~/tmp$ cat first.sh
set -e
bash second.sh not $@
bash second.sh with "$@"

kyleburton@indigo64 ~/tmp$ cat second.sh
set -e
echo 1 = $1
echo 2 = $2
echo 3 = $3
echo 4 = $4
echo 5 = $5
echo 6 = $6
echo 7 = $7
echo ""

kyleburton@indigo64 ~/tmp$ bash first.sh 1 2 "three for five"
1 = not
2 = 1
3 = 2
4 = three
5 = for
6 = five
7 =

1 = with
2 = 1
3 = 2
4 = three for five
5 =
6 =
7 =

kyleburton@indigo64 ~/tmp$
</pre>
<p><img src="/images/2009-08/J-2806802177_3c32cec9dc_b-scaled.jpg" style="float: right; padding: 1em; " /></p>
<p>The first invocation of second.sh from first.sh does not use the quotes, which causes bash to re-parse the arguments within the first.sh script.  Resulting in <code>"three four five"</code> being split into 3 distinct parameters to be passed to second.sh.  In the second case, using <code>"$@"</code>, the atomicity of the argument is preserved.</p>
<h2>Conclusion</h2>
<p>Writing robust bash shell scripts is helped significantly through the enabling of error checking as well as being diligent when using and passing command line arguments.  I hope these tips help you in your scripting.</p>
<p class="meta">Kyle Burton, 7th August 2009 &#8211; Wayne PA</p>
<h3>Thanks</h3>
<p>Special thanks to <a href="http://plpatterns.com/">Jonathan Tran</a>, and <a href="http://www.leftrightfold.com/">Aaron Feng</a> for reading drafts and providing feedback and suggestions.</p>
<h5>Photo Credits</h5>
<ul>
	<li><a href="http://www.flickr.com/photos/takomabibelot/2806644149/">B &#8216;Script&#8217;</a></li>
	<li><a href="http://www.flickr.com/photos/takomabibelot/2806802177/">J &#8216;Script&#8217;</a></li>
	<li><a href="http://asymmetrical-view.com/about/">shell</a></li>
</ul>]]></description>
      <content:encoded><![CDATA[<p><img src="/images/2009-08/B-2806644149_6cff9a07ee_b-scaled.jpg" style="float: left; padding: 1em; " /></p>
<h1>Safer Bash Scripting</h1>
<p>I was pairing with a colleague today writing a moderately sized <a href="http://en.wikipedia.org/wiki/Shell_script">shell script</a>, during the session some of the best practices I try to follow came up.  There are some best practices I try to follow when programming, be it in <a href="http://en.wikipedia.org/wiki/Shell_script">shell</a> or any other language.  We took a little time to talk about two of the habits I picked up which encouraged me to share them here.  The first has two parts: treating warnings as errors and logging what happens.  The second best practice has to do with clean argument and variable handling in Unix (<a href="http://www.gnu.org/software/bash/">bash</a>) shell scripts.</p>
<h2>Enable <i><b>All</b></i> Warnings</h2>
<p>This is a universal best practice for all my software development.  For <a href="http://gcc.gnu.org/">gcc</a> you can do this by adding <code>-Wall</code> and <code>-Werror</code> which enables all warnings and treats them as errors.  For <a href="http://www.perl.org/">perl</a> you use <code>-w</code>, or within the code, the <code>warnings</code> and <code>strict</code> pragmas.  The additional strictness is more work up front but pays off in not having to debug later.  gcc even goes so far as to ensure your <code>printf</code> format strings have corresponding arguments of the correct type!  As you learn what constitutes an error or warning to the compiler or run-time you will write cleaner code and it will no longer feel like a burden, and whole classes of errors will cease to happen in your software.</p>
<h3>&#8216;<code>set -e</code>&#8217;</h3>
<p><a href="http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html">Bash</a> supports a setting, enabled via <code>set -e</code>, that causes your shell-script to immediately cease if any of the commands you&#8217;ve called return a non-zero exit value back to the shell (a zero exit value is the standard indication of success for a program or command).  Enabling this feature is similar to exception handling, like getting a free &#8216;if this errors, abort the program&#8217;.</p>
<p>As pedagogical example, if you were writing a shell script to create a sub-directory and create a file with the current date and time as its contents, you could easily write:</p>
<pre class="code">
kyleburton@indigo64 ~/tmp$ rm -rf logs/
kyleburton@indigo64 ~/tmp$ cat dlog.sh 
mkdir logs
date &gt;&gt; logs/uptime.log
kyleburton@indigo64 ~/tmp$ bash dlog.sh 
kyleburton@indigo64 ~/tmp$ cat logs/uptime.log 
Fri Aug  7 22:30:18 EDT 2009
kyleburton@indigo64 ~/tmp$ bash dlog.sh 
mkdir: cannot create directory `logs': File exists
kyleburton@indigo64 ~/tmp$ cat logs/uptime.log 
Fri Aug  7 22:30:18 EDT 2009
Fri Aug  7 22:30:21 EDT 2009
kyleburton@indigo64 ~/tmp$ 
</pre>
<p>This would work every time it was run (permissions problems and insufficient disk space not withstanding).  The second time it was run though, and every subsequent time, the <code>mkdir</code> program will error informing you the logs directory already exists.  With the same script, with <code>set -e</code> set, this line will fail immediately, and not append the current date and time to the log file:</p>
<pre class="code">
kyleburton@indigo64 ~/tmp$ cat dlog.sh 
set -e
mkdir logs
date &gt;&gt; logs/uptime.log
kyleburton@indigo64 ~/tmp$ bash dlog.sh 
kyleburton@indigo64 ~/tmp$ cat logs/uptime.log 
Fri Aug  7 22:31:07 EDT 2009
kyleburton@indigo64 ~/tmp$ bash dlog.sh 
mkdir: cannot create directory `logs': File exists
kyleburton@indigo64 ~/tmp$ cat logs/uptime.log 
Fri Aug  7 22:31:07 EDT 2009
kyleburton@indigo64 ~/tmp$ 
</pre>
<p>This protects us against the script continuing and, depending on the behavior and goals of the script, potentially causing damage or corruption.  You could wrap each command in an if/else branch, exiting in the case when the command fails, but the <code>set -e</code> effectively inverts that from having to check for errors as the default behavior to errors aborting processing as the default behavior.</p>
<h3>&#8216;<code>set -x</code>&#8217;</h3>
<p>The second declaration I often use at the top of my scripts is <code>set -x</code>, which causes bash to echo each command that it executes:</p>
<pre class="code">
kyleburton@indigo64 ~/tmp$ cat dlog.sh 
set -x
set -e
mkdir logs
date &gt;&gt; logs/uptime.log
kyleburton@indigo64 ~/tmp$ bash dlog.sh 
+ set -e
+ mkdir logs
+ date
kyleburton@indigo64 ~/tmp$ 
</pre>
<p>Combined with the <a href="http://www.gnu.org/manual/gawk/html_node/Tee-Program.html">tee</a> command, <code>set -x</code> gives you a log of what your bash script (which is a program after all) was trying to do.  These are often invaluable in determining where and why failures have occurred.</p>
<h2>Safe-r Variable Handling</h2>
<p>Bash scripts, almost by definition, call other programs, some of them bash scripts.  With any but the most trivial bash scripts, you will also encounter variables.  The main gotcha with variables and the shell is the way argument parsing takes place.  The default is to use spaces to separate arguments, which if you&#8217;re not careful about how you handle your variables, can cause them to be parsed in unexpected ways.  You protect against this by wrapping your variable usage with double quotes.  You must be diligent about this, anywhere you see a dollar-sign, it should be wrapped in double quotes.</p>
<p><img src="/images/2009-08/shell.png" style="float: right; padding: 1em; " /></p>
<p>In the case of a bash script wanting to pass its arguments on to another program without modification (perhaps you&#8217;re writing a wrapper script to log timing information or log other information about the execution), you use <code>$@</code> to refer to all of the command line arguments.  To pass them on with no additional accidental parsing, you just surround it with double quotes (<code>"$@"</code>) as in the following example.  Here we have 2 scripts, the first calls the second, first without the double quotes and then again with the double quotes:</p>
<pre class="code">

kyleburton@indigo64 ~/tmp$ cat first.sh
set -e
bash second.sh not $@
bash second.sh with "$@"

kyleburton@indigo64 ~/tmp$ cat second.sh
set -e
echo 1 = $1
echo 2 = $2
echo 3 = $3
echo 4 = $4
echo 5 = $5
echo 6 = $6
echo 7 = $7
echo ""

kyleburton@indigo64 ~/tmp$ bash first.sh 1 2 "three for five"
1 = not
2 = 1
3 = 2
4 = three
5 = for
6 = five
7 =

1 = with
2 = 1
3 = 2
4 = three for five
5 =
6 =
7 =

kyleburton@indigo64 ~/tmp$
</pre>
<p><img src="/images/2009-08/J-2806802177_3c32cec9dc_b-scaled.jpg" style="float: right; padding: 1em; " /></p>
<p>The first invocation of second.sh from first.sh does not use the quotes, which causes bash to re-parse the arguments within the first.sh script.  Resulting in <code>"three four five"</code> being split into 3 distinct parameters to be passed to second.sh.  In the second case, using <code>"$@"</code>, the atomicity of the argument is preserved.</p>
<h2>Conclusion</h2>
<p>Writing robust bash shell scripts is helped significantly through the enabling of error checking as well as being diligent when using and passing command line arguments.  I hope these tips help you in your scripting.</p>
<p class="meta">Kyle Burton, 7th August 2009 &#8211; Wayne PA</p>
<h3>Thanks</h3>
<p>Special thanks to <a href="http://plpatterns.com/">Jonathan Tran</a>, and <a href="http://www.leftrightfold.com/">Aaron Feng</a> for reading drafts and providing feedback and suggestions.</p>
<h5>Photo Credits</h5>
<ul>
	<li><a href="http://www.flickr.com/photos/takomabibelot/2806644149/">B &#8216;Script&#8217;</a></li>
	<li><a href="http://www.flickr.com/photos/takomabibelot/2806802177/">J &#8216;Script&#8217;</a></li>
	<li><a href="http://asymmetrical-view.com/about/">shell</a></li>
</ul>]]></content:encoded>
    </item>
    
    <item>
      <title>Departure</title>
      <link>http://blog.asymmetrical-view.com/2009/07/19/departure.html</link>
      <comments>http://blog.asymmetrical-view.com/2009/07/19/departure.html#comments</comments>

      <pubDate>2009-07-19T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2009/07/19/departure.html</guid>

      <id>http://blog.asymmetrical-view.com/2009/07/19/departure</id>
      <description><![CDATA[<h1>Departure</h1>
<p>I recently moved on from a company I was with for eight years (my longest time at any one company).  My experience at <span class="caps">HMS</span> was absolutely without equal.  I was given better opportunities than I could have reasonably asked for.  I grew both professionally and personally, and both of my children were born while I was with <span class="caps">HMS</span>.  I was presented with what I believe to be an unique situation and did not make the decision to leave lightly.  I know they will continue to do great things.  Based on some of the feedback I received from friends I&#8217;ve decided to share the email I sent to them as I departed.</p>
<p class="meta">Kyle Burton, 17th July 2009 &#8211; King of Prussia PA</p>
<h2>You&#8217;ll have to&#8230;</h2>
<p>&#8230;do the enthusiastic white boarding; come up with the snide nick names, and make bad puns.  I won&#8217;t be here to do it.</p>
<p>Don&#8217;t be afraid to fail.  Don&#8217;t be afraid that you might not know it all.  Try.</p>
<p>You are all phenomenal at the technical aspect of what you do for <span class="caps">HMS</span>.</p>
<p>If I could give you advice that you&#8217;d follow, it would be this:</p>
<p>Work hard at developing relationships with your peers in the other business units.  They&#8217;re in this as much as you are.  Work to understand the music they have to face standing in front of customers.  Appreciate that you&#8217;re shielded from this.</p>
<p>Learn about every role in the organization: find out what sales faces when presenting what you make; find out what the auditors are validating about the data your systems create.</p>
<p>If you do this, you will find that they will come understand you as you develop empathy for them.  You will be the one has to do it, no one else can do it for you or instead of you.  Do it even if no one else does it back.  If you keep doing it eventually you&#8217;ll see people start to take your lead.</p>
<p>Chaperone your peers across the building.  Walk with them.  Be the one who says lets do it now, lets go see if there over there now.</p>
<p>When you see something you sincerely believe to be exceptional, say so, out loud.  Tell their manager even if that manager is the <span class="caps">CIO</span> or <span class="caps">CEO</span>. You will gain more by doing this than I can possibly tell you.  You will also be surprised at how people will try to live up to the virtues you point out in them.</p>
<p>You are all living through a shared challenge right now.  Realize that what you are doing now is a story; it is a history, it is a rare shared experience.  You have an opportunity to develop deep respect and friendships.  Events like this do not come along often, you may not get the chance again for a long, long time.  You are seeing those around you prove themselves.  As busy as you are, make an effort to see what they are doing.  From what I am seeing it is incredible.</p>
<p>It has been my distinct pleasure working along side each and every one of you.  Thank you for helping me grow these past eight years.</p>
<p>Thank you for being who you are.</p>
<p>Kyle Burton</p>]]></description>
      <content:encoded><![CDATA[<h1>Departure</h1>
<p>I recently moved on from a company I was with for eight years (my longest time at any one company).  My experience at <span class="caps">HMS</span> was absolutely without equal.  I was given better opportunities than I could have reasonably asked for.  I grew both professionally and personally, and both of my children were born while I was with <span class="caps">HMS</span>.  I was presented with what I believe to be an unique situation and did not make the decision to leave lightly.  I know they will continue to do great things.  Based on some of the feedback I received from friends I&#8217;ve decided to share the email I sent to them as I departed.</p>
<p class="meta">Kyle Burton, 17th July 2009 &#8211; King of Prussia PA</p>
<h2>You&#8217;ll have to&#8230;</h2>
<p>&#8230;do the enthusiastic white boarding; come up with the snide nick names, and make bad puns.  I won&#8217;t be here to do it.</p>
<p>Don&#8217;t be afraid to fail.  Don&#8217;t be afraid that you might not know it all.  Try.</p>
<p>You are all phenomenal at the technical aspect of what you do for <span class="caps">HMS</span>.</p>
<p>If I could give you advice that you&#8217;d follow, it would be this:</p>
<p>Work hard at developing relationships with your peers in the other business units.  They&#8217;re in this as much as you are.  Work to understand the music they have to face standing in front of customers.  Appreciate that you&#8217;re shielded from this.</p>
<p>Learn about every role in the organization: find out what sales faces when presenting what you make; find out what the auditors are validating about the data your systems create.</p>
<p>If you do this, you will find that they will come understand you as you develop empathy for them.  You will be the one has to do it, no one else can do it for you or instead of you.  Do it even if no one else does it back.  If you keep doing it eventually you&#8217;ll see people start to take your lead.</p>
<p>Chaperone your peers across the building.  Walk with them.  Be the one who says lets do it now, lets go see if there over there now.</p>
<p>When you see something you sincerely believe to be exceptional, say so, out loud.  Tell their manager even if that manager is the <span class="caps">CIO</span> or <span class="caps">CEO</span>. You will gain more by doing this than I can possibly tell you.  You will also be surprised at how people will try to live up to the virtues you point out in them.</p>
<p>You are all living through a shared challenge right now.  Realize that what you are doing now is a story; it is a history, it is a rare shared experience.  You have an opportunity to develop deep respect and friendships.  Events like this do not come along often, you may not get the chance again for a long, long time.  You are seeing those around you prove themselves.  As busy as you are, make an effort to see what they are doing.  From what I am seeing it is incredible.</p>
<p>It has been my distinct pleasure working along side each and every one of you.  Thank you for helping me grow these past eight years.</p>
<p>Thank you for being who you are.</p>
<p>Kyle Burton</p>]]></content:encoded>
    </item>
    
    <item>
      <title>Array Type Hints in Clojure</title>
      <link>http://blog.asymmetrical-view.com/2009/07/02/clojure-primitive-arrays.html</link>
      <comments>http://blog.asymmetrical-view.com/2009/07/02/clojure-primitive-arrays.html#comments</comments>

      <pubDate>2009-07-02T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2009/07/02/clojure-primitive-arrays.html</guid>

      <id>http://blog.asymmetrical-view.com/2009/07/02/clojure-primitive-arrays</id>
      <description><![CDATA[<p><img src="/images/2009-07/numerical-types-115805043_c5dac1db3c_b.jpg" style="float: left; padding: 1em; " /></p>
<h1>Array Type Hints in Clojure</h1>
<p>How to encode type hints for Java array types came up recently in conversation with a friend and I found it difficult to <a href="http://gootle.com/">Google</a> for so I decided to write it up here.  This is because Java doesn&#8217;t have what you&#8217;d normally think of as a class name for its typed arrays, but first a brief explanation of type hints&#8230;</p>
<h2>Clojure Type Hints</h2>
<p><a href="http://clojure.org/">Clojure</a> allows you to use type declarations, or <a href="http://clojure.org/java_interop#toc35">hints</a>, in two ways.  The first are declarations to the <a href="http://clojure.org/">Clojure</a> compiler which aid in function signature checking.  Type-hinted code will be faster in many cases (when the type was otherwise ambiguous to the compiler) because the <a href="http://clojure.org/">Clojure</a> run-time doesn&#8217;t have to spend time using <a href="http://java.sun.com/docs/books/tutorial/reflect/index.html">Java&#8217;s Reflection <span class="caps">API</span></a> to figure out which underlying method is appropriate for the type of your arguments.  The second aspect of where types used in Clojure is in <a href="http://clojure.org/multimethods">multi-methods</a>, where the types of the arguments are typically used in determining how method resolution is performed.</p>
<div style="clear: left; padding-top: 10px;"></div>
<p>You can see Clojure doing reflective lookups by setting <code>*warn-on-reflection*</code> to <code>true</code>.  Having this set to true while you run your unit tests, or at the end of your development pushes, is a good habit to get into since the performance impact of all the default reflective look-ups is a good thing to eliminate out of your code once things are stable.</p>
<p>Enabling those warnings produces errors that look like this:</p>
<pre class="code">

user&gt; (set! *warn-on-reflection* true)
true
user&gt; (def x (StringBuilder.))
#'user/x
user&gt; (.append x "foo")
Reflection warning, NO_SOURCE_PATH:1 - call to append can't be resolved.
#&lt;StringBuilder foo&gt;
user&gt; (.append x 1)
Reflection warning, NO_SOURCE_PATH:1 - call to append can't be resolved.
#&lt;StringBuilder foo1&gt;
user&gt; 
user&gt; (defn second-ch [s]
        (.charAt s 1))
Reflection warning, NO_SOURCE_PATH:2 - call to charAt can't be resolved.
#'user/second-ch
user&gt; (second-ch "twenty")
\w
user&gt; 

</pre>
<p>Note that the warning happened at the time the function was compiled, not when it is called.  Clojure is warning us that it couldn&#8217;t generate code to call the method directly, but it had to generate code that used the reflection <span class="caps">API</span> to first find the proper method to call and then call it.   We can avoid the expensive reflective look-up and quiet warning by introducing a type-hint for the parameter, telling Clojure that it is a String:</p>
<pre class="code">
user&gt; (defn second-ch [#^String s]
        (.charAt s 1))
#'user/second-ch
user&gt; (second-ch "thirty")
\h
user&gt; 
</pre>
<p>This time there is no warning and the generated code will call <code>charAt</code> directly.</p>
<h2>Multimethods</h2>
<p>Multimethods are the other area where the annotations frequently come into play.  There are 2 steps to defining a basic multimethod.  The first is the <code>defmulti</code> declaration where you name the multi-method and you then provide a function which Clojure will use to dispatch the call to one of the multi-method instances you later declare.  One of the most common dispatch functions is <code>class</code>, which will match up the Java class of the argument to the one declared in the <code>defmethod</code>.</p>
<p>This example declares a multimethod that takes either a String or an Integer:</p>
<pre class="code">

user&gt; (defmulti bar class)
#'user/bar
user&gt; (defmethod bar String  [s] (str "the-str:" s))
#&lt;MultiFn clojure.lang.MultiFn@2e239525&gt;
user&gt; (defmethod bar Integer [s] (str "the-int:" s))
#&lt;MultiFn clojure.lang.MultiFn@2e239525&gt;
user&gt; (bar "this")
"the-str:this"
user&gt; (bar 123)
"the-int:123"
user&gt; 

</pre>
<p>And if you attempt a call with an argument that doesn&#8217;t match any of the declarations:</p>
<pre class="code">
user&gt; (bar 4.56)
; Evaluation aborted.
No method in multimethod 'bar' for dispatch value: class java.lang.Double
  [Thrown class java.lang.IllegalArgumentException]
...
</pre>
<p>That&#8217;s effectively what <a href="http://github.com/kyleburton/krbemacs/tree">Emacs, Slime and Clojure</a> report to me.</p>
<p>There are more nuances to multimethods, like specifying defaults, handling multiple arguments and using your own dispatch functions &#8211; for now, the <a href="http://clojure.org/multimethods">documentation</a> is probably the best place to find out more.</p>
<p><img src="/images/2009-07/led-array-2245492155_795395b056_o.jpg" style="float: right; padding: 1em; " /></p>
<h2>Arrays and Class Names</h2>
<p>So, back to why we&#8217;re here.  As you start using type hints you may (as I did) run into a situation where you want to use a hint for a situation where you have a typed array, or as a dispatching value in multimethods.  Javadoc presents these as <code>Type[]</code> and that is how you encode them in your Java source code.  The problem, though, is that that&#8217;s not what the byte-code or <span class="caps">JVM</span> calls it at run-time, and what it does call it is not syntatically valid in either your Java or Clojure source code.</p>
<div style="clear: both;">
<p>So what are typed arrays called in Java?  Lets ask Java what they&#8217;re called&#8230;you can find out what a String array is called with this bit of example code:</p>
</div>
<pre class="code">
kyleburton@indigo64 ~$ cat Test.java
public class Test {
  public static void main(String [] args) {
    System.out.println("String array: " + args.getClass());
    System.out.println("Byte Array: " + "foo".getBytes().getClass());
  }
}
kyleburton@indigo64 ~$ javac Test.java
kyleburton@indigo64 ~$ java Test
String array: class [Ljava.lang.String;
Byte Array: class [B
kyleburton@indigo64 ~$ 
</pre>
<p>You can get the same information from the Clojure <span class="caps">REPL</span> as well by using Clojure&#8217;s <code>into-array</code>:</p>
<pre class="code">
user&gt; (class (into-array ["a"]))
[Ljava.lang.String;
user&gt; (class (.getBytes "foo"))
[B
user&gt; 
</pre>
<p>So you now know how to ask for the class name of an array you have an instance of.  You can use this to ask <code>Class</code> for the class based on its name (as a String):</p>
<pre class="code">
user&gt; (Class/forName "[B")
[B
user&gt; (Class/forName "[Ljava.lang.String;")
[Ljava.lang.String;
user&gt; 
</pre>
<p>Of course Clojure supports this for primitive types by pluralizing the primitive type:</p>
<pre class="code">
user&gt; (defn foo [#^bytes b] (String. b))
</pre>
<p>That approach doesn&#8217;t work for non-primitive types (classes) though.</p>
<h2>Java Array Type Hints</h2>
<p>Putting these together we can now declare <code>defmethod</code>s using either of these techniques.  Asking the <span class="caps">JVM</span> what the the class is based on a hard-coded example value looks like this:</p>
<pre class="code">

user&gt; (defmethod bar (class (into-array String [])) [s]
        (str "the-string[]:" s))
#&lt;MultiFn clojure.lang.MultiFn@70e8fdc9&gt;
user&gt; (bar (into-array String ["a" "b"]))
"the-string[]:[Ljava.lang.String;@14f3cf72"

</pre>
<p>Using a hard-coded string of the class name as the <span class="caps">JVM</span> sees it (which also works for the primitive types) looks like the following:</p>
<pre class="code">

user&gt; (defmethod bar (Class/forName "[Ljava.lang.String;") [s]
        (str "the-string[]:" s))
#&lt;MultiFn clojure.lang.MultiFn@70e8fdc9&gt;
user&gt; (bar (into-array String ["b" "c"]))
"the-string[]:[Ljava.lang.String;@4597871d"
user&gt; 

user&gt; (defmethod bar (Class/forName "[B") [s] ;; same as #^bytes
        (str "the-bytes:" s))
#&lt;MultiFn clojure.lang.MultiFn@70e8fdc9&gt;
user&gt; (bar (.getBytes "foo"))
"the-bytes:[B@7eedec92"
user&gt; 

</pre>
<p>Even though this works, I recommend staying away from hard-coding the string representation and using <code>Class/forName</code>.  I worry that it might change in a future <span class="caps">JVM</span> release, breaking the code.</p>
<h2>Conclusion</h2>
<p>Even though Clojure does not have direct syntax support for hints for Java arrays, it&#8217;s still possible to use them.</p>
<p class="meta">Kyle Burton, 14th July 2009 &#8211; Wayne PA</p>
<h3>Thanks</h3>
<p>Special thanks to <a href="http://plpatterns.com/">Jonathan Tran</a>, and <a href="http://www.linkedin.com/pub/mike-delaurentis/a/847/b80">Mike DeLaurentis</a> for reading drafts and providing feedback and suggestions.</p>
<h5>Photo Credits</h5>
<ul>
	<li><a href="http://www.flickr.com/photos/threedots/115805043/">Numerical Types</a></li>
	<li><a href="http://www.flickr.com/photos/cibomahto/2245492155/"><span class="caps">LED</span> Array</a></li>
</ul>]]></description>
      <content:encoded><![CDATA[<p><img src="/images/2009-07/numerical-types-115805043_c5dac1db3c_b.jpg" style="float: left; padding: 1em; " /></p>
<h1>Array Type Hints in Clojure</h1>
<p>How to encode type hints for Java array types came up recently in conversation with a friend and I found it difficult to <a href="http://gootle.com/">Google</a> for so I decided to write it up here.  This is because Java doesn&#8217;t have what you&#8217;d normally think of as a class name for its typed arrays, but first a brief explanation of type hints&#8230;</p>
<h2>Clojure Type Hints</h2>
<p><a href="http://clojure.org/">Clojure</a> allows you to use type declarations, or <a href="http://clojure.org/java_interop#toc35">hints</a>, in two ways.  The first are declarations to the <a href="http://clojure.org/">Clojure</a> compiler which aid in function signature checking.  Type-hinted code will be faster in many cases (when the type was otherwise ambiguous to the compiler) because the <a href="http://clojure.org/">Clojure</a> run-time doesn&#8217;t have to spend time using <a href="http://java.sun.com/docs/books/tutorial/reflect/index.html">Java&#8217;s Reflection <span class="caps">API</span></a> to figure out which underlying method is appropriate for the type of your arguments.  The second aspect of where types used in Clojure is in <a href="http://clojure.org/multimethods">multi-methods</a>, where the types of the arguments are typically used in determining how method resolution is performed.</p>
<div style="clear: left; padding-top: 10px;"></div>
<p>You can see Clojure doing reflective lookups by setting <code>*warn-on-reflection*</code> to <code>true</code>.  Having this set to true while you run your unit tests, or at the end of your development pushes, is a good habit to get into since the performance impact of all the default reflective look-ups is a good thing to eliminate out of your code once things are stable.</p>
<p>Enabling those warnings produces errors that look like this:</p>
<pre class="code">

user&gt; (set! *warn-on-reflection* true)
true
user&gt; (def x (StringBuilder.))
#'user/x
user&gt; (.append x "foo")
Reflection warning, NO_SOURCE_PATH:1 - call to append can't be resolved.
#&lt;StringBuilder foo&gt;
user&gt; (.append x 1)
Reflection warning, NO_SOURCE_PATH:1 - call to append can't be resolved.
#&lt;StringBuilder foo1&gt;
user&gt; 
user&gt; (defn second-ch [s]
        (.charAt s 1))
Reflection warning, NO_SOURCE_PATH:2 - call to charAt can't be resolved.
#'user/second-ch
user&gt; (second-ch "twenty")
\w
user&gt; 

</pre>
<p>Note that the warning happened at the time the function was compiled, not when it is called.  Clojure is warning us that it couldn&#8217;t generate code to call the method directly, but it had to generate code that used the reflection <span class="caps">API</span> to first find the proper method to call and then call it.   We can avoid the expensive reflective look-up and quiet warning by introducing a type-hint for the parameter, telling Clojure that it is a String:</p>
<pre class="code">
user&gt; (defn second-ch [#^String s]
        (.charAt s 1))
#'user/second-ch
user&gt; (second-ch "thirty")
\h
user&gt; 
</pre>
<p>This time there is no warning and the generated code will call <code>charAt</code> directly.</p>
<h2>Multimethods</h2>
<p>Multimethods are the other area where the annotations frequently come into play.  There are 2 steps to defining a basic multimethod.  The first is the <code>defmulti</code> declaration where you name the multi-method and you then provide a function which Clojure will use to dispatch the call to one of the multi-method instances you later declare.  One of the most common dispatch functions is <code>class</code>, which will match up the Java class of the argument to the one declared in the <code>defmethod</code>.</p>
<p>This example declares a multimethod that takes either a String or an Integer:</p>
<pre class="code">

user&gt; (defmulti bar class)
#'user/bar
user&gt; (defmethod bar String  [s] (str "the-str:" s))
#&lt;MultiFn clojure.lang.MultiFn@2e239525&gt;
user&gt; (defmethod bar Integer [s] (str "the-int:" s))
#&lt;MultiFn clojure.lang.MultiFn@2e239525&gt;
user&gt; (bar "this")
"the-str:this"
user&gt; (bar 123)
"the-int:123"
user&gt; 

</pre>
<p>And if you attempt a call with an argument that doesn&#8217;t match any of the declarations:</p>
<pre class="code">
user&gt; (bar 4.56)
; Evaluation aborted.
No method in multimethod 'bar' for dispatch value: class java.lang.Double
  [Thrown class java.lang.IllegalArgumentException]
...
</pre>
<p>That&#8217;s effectively what <a href="http://github.com/kyleburton/krbemacs/tree">Emacs, Slime and Clojure</a> report to me.</p>
<p>There are more nuances to multimethods, like specifying defaults, handling multiple arguments and using your own dispatch functions &#8211; for now, the <a href="http://clojure.org/multimethods">documentation</a> is probably the best place to find out more.</p>
<p><img src="/images/2009-07/led-array-2245492155_795395b056_o.jpg" style="float: right; padding: 1em; " /></p>
<h2>Arrays and Class Names</h2>
<p>So, back to why we&#8217;re here.  As you start using type hints you may (as I did) run into a situation where you want to use a hint for a situation where you have a typed array, or as a dispatching value in multimethods.  Javadoc presents these as <code>Type[]</code> and that is how you encode them in your Java source code.  The problem, though, is that that&#8217;s not what the byte-code or <span class="caps">JVM</span> calls it at run-time, and what it does call it is not syntatically valid in either your Java or Clojure source code.</p>
<div style="clear: both;">
<p>So what are typed arrays called in Java?  Lets ask Java what they&#8217;re called&#8230;you can find out what a String array is called with this bit of example code:</p>
</div>
<pre class="code">
kyleburton@indigo64 ~$ cat Test.java
public class Test {
  public static void main(String [] args) {
    System.out.println("String array: " + args.getClass());
    System.out.println("Byte Array: " + "foo".getBytes().getClass());
  }
}
kyleburton@indigo64 ~$ javac Test.java
kyleburton@indigo64 ~$ java Test
String array: class [Ljava.lang.String;
Byte Array: class [B
kyleburton@indigo64 ~$ 
</pre>
<p>You can get the same information from the Clojure <span class="caps">REPL</span> as well by using Clojure&#8217;s <code>into-array</code>:</p>
<pre class="code">
user&gt; (class (into-array ["a"]))
[Ljava.lang.String;
user&gt; (class (.getBytes "foo"))
[B
user&gt; 
</pre>
<p>So you now know how to ask for the class name of an array you have an instance of.  You can use this to ask <code>Class</code> for the class based on its name (as a String):</p>
<pre class="code">
user&gt; (Class/forName "[B")
[B
user&gt; (Class/forName "[Ljava.lang.String;")
[Ljava.lang.String;
user&gt; 
</pre>
<p>Of course Clojure supports this for primitive types by pluralizing the primitive type:</p>
<pre class="code">
user&gt; (defn foo [#^bytes b] (String. b))
</pre>
<p>That approach doesn&#8217;t work for non-primitive types (classes) though.</p>
<h2>Java Array Type Hints</h2>
<p>Putting these together we can now declare <code>defmethod</code>s using either of these techniques.  Asking the <span class="caps">JVM</span> what the the class is based on a hard-coded example value looks like this:</p>
<pre class="code">

user&gt; (defmethod bar (class (into-array String [])) [s]
        (str "the-string[]:" s))
#&lt;MultiFn clojure.lang.MultiFn@70e8fdc9&gt;
user&gt; (bar (into-array String ["a" "b"]))
"the-string[]:[Ljava.lang.String;@14f3cf72"

</pre>
<p>Using a hard-coded string of the class name as the <span class="caps">JVM</span> sees it (which also works for the primitive types) looks like the following:</p>
<pre class="code">

user&gt; (defmethod bar (Class/forName "[Ljava.lang.String;") [s]
        (str "the-string[]:" s))
#&lt;MultiFn clojure.lang.MultiFn@70e8fdc9&gt;
user&gt; (bar (into-array String ["b" "c"]))
"the-string[]:[Ljava.lang.String;@4597871d"
user&gt; 

user&gt; (defmethod bar (Class/forName "[B") [s] ;; same as #^bytes
        (str "the-bytes:" s))
#&lt;MultiFn clojure.lang.MultiFn@70e8fdc9&gt;
user&gt; (bar (.getBytes "foo"))
"the-bytes:[B@7eedec92"
user&gt; 

</pre>
<p>Even though this works, I recommend staying away from hard-coding the string representation and using <code>Class/forName</code>.  I worry that it might change in a future <span class="caps">JVM</span> release, breaking the code.</p>
<h2>Conclusion</h2>
<p>Even though Clojure does not have direct syntax support for hints for Java arrays, it&#8217;s still possible to use them.</p>
<p class="meta">Kyle Burton, 14th July 2009 &#8211; Wayne PA</p>
<h3>Thanks</h3>
<p>Special thanks to <a href="http://plpatterns.com/">Jonathan Tran</a>, and <a href="http://www.linkedin.com/pub/mike-delaurentis/a/847/b80">Mike DeLaurentis</a> for reading drafts and providing feedback and suggestions.</p>
<h5>Photo Credits</h5>
<ul>
	<li><a href="http://www.flickr.com/photos/threedots/115805043/">Numerical Types</a></li>
	<li><a href="http://www.flickr.com/photos/cibomahto/2245492155/"><span class="caps">LED</span> Array</a></li>
</ul>]]></content:encoded>
    </item>
    
    <item>
      <title>Creating Executable Jars For Your Clojure Application</title>
      <link>http://blog.asymmetrical-view.com/2009/06/22/executable-clojure-jars.html</link>
      <comments>http://blog.asymmetrical-view.com/2009/06/22/executable-clojure-jars.html#comments</comments>

      <pubDate>2009-06-22T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2009/06/22/executable-clojure-jars.html</guid>

      <id>http://blog.asymmetrical-view.com/2009/06/22/executable-clojure-jars</id>
      <description><![CDATA[<h1>Creating Executable Jars For Your Clojure Application</h1>
<p><img src="/images/2009-06/green-glowing-jar.jpg" style="float: left; margin-right: 1em; " /></p>
<p>It is possible to create stand alone executable <a href="http://en.wikipedia.org/wiki/JAR_(file_format%29">Jar</a> files for your <a href="http://clojure.org/">Clojure</a> programs.  In this post I walk you through the issues you need to keep in mind and the steps you need to take to create the jar.  You can download the example code this post walks through in its entirety from my <a href="http://github.com/kyleburton/sandbox/tree/master">GitHub</a> account (under examples/exec-jar).</p>
<p>I used <a href="http://ant.apache.org/">ant</a> to build the jar, other <a href="http://maven.apache.org/">Java development tools</a> can also do the task.</p>
<h3>Jar Files</h3>
<p>Jar files are <a href="http://en.wikipedia.org/wiki/ZIP_(file_format%29">Zip</a> files with a few conventions for what goes where and of their contents.  Jar files support a <a href="http://en.wikipedia.org/wiki/Manifest_file">Manifest File</a> file which tells Java what the archive contains.  The manifest file has a simple format of key/value pairs, very similar to an <span class="caps">HTTP</span> header.  This is manifest for the Clojure Jar:</p>
<pre class="code">
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.1
Created-By: 11.2-b01 (Sun Microsystems Inc.)
Main-Class: clojure.main
Class-Path: .
</pre>
<p>The important bit there is &#8216;Main-Class&#8217;.  The Main-Class specifies the Java class that will be executed by default when run as <code>java -jar clojure.jar</code>.  In <code>clojure.jar</code> the main class is <code>clojure.main</code>.</p>
<h3>Clojure Application</h3>
<p>The example application performs a <a href="http://google.com/">Google</a> search, printing each link and its text:</p>
<pre class="code">

(ns com.github.kyleburton.app
  (:gen-class)
  (:use [com.github.kyleburton.sandbox.web :as kweb]
        [com.github.kyleburton.sandbox.landmark-parser :as lp]
        [clojure.contrib.str-utils :as str-utils]))

(defn fetch-page [terms]
  (let [page (kweb/get-&gt;string (format "http://www.google.com/search?q=%s" (str-utils/str-join "+" terms)))]
    (doseq [link (filter #(.contains % "class=l") (lp/html-&gt;anchors page))]
      (let [href (lp/anchor-&gt;href link)
            text (kweb/strip-html (lp/anchor-&gt;body link))]
        (println text)
        (println href)
        (println "\n")))))

(defn show-help []
  (pritnln
   "app term [term2 [term3 ...]]

Performs a Google Search for the given terms

"))

(defn -main [&amp; terms]
  (cond (empty? terms)
        (show-help)
        true
        (fetch-page terms)))



</pre>
<h3>Compilation</h3>
<p>Java will only run Java byte code so we need to compile the application.  I&#8217;ve set up the <code>build.xml</code> to do so:</p>
<pre class="code">

  &lt;target name="compile" description="Run the Clojure Compiler"&gt;
    &lt;property name="cpath" refid="classpath" /&gt;
    &lt;echo message="cpath=${cpath}" /&gt;
    &lt;mkdir dir="${classes.dir}"/&gt;
    &lt;java classname="clojure.lang.Compile" fork="true"&gt;
      &lt;sysproperty key="clojure.compile.path" value="${classes.dir}" /&gt;
      &lt;classpath refid="classpath" /&gt;
      &lt;arg value="com.github.kyleburton.app" /&gt;
    &lt;/java&gt;
  &lt;/target&gt;

</pre>
<p>The <code>jar-with-manifest</code> then uses the compiled classes, generates a manifest file and uses <a href="http://ant.apache.org/">Ant&#8217;s</a> <code>jar</code> task with a series of <code>zipfileset</code>s to combine the clojure, clojure-contrib and other dependency&#8217;s jars into a single, executable, jar:</p>
<pre class="code">

  &lt;target name="jar-with-manifest" depends="compile" description="Build the JAR"&gt;
    &lt;manifest file="${target.dir}/MANIFEST.MF"&gt;
      &lt;attribute name="Built-By" value="${user.name}" /&gt;
      &lt;attribute name="Main-Class" value="com.github.kyleburton.app" /&gt;
    &lt;/manifest&gt;
    &lt;jar jarfile="${target.dir}/${jar.file.name}" manifest="${target.dir}/MANIFEST.MF"&gt;
      &lt;fileset dir="${classes.dir}" includes="**/*.class"/&gt;
      &lt;zipfileset src="${clojure.jar}" /&gt;
      &lt;zipfileset src="${clojure-contrib.jar}" /&gt;
      &lt;zipfileset src="${krb-utils.jar.repo}/commons-httpclient-3.1.jar" /&gt;
      &lt;zipfileset src="${krb-utils.jar.repo}/commons-codec-1.3.jar" /&gt;
      &lt;zipfileset src="${krb-utils.jar.repo}//commons-logging-1.1.1.jar" /&gt;
      &lt;zipfileset src="${krb-utils.jar.repo}//commons-logging-1.1.1-sources.jar" /&gt;
      &lt;zipfileset src="${krb-utils.jar.repo}//commons-logging-adapters-1.1.1.jar" /&gt;
      &lt;zipfileset src="${krb-utils.jar.repo}//commons-logging-api-1.1.1.jar" /&gt;
    &lt;/jar&gt;
  &lt;/target&gt;

</pre>
<h3>Running The Application</h3>
<p>Our application can now be run all by itself with <code>java -jar ...</code>:</p>
<pre class="code">

kyleburton@indigo64 exec-jar[master*]$ java -jar target/exec-jar-0.1.jar ant zipfileset

ZipFileSet Type
http://ant.apache.org/manual/CoreTypes/zipfileset.html

Zip Task
http://ant.apache.org/manual/CoreTasks/zip.html

Ant Best Practices: Use ZipFileSet | The Build Doctor
http://www.build-doctor.com/2008/07/13/ant-best-practices-use-zipfileset

Top 15 Ant Best Practices - O&amp;#39;Reilly Media
http://www.onjava.com/pub/a/onjava/2003/12/17/ant_bestpractices.html

&amp;#39;cvs commit: ant/src/main/org/apache/tools/ant/types ZipFileSet ...
http://marc.info/?l=ant-dev&amp;m=112197754500691&amp;w=2

[picocontainer-scm] [CVS java] improved maven scri: msg#00056 java ...
http://osdir.com/ml/java.picocontainer.cvs/2004-07/msg00056.html

ZipFileSet Apache Ant 1.6.5 API Documentation and Javadoc
http://www.jdocs.com/link/org/apache/tools/ant/types/zipfileset.html

svn commit: r719578 - /ant/core/trunk/src/tests/antunit/types ...
http://mail-archives.apache.org/mod_mbox/ant-notifications/200811.mbox/%3C20081121133918.572D2238889E@eris.apache.org%3E

ZipFileSet (Apache Ant API)
http://lia.deis.unibo.it/Courses/TecnologieWeb0607/materiale/laboratorio/ant/api/org/apache/tools/ant/types/ZipFileSet.html

[news.eclipse.platform] Re: Problem with ANT zipfileset ... Re ...
http://dev.eclipse.org/newslists/news.eclipse.platform/msg07778.html

kyleburton@indigo64 exec-jar[master]$ 

</pre>
<h3>Conclusion</h3>
<p><img src="/images/2009-06/glass-jar.jpg" style="float: right; margin-left: 1em; " /></p>
<p>Bundling your application into a single Jar can simplify the deployment, and distribution of your application.  What tends to be less desirable about this technique though is that you have to track your dependencies carefully (you risk <code>ClassNotFoundException</code>s) and the jars you create are often quite large.  You can not add additional jars or paths to the classpath when running <code>java -jar</code>, which means that you won&#8217;t be able to re-use the libraries across other applications.</p>
<p>This technique allows you to create a single file that your users can download to run your clojure based applications.</p>
<p class="meta">Kyle Burton, 28th June 2009 &#8211; Wayne PA</p>
<h4>Links</h4>
<ul>
	<li><a href="http://java.sun.com/docs/books/tutorial/deployment/jar/" title="Sun">Jar Deployment Tutorial</a></li>
	<li><a href="http://java.sun.com/docs/books/tutorial/deployment/jar/manifestindex.html" title="Sun">Manifest Files</a></li>
</ul>
<h5>Photo Credits</h5>
<ul>
	<li><a href="http://www.flickr.com/photos/mmechtley/2110083185/sizes/l/">Green Glowing Jars</a></li>
	<li><a href="http://www.flickr.com/photos/mmechtley/2110083601/sizes/l/in/set-72157603453391346/">Blue Glowing Jars</a></li>
	<li><a href="http://www.flickr.com/photos/pacomexico/3288346239/sizes/l/">Cookie Jar and Orange</a></li>
	<li><a href="http://www.flickr.com/photos/riotjane/2216995811/sizes/l/">Glass Jar</a></li>
</ul>]]></description>
      <content:encoded><![CDATA[<h1>Creating Executable Jars For Your Clojure Application</h1>
<p><img src="/images/2009-06/green-glowing-jar.jpg" style="float: left; margin-right: 1em; " /></p>
<p>It is possible to create stand alone executable <a href="http://en.wikipedia.org/wiki/JAR_(file_format%29">Jar</a> files for your <a href="http://clojure.org/">Clojure</a> programs.  In this post I walk you through the issues you need to keep in mind and the steps you need to take to create the jar.  You can download the example code this post walks through in its entirety from my <a href="http://github.com/kyleburton/sandbox/tree/master">GitHub</a> account (under examples/exec-jar).</p>
<p>I used <a href="http://ant.apache.org/">ant</a> to build the jar, other <a href="http://maven.apache.org/">Java development tools</a> can also do the task.</p>
<h3>Jar Files</h3>
<p>Jar files are <a href="http://en.wikipedia.org/wiki/ZIP_(file_format%29">Zip</a> files with a few conventions for what goes where and of their contents.  Jar files support a <a href="http://en.wikipedia.org/wiki/Manifest_file">Manifest File</a> file which tells Java what the archive contains.  The manifest file has a simple format of key/value pairs, very similar to an <span class="caps">HTTP</span> header.  This is manifest for the Clojure Jar:</p>
<pre class="code">
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.1
Created-By: 11.2-b01 (Sun Microsystems Inc.)
Main-Class: clojure.main
Class-Path: .
</pre>
<p>The important bit there is &#8216;Main-Class&#8217;.  The Main-Class specifies the Java class that will be executed by default when run as <code>java -jar clojure.jar</code>.  In <code>clojure.jar</code> the main class is <code>clojure.main</code>.</p>
<h3>Clojure Application</h3>
<p>The example application performs a <a href="http://google.com/">Google</a> search, printing each link and its text:</p>
<pre class="code">

(ns com.github.kyleburton.app
  (:gen-class)
  (:use [com.github.kyleburton.sandbox.web :as kweb]
        [com.github.kyleburton.sandbox.landmark-parser :as lp]
        [clojure.contrib.str-utils :as str-utils]))

(defn fetch-page [terms]
  (let [page (kweb/get-&gt;string (format "http://www.google.com/search?q=%s" (str-utils/str-join "+" terms)))]
    (doseq [link (filter #(.contains % "class=l") (lp/html-&gt;anchors page))]
      (let [href (lp/anchor-&gt;href link)
            text (kweb/strip-html (lp/anchor-&gt;body link))]
        (println text)
        (println href)
        (println "\n")))))

(defn show-help []
  (pritnln
   "app term [term2 [term3 ...]]

Performs a Google Search for the given terms

"))

(defn -main [&amp; terms]
  (cond (empty? terms)
        (show-help)
        true
        (fetch-page terms)))



</pre>
<h3>Compilation</h3>
<p>Java will only run Java byte code so we need to compile the application.  I&#8217;ve set up the <code>build.xml</code> to do so:</p>
<pre class="code">

  &lt;target name="compile" description="Run the Clojure Compiler"&gt;
    &lt;property name="cpath" refid="classpath" /&gt;
    &lt;echo message="cpath=${cpath}" /&gt;
    &lt;mkdir dir="${classes.dir}"/&gt;
    &lt;java classname="clojure.lang.Compile" fork="true"&gt;
      &lt;sysproperty key="clojure.compile.path" value="${classes.dir}" /&gt;
      &lt;classpath refid="classpath" /&gt;
      &lt;arg value="com.github.kyleburton.app" /&gt;
    &lt;/java&gt;
  &lt;/target&gt;

</pre>
<p>The <code>jar-with-manifest</code> then uses the compiled classes, generates a manifest file and uses <a href="http://ant.apache.org/">Ant&#8217;s</a> <code>jar</code> task with a series of <code>zipfileset</code>s to combine the clojure, clojure-contrib and other dependency&#8217;s jars into a single, executable, jar:</p>
<pre class="code">

  &lt;target name="jar-with-manifest" depends="compile" description="Build the JAR"&gt;
    &lt;manifest file="${target.dir}/MANIFEST.MF"&gt;
      &lt;attribute name="Built-By" value="${user.name}" /&gt;
      &lt;attribute name="Main-Class" value="com.github.kyleburton.app" /&gt;
    &lt;/manifest&gt;
    &lt;jar jarfile="${target.dir}/${jar.file.name}" manifest="${target.dir}/MANIFEST.MF"&gt;
      &lt;fileset dir="${classes.dir}" includes="**/*.class"/&gt;
      &lt;zipfileset src="${clojure.jar}" /&gt;
      &lt;zipfileset src="${clojure-contrib.jar}" /&gt;
      &lt;zipfileset src="${krb-utils.jar.repo}/commons-httpclient-3.1.jar" /&gt;
      &lt;zipfileset src="${krb-utils.jar.repo}/commons-codec-1.3.jar" /&gt;
      &lt;zipfileset src="${krb-utils.jar.repo}//commons-logging-1.1.1.jar" /&gt;
      &lt;zipfileset src="${krb-utils.jar.repo}//commons-logging-1.1.1-sources.jar" /&gt;
      &lt;zipfileset src="${krb-utils.jar.repo}//commons-logging-adapters-1.1.1.jar" /&gt;
      &lt;zipfileset src="${krb-utils.jar.repo}//commons-logging-api-1.1.1.jar" /&gt;
    &lt;/jar&gt;
  &lt;/target&gt;

</pre>
<h3>Running The Application</h3>
<p>Our application can now be run all by itself with <code>java -jar ...</code>:</p>
<pre class="code">

kyleburton@indigo64 exec-jar[master*]$ java -jar target/exec-jar-0.1.jar ant zipfileset

ZipFileSet Type
http://ant.apache.org/manual/CoreTypes/zipfileset.html

Zip Task
http://ant.apache.org/manual/CoreTasks/zip.html

Ant Best Practices: Use ZipFileSet | The Build Doctor
http://www.build-doctor.com/2008/07/13/ant-best-practices-use-zipfileset

Top 15 Ant Best Practices - O&amp;#39;Reilly Media
http://www.onjava.com/pub/a/onjava/2003/12/17/ant_bestpractices.html

&amp;#39;cvs commit: ant/src/main/org/apache/tools/ant/types ZipFileSet ...
http://marc.info/?l=ant-dev&amp;m=112197754500691&amp;w=2

[picocontainer-scm] [CVS java] improved maven scri: msg#00056 java ...
http://osdir.com/ml/java.picocontainer.cvs/2004-07/msg00056.html

ZipFileSet Apache Ant 1.6.5 API Documentation and Javadoc
http://www.jdocs.com/link/org/apache/tools/ant/types/zipfileset.html

svn commit: r719578 - /ant/core/trunk/src/tests/antunit/types ...
http://mail-archives.apache.org/mod_mbox/ant-notifications/200811.mbox/%3C20081121133918.572D2238889E@eris.apache.org%3E

ZipFileSet (Apache Ant API)
http://lia.deis.unibo.it/Courses/TecnologieWeb0607/materiale/laboratorio/ant/api/org/apache/tools/ant/types/ZipFileSet.html

[news.eclipse.platform] Re: Problem with ANT zipfileset ... Re ...
http://dev.eclipse.org/newslists/news.eclipse.platform/msg07778.html

kyleburton@indigo64 exec-jar[master]$ 

</pre>
<h3>Conclusion</h3>
<p><img src="/images/2009-06/glass-jar.jpg" style="float: right; margin-left: 1em; " /></p>
<p>Bundling your application into a single Jar can simplify the deployment, and distribution of your application.  What tends to be less desirable about this technique though is that you have to track your dependencies carefully (you risk <code>ClassNotFoundException</code>s) and the jars you create are often quite large.  You can not add additional jars or paths to the classpath when running <code>java -jar</code>, which means that you won&#8217;t be able to re-use the libraries across other applications.</p>
<p>This technique allows you to create a single file that your users can download to run your clojure based applications.</p>
<p class="meta">Kyle Burton, 28th June 2009 &#8211; Wayne PA</p>
<h4>Links</h4>
<ul>
	<li><a href="http://java.sun.com/docs/books/tutorial/deployment/jar/" title="Sun">Jar Deployment Tutorial</a></li>
	<li><a href="http://java.sun.com/docs/books/tutorial/deployment/jar/manifestindex.html" title="Sun">Manifest Files</a></li>
</ul>
<h5>Photo Credits</h5>
<ul>
	<li><a href="http://www.flickr.com/photos/mmechtley/2110083185/sizes/l/">Green Glowing Jars</a></li>
	<li><a href="http://www.flickr.com/photos/mmechtley/2110083601/sizes/l/in/set-72157603453391346/">Blue Glowing Jars</a></li>
	<li><a href="http://www.flickr.com/photos/pacomexico/3288346239/sizes/l/">Cookie Jar and Orange</a></li>
	<li><a href="http://www.flickr.com/photos/riotjane/2216995811/sizes/l/">Glass Jar</a></li>
</ul>]]></content:encoded>
    </item>
    
    <item>
      <title>Visualizing AMQP Broker Behavior with Clojure and Incanter</title>
      <link>http://blog.asymmetrical-view.com/2009/06/02/incanter-amqp-benchmark.html</link>
      <comments>http://blog.asymmetrical-view.com/2009/06/02/incanter-amqp-benchmark.html#comments</comments>

      <pubDate>2009-06-02T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2009/06/02/incanter-amqp-benchmark.html</guid>

      <id>http://blog.asymmetrical-view.com/2009/06/02/incanter-amqp-benchmark</id>
      <description><![CDATA[<h1>Visualizing <span class="caps">AMQP</span> Broker Behavior with Clojure and Incanter</h1>
<p><img src="/images/2009-06/rabbit-run.jpg" style="float: left; margin-right: 1em; " /></p>
<p>I&#8217;m working with our system architect (<a href="http://www.linkedin.com/pub/mark-mehalik/13/113/461">Mark Mehalik</a>) evaluating <a href="http://amqp.org/"><span class="caps">AMQP</span></a> as a messaging implementation for a new project.  One of the things want to prove out is how the brokers behave under a widely varying number messages, message sizes, numbers of producers, consumers, queues and in differing clustering configurations.  Since <a href="http://amqp.org/"><span class="caps">AMQP</span></a> is a standard we should be able to build a single test suite and then execute it against the different brokers to measure their behavior as well as how robust they are under those conditions.</p>
<h2>Scripting and Automation</h2>
<p>I started the process of mocking up and automating the tests with the goal to help us figure out what we want to test.  I chose to do this with <a href="http://clojure.org/">Clojure</a> and to use <a href="http://github.com/liebke/incanter/tree/master">Incanter</a> for a quick and easy visualization.  You can the check the code out of my <a href="http://github.com/kyleburton/sandbox/tree/master">sandbox</a> project on <a href="http://github.com/">GitHub</a>.  The example code exercises a local <a href="http://amqp.org/"><span class="caps">AMQP</span></a> v0.8 broker using the <a href="http://www.rabbitmq.com/">RabbitMQ</a> Java Client Libraries (which support 0.8 at this time).</p>
<h3>Producer</h3>
<p>To test the broker, I created a simple producer and consumer and had them pass small (371 byte) messages.  They use the simple Rabbit Java client library primitives for <tt>Channel.basicPublish</tt> and <tt>Channel.basicGet</tt>.  The message consists of an array of two values: a message id (integer); and a time-stamp (<tt>java.util.Date</tt>).  They get serialized and placed into the <a href="http://amqp.org/"><span class="caps">AMQP</span></a> message body.  The producer just loops pushing all the messages to the broker and then logs its start and end times:</p>
<pre class="code">
(defn producer [producer-num cnt]
  (rabbit/with-amqp
   {}
   (let [start-time now]
     (dotimes [ii cnt]
       (object-publish [ii (Date.)]))
     (log-producer-stat producer-num cnt start-time (now)))))
</pre>
<h3>Consumer</h3>
<p>The consumer is a bit more more complex, doing more book keeping.  It tracks the number of messages it receives, its own elapsed time and totals up the amount of time each message was spent on the queue.  Just as with the producer, it logs its timings after it has consumed all of the messages on the queue.</p>
<pre class="code">
(defn consumer [consumer-num]
  (rabbit/with-amqp
   {}
   (let [start-time (now -1)
         num-msgs   (atom 0)
         msg-age    (atom 0)]
     (loop [[ii dt] (rabbit/object-get)]
       (if ii
         (let [end         (now -1)
               msg-elapsed (- end (.getTime dt))]
           (reset! num-msgs (+ 1 @num-msgs))
           (reset! msg-age  (+ msg-elapsed @msg-age))
           (recur (rabbit/object-get)))))
     (log-consumer-stat consumer-num @num-msgs start-time (now) @msg-age)
     (let [elapsed (/ (- (now) start-time) 1000.0)
           rate    (/ @num-msgs elapsed)]
       (prn (format "%s messages in %s elapsed seconds @ %s/second"
                    @num-msgs
                    elapsed
                    rate))))))
</pre>
<h3>Benchmark</h3>
<p>I chose to run a series of tests with message counts from 1 up to 500k, repeating each test three times.  This is only to get some data to play with, we plan on creating longer running and distributed tests over the next week to measure the behavior of the brokers in other configurations.  This test was enough to produce data for me to try out <a href="http://github.com/liebke/incanter/tree/master">Incanter</a> with though and given how easy this was to create, we&#8217;ll likely continue to modify this set of files.</p>
<pre class="code">
(defn run-benchmark [broker num-prods num-cons]
  (doseq [msg-count [1 5 10 50 100 500 1000 5000 10000 50000 100000 500000]]
    (run-single-benchmark (format "Series-%sm-%sp-%sc" msg-count num-prods num-cons)
                          broker
                          3 
                          msg-count
                          num-prods))
  (prn (format "run-benchmark: %s completed" broker)))

(defn run-single-benchmark [series broker num-runs num-msgs num-producers]
  (dotimes [run-number num-runs]
    (binding [*testing-info* (merge *testing-info*
                                    {:series  series
                                     :broker  broker
                                     :run-num (+ 1 run-number)})]
      (let [msgs-per-producer (/ num-msgs num-producers)]
        (dotimes [ii num-producers]
          (.start (Thread. (fn [] (producer (format "p%s" ii) msgs-per-producer))))))
      (Thread/sleep 100)
      (consumer "c1"))))
</pre>
<h3>Incanter Visualization</h3>
<p>Once we had run this against <a href="http://qpid.apache.org/">Apache&#8217;s Qpid</a> and <a href="http://rabbitmq.com/">RabbitMQ</a> there was enough data to produce some charts.   There is code to support loading the collected data from the files from disk, and the <a href="http://github.com/liebke/incanter/tree/master">Incanter</a> code is wonderfully easy to use.</p>
<p><tt>get-stat-data</tt> pulls the data from the consumer log for the named broker as a sequence of maps where the column headers are the keys and the row fields are the values.  <tt>get-xy-data</tt> pulls two of the fields and separates them into two sequences &#8211; just what the plotting functions in <a href="http://github.com/liebke/incanter/tree/master">Incanter</a> expect.  <tt>simple-xy-plot</tt> then passes the two sequences to <a href="http://github.com/liebke/incanter/tree/master&#39;s">Incanter</a> line-plot to visualize the data.</p>
<pre class="code">
(defn get-xy-data [broker xname yname]
  (let [stat-data (get-stat-data broker *consumer-stats-file*)
        count-and-rate (map (fn [ent] [(ent xname) (ent yname)]) stat-data)
        x-vals    (map #(Double/parseDouble (% 0))  count-and-rate)
        y-vals    (map #(Double/parseDouble (% 1))  count-and-rate)]
    [x-vals y-vals]))

(defn simple-xy-plot [broker xname yname]
  (let [rabbit-data (get-xy-data broker xname yname)]
    (line-plot (rabbit-data 0) (rabbit-data 1)
               :title (format "%s vs %s" xname yname)
               :x-label xname
               :y-label yname)))

(view (simple-xy-plot "RabbitMQ"    "TOTAL-MESSAGES" "M/S"))
(view (simple-xy-plot "Apache-Qpid" "TOTAL-MESSAGES" "M/S"))
</pre>
<div style="margin-top: 4em; margin-bottom: 4em;">
<p><img src="/images/2009-06/feisty-rabbit.jpg" style="float: right; margin-left: 2em;" height="219" width="256" /></p>
<p>I ran the broker, and a single <span class="caps">JVM</span> hosting both the producer and consumer on my workstation (along with all my other processes, X, <span class="caps">KDE</span>, Emacs and a ton of other processes).  I did no tuning of the brokers, running them in their default configurations.  I don&#8217;t expect these numbers to be too representative of the brokers performance in any kind of production configuration.</p>
<p>There are a few other interesting findings:  With no tuning Qpid failed at 100k messages with an out of memory exception (crashed hard).  This was with the default 1024Mb heap setting, at 2048Mb it was able to handle 100k messages and the graph shows Qpid using the 2048Mb heap setting.  Rabbit survived up to 500k message (as far as I pushed it), <em>but</em> the performance degraded significantly down to about 170 messages per second.</p>
</div>
<h4>Qpid <span class="caps">RSS</span></h4>
<p><img src="/images/2009-06/qpid-mem-rss.png" /></p>
<p>This shows the 2048M heap configuration growing up to the 100k message mark.</p>
<h4>Qpid <span class="caps">VSS</span></h4>
<p><img src="/images/2009-06/qpid-mem-vss.png" /></p>
<p>The flatness of this isn&#8217;t surprising as the <span class="caps">JVM</span> allocated its entire heap all at once.</p>
<h4>Rabbit <span class="caps">RSS</span></h4>
<p><img src="/images/2009-06/rabbit-mem-rss.png" /></p>
<p><a href="http://erlang.org/">Erlang&#8217;s</a> a bit more interesting, you can see it trying to cope with the various message loads, spiking up to about 3/4 of a gig with 500k messages.  In this configuration Rabbit&#8217;s rate dropped significantly from its average, to about 170/s.  It did stay up though.  The next step here is to see what we can learn about how Rabbit is handling this deluge of messages.</p>
<h4>Rabbit <span class="caps">VSS</span></h4>
<p><img src="/images/2009-06/rabbit-mem-vss.png" /></p>
<p>This pretty closely follows the shape of the <span class="caps">RSS</span> graph.</p>
<h4><font color="red">Rabbit</font> vs <font color="blue">Qpid</font> Messages per Second</h4>
<p><img src="/images/2009-06/rabbit-vs-qpid-mps.png" /></p>
<h2>Clojure and Incanter</h2>
<p>It was very straight forward to set up these benchmarks and the graphing code with Clojure and Incanter.  We were able to try different approaches and visualizations very rapidly.  Clojure&#8217;s ease of development and Incanter&#8217;s high level graphing functions turned the profiling from a chore into a fun task.</p>
<p class="meta">Kyle Burton, 2nd June 2009 &#8211; King of Prussia PA</p>
<h5>Photo Credits</h5>
<ul>
	<li><a href="http://www.flickr.com/photos/sapphir3blu3/3235526282/sizes/l/">Rabbit Run</a></li>
	<li><a href="http://www.flickr.com/photos/markhillary/2950218730/sizes/l/">Nail Filer</a></li>
	<li><a href="http://www.flickr.com/photos/boskizzi/4731745/sizes/o/">Dead Rabbit</a></li>
	<li><a href="http://www.flickr.com/photos/flik/3182151968/sizes/l/">feisty rabbit</a></li>
	<li><a href="http://www.flickr.com/photos/thetim/458733962/">dryer rabbit</a></li>
	<li><a href="http://www.flickr.com/photos/53366513@N00/67046506/">hidden rabbit</a></li>
</ul>]]></description>
      <content:encoded><![CDATA[<h1>Visualizing <span class="caps">AMQP</span> Broker Behavior with Clojure and Incanter</h1>
<p><img src="/images/2009-06/rabbit-run.jpg" style="float: left; margin-right: 1em; " /></p>
<p>I&#8217;m working with our system architect (<a href="http://www.linkedin.com/pub/mark-mehalik/13/113/461">Mark Mehalik</a>) evaluating <a href="http://amqp.org/"><span class="caps">AMQP</span></a> as a messaging implementation for a new project.  One of the things want to prove out is how the brokers behave under a widely varying number messages, message sizes, numbers of producers, consumers, queues and in differing clustering configurations.  Since <a href="http://amqp.org/"><span class="caps">AMQP</span></a> is a standard we should be able to build a single test suite and then execute it against the different brokers to measure their behavior as well as how robust they are under those conditions.</p>
<h2>Scripting and Automation</h2>
<p>I started the process of mocking up and automating the tests with the goal to help us figure out what we want to test.  I chose to do this with <a href="http://clojure.org/">Clojure</a> and to use <a href="http://github.com/liebke/incanter/tree/master">Incanter</a> for a quick and easy visualization.  You can the check the code out of my <a href="http://github.com/kyleburton/sandbox/tree/master">sandbox</a> project on <a href="http://github.com/">GitHub</a>.  The example code exercises a local <a href="http://amqp.org/"><span class="caps">AMQP</span></a> v0.8 broker using the <a href="http://www.rabbitmq.com/">RabbitMQ</a> Java Client Libraries (which support 0.8 at this time).</p>
<h3>Producer</h3>
<p>To test the broker, I created a simple producer and consumer and had them pass small (371 byte) messages.  They use the simple Rabbit Java client library primitives for <tt>Channel.basicPublish</tt> and <tt>Channel.basicGet</tt>.  The message consists of an array of two values: a message id (integer); and a time-stamp (<tt>java.util.Date</tt>).  They get serialized and placed into the <a href="http://amqp.org/"><span class="caps">AMQP</span></a> message body.  The producer just loops pushing all the messages to the broker and then logs its start and end times:</p>
<pre class="code">
(defn producer [producer-num cnt]
  (rabbit/with-amqp
   {}
   (let [start-time now]
     (dotimes [ii cnt]
       (object-publish [ii (Date.)]))
     (log-producer-stat producer-num cnt start-time (now)))))
</pre>
<h3>Consumer</h3>
<p>The consumer is a bit more more complex, doing more book keeping.  It tracks the number of messages it receives, its own elapsed time and totals up the amount of time each message was spent on the queue.  Just as with the producer, it logs its timings after it has consumed all of the messages on the queue.</p>
<pre class="code">
(defn consumer [consumer-num]
  (rabbit/with-amqp
   {}
   (let [start-time (now -1)
         num-msgs   (atom 0)
         msg-age    (atom 0)]
     (loop [[ii dt] (rabbit/object-get)]
       (if ii
         (let [end         (now -1)
               msg-elapsed (- end (.getTime dt))]
           (reset! num-msgs (+ 1 @num-msgs))
           (reset! msg-age  (+ msg-elapsed @msg-age))
           (recur (rabbit/object-get)))))
     (log-consumer-stat consumer-num @num-msgs start-time (now) @msg-age)
     (let [elapsed (/ (- (now) start-time) 1000.0)
           rate    (/ @num-msgs elapsed)]
       (prn (format "%s messages in %s elapsed seconds @ %s/second"
                    @num-msgs
                    elapsed
                    rate))))))
</pre>
<h3>Benchmark</h3>
<p>I chose to run a series of tests with message counts from 1 up to 500k, repeating each test three times.  This is only to get some data to play with, we plan on creating longer running and distributed tests over the next week to measure the behavior of the brokers in other configurations.  This test was enough to produce data for me to try out <a href="http://github.com/liebke/incanter/tree/master">Incanter</a> with though and given how easy this was to create, we&#8217;ll likely continue to modify this set of files.</p>
<pre class="code">
(defn run-benchmark [broker num-prods num-cons]
  (doseq [msg-count [1 5 10 50 100 500 1000 5000 10000 50000 100000 500000]]
    (run-single-benchmark (format "Series-%sm-%sp-%sc" msg-count num-prods num-cons)
                          broker
                          3 
                          msg-count
                          num-prods))
  (prn (format "run-benchmark: %s completed" broker)))

(defn run-single-benchmark [series broker num-runs num-msgs num-producers]
  (dotimes [run-number num-runs]
    (binding [*testing-info* (merge *testing-info*
                                    {:series  series
                                     :broker  broker
                                     :run-num (+ 1 run-number)})]
      (let [msgs-per-producer (/ num-msgs num-producers)]
        (dotimes [ii num-producers]
          (.start (Thread. (fn [] (producer (format "p%s" ii) msgs-per-producer))))))
      (Thread/sleep 100)
      (consumer "c1"))))
</pre>
<h3>Incanter Visualization</h3>
<p>Once we had run this against <a href="http://qpid.apache.org/">Apache&#8217;s Qpid</a> and <a href="http://rabbitmq.com/">RabbitMQ</a> there was enough data to produce some charts.   There is code to support loading the collected data from the files from disk, and the <a href="http://github.com/liebke/incanter/tree/master">Incanter</a> code is wonderfully easy to use.</p>
<p><tt>get-stat-data</tt> pulls the data from the consumer log for the named broker as a sequence of maps where the column headers are the keys and the row fields are the values.  <tt>get-xy-data</tt> pulls two of the fields and separates them into two sequences &#8211; just what the plotting functions in <a href="http://github.com/liebke/incanter/tree/master">Incanter</a> expect.  <tt>simple-xy-plot</tt> then passes the two sequences to <a href="http://github.com/liebke/incanter/tree/master&#39;s">Incanter</a> line-plot to visualize the data.</p>
<pre class="code">
(defn get-xy-data [broker xname yname]
  (let [stat-data (get-stat-data broker *consumer-stats-file*)
        count-and-rate (map (fn [ent] [(ent xname) (ent yname)]) stat-data)
        x-vals    (map #(Double/parseDouble (% 0))  count-and-rate)
        y-vals    (map #(Double/parseDouble (% 1))  count-and-rate)]
    [x-vals y-vals]))

(defn simple-xy-plot [broker xname yname]
  (let [rabbit-data (get-xy-data broker xname yname)]
    (line-plot (rabbit-data 0) (rabbit-data 1)
               :title (format "%s vs %s" xname yname)
               :x-label xname
               :y-label yname)))

(view (simple-xy-plot "RabbitMQ"    "TOTAL-MESSAGES" "M/S"))
(view (simple-xy-plot "Apache-Qpid" "TOTAL-MESSAGES" "M/S"))
</pre>
<div style="margin-top: 4em; margin-bottom: 4em;">
<p><img src="/images/2009-06/feisty-rabbit.jpg" style="float: right; margin-left: 2em;" height="219" width="256" /></p>
<p>I ran the broker, and a single <span class="caps">JVM</span> hosting both the producer and consumer on my workstation (along with all my other processes, X, <span class="caps">KDE</span>, Emacs and a ton of other processes).  I did no tuning of the brokers, running them in their default configurations.  I don&#8217;t expect these numbers to be too representative of the brokers performance in any kind of production configuration.</p>
<p>There are a few other interesting findings:  With no tuning Qpid failed at 100k messages with an out of memory exception (crashed hard).  This was with the default 1024Mb heap setting, at 2048Mb it was able to handle 100k messages and the graph shows Qpid using the 2048Mb heap setting.  Rabbit survived up to 500k message (as far as I pushed it), <em>but</em> the performance degraded significantly down to about 170 messages per second.</p>
</div>
<h4>Qpid <span class="caps">RSS</span></h4>
<p><img src="/images/2009-06/qpid-mem-rss.png" /></p>
<p>This shows the 2048M heap configuration growing up to the 100k message mark.</p>
<h4>Qpid <span class="caps">VSS</span></h4>
<p><img src="/images/2009-06/qpid-mem-vss.png" /></p>
<p>The flatness of this isn&#8217;t surprising as the <span class="caps">JVM</span> allocated its entire heap all at once.</p>
<h4>Rabbit <span class="caps">RSS</span></h4>
<p><img src="/images/2009-06/rabbit-mem-rss.png" /></p>
<p><a href="http://erlang.org/">Erlang&#8217;s</a> a bit more interesting, you can see it trying to cope with the various message loads, spiking up to about 3/4 of a gig with 500k messages.  In this configuration Rabbit&#8217;s rate dropped significantly from its average, to about 170/s.  It did stay up though.  The next step here is to see what we can learn about how Rabbit is handling this deluge of messages.</p>
<h4>Rabbit <span class="caps">VSS</span></h4>
<p><img src="/images/2009-06/rabbit-mem-vss.png" /></p>
<p>This pretty closely follows the shape of the <span class="caps">RSS</span> graph.</p>
<h4><font color="red">Rabbit</font> vs <font color="blue">Qpid</font> Messages per Second</h4>
<p><img src="/images/2009-06/rabbit-vs-qpid-mps.png" /></p>
<h2>Clojure and Incanter</h2>
<p>It was very straight forward to set up these benchmarks and the graphing code with Clojure and Incanter.  We were able to try different approaches and visualizations very rapidly.  Clojure&#8217;s ease of development and Incanter&#8217;s high level graphing functions turned the profiling from a chore into a fun task.</p>
<p class="meta">Kyle Burton, 2nd June 2009 &#8211; King of Prussia PA</p>
<h5>Photo Credits</h5>
<ul>
	<li><a href="http://www.flickr.com/photos/sapphir3blu3/3235526282/sizes/l/">Rabbit Run</a></li>
	<li><a href="http://www.flickr.com/photos/markhillary/2950218730/sizes/l/">Nail Filer</a></li>
	<li><a href="http://www.flickr.com/photos/boskizzi/4731745/sizes/o/">Dead Rabbit</a></li>
	<li><a href="http://www.flickr.com/photos/flik/3182151968/sizes/l/">feisty rabbit</a></li>
	<li><a href="http://www.flickr.com/photos/thetim/458733962/">dryer rabbit</a></li>
	<li><a href="http://www.flickr.com/photos/53366513@N00/67046506/">hidden rabbit</a></li>
</ul>]]></content:encoded>
    </item>
    
    <item>
      <title>Trixx Gets a Build</title>
      <link>http://blog.asymmetrical-view.com/2009/05/21/trixx-gets-a-build.html</link>
      <comments>http://blog.asymmetrical-view.com/2009/05/21/trixx-gets-a-build.html#comments</comments>

      <pubDate>2009-05-21T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2009/05/21/trixx-gets-a-build.html</guid>

      <id>http://blog.asymmetrical-view.com/2009/05/21/trixx-gets-a-build</id>
      <description><![CDATA[<h1>Trixx Gets a Build</h1>
<p>I just implemented an <a href="http://ant.apache.org/">ant</a> build for <a href="http://github.com/kyleburton/trixx/tree/master">Trixx</a>.  Trixx now builds, pulls down its dependencies jar, and contains and builds the required version of <a href="http://rabbitmq.com/">RabbitMQ</a>.</p>
<p>To build using ant (you will need to have <a href="http://erlang.org/">Erlang</a> already installed):</p>
<pre class="code">
kyleburton@indigo64 ~/personal/projects/$ git clone git@github.com:kyleburton/trixx.git
kyleburton@indigo64 ~/personal/projects/$ cd trixx
kyleburton@indigo64 ~/personal/projects/trixx[master]$ ant fetch-deps compile-rabbit-server compile-rabbit-java-client jar
</pre>
<p>Then in separate terminals, run RabbitMQ:</p>
<pre class="code">
kyleburton@indigo64 ~/personal/projects/trixx[master]$ ant run-rabbit
Buildfile: build.xml

run-rabbit:
     [exec] RabbitMQ %%VERSION%% (AMQP 8-0)
     [exec] Copyright (C) 2007-2009 LShift Ltd., Cohesive Financial Technologies LLC., and Rabbit Technologies Ltd.
     [exec] Licensed under the MPL.  See http://www.rabbitmq.com/
     [exec]
     [exec] Logging to "/home/kyleburton/local/var/rabbit/log/rabbit.log"
     [exec] SASL logging to "/home/kyleburton/local/var/rabbit/log/rabbit-sasl.log"
     [exec]
     [exec] starting database             ...done
     [exec] starting core processes       ...done
     [exec] starting recovery             ...done
     [exec] starting persister            ...done
     [exec] starting guid generator       ...done
     [exec] starting builtin applications ...done
     [exec] starting TCP listeners        ...done
     [exec]
     [exec] broker running
</pre>
<p>In another terminal, run Trixx:</p>
<pre class="code">
kyleburton@indigo64 ~/personal/projects/trixx[master]$ ant run-trixx
Buildfile: build.xml

run-trixx:
     [echo] Ensure you've run rabbit before this task...
     [java] "com.leftrightfold.trixx: *cookie*=FONEINRZCWQWZOERIHXH"
     [java] "com.leftrightfold.trixx: *server*=localhost"
     [java] "com.leftrightfold.trixx: *rabbit-instance=rabbit"
     [java] 2009-05-22 00:15:58.317::INFO:  Logging to STDERR via org.mortbay.log.StdErrLog
     [java] clojure.proxy.javax.servlet.http.HttpServlet
     [java] 2009-05-22 00:15:58.395::INFO:  jetty-6.1.15
     [java] 2009-05-22 00:16:00.462::INFO:  Started SocketConnector@0.0.0.0:8080
</pre>
<p><a href="http://github.com/aaronfeng/">Aaron&#8217;s</a> stated goal is to make Trixx a management console for RabbitMQ.  He just started implementing a RESTfull interface using <a href="http://github.com/weavejester/compojure/tree/master">Compojure</a> which you can hit with a browser after running <code>ant run-trixx</code>.</p>
<p>Now that things are easier to build and run I expect the development to go more smoothly.</p>
<p class="meta">Kyle Burton, 21 May 2009 &#8211; Wayne PA</p>]]></description>
      <content:encoded><![CDATA[<h1>Trixx Gets a Build</h1>
<p>I just implemented an <a href="http://ant.apache.org/">ant</a> build for <a href="http://github.com/kyleburton/trixx/tree/master">Trixx</a>.  Trixx now builds, pulls down its dependencies jar, and contains and builds the required version of <a href="http://rabbitmq.com/">RabbitMQ</a>.</p>
<p>To build using ant (you will need to have <a href="http://erlang.org/">Erlang</a> already installed):</p>
<pre class="code">
kyleburton@indigo64 ~/personal/projects/$ git clone git@github.com:kyleburton/trixx.git
kyleburton@indigo64 ~/personal/projects/$ cd trixx
kyleburton@indigo64 ~/personal/projects/trixx[master]$ ant fetch-deps compile-rabbit-server compile-rabbit-java-client jar
</pre>
<p>Then in separate terminals, run RabbitMQ:</p>
<pre class="code">
kyleburton@indigo64 ~/personal/projects/trixx[master]$ ant run-rabbit
Buildfile: build.xml

run-rabbit:
     [exec] RabbitMQ %%VERSION%% (AMQP 8-0)
     [exec] Copyright (C) 2007-2009 LShift Ltd., Cohesive Financial Technologies LLC., and Rabbit Technologies Ltd.
     [exec] Licensed under the MPL.  See http://www.rabbitmq.com/
     [exec]
     [exec] Logging to "/home/kyleburton/local/var/rabbit/log/rabbit.log"
     [exec] SASL logging to "/home/kyleburton/local/var/rabbit/log/rabbit-sasl.log"
     [exec]
     [exec] starting database             ...done
     [exec] starting core processes       ...done
     [exec] starting recovery             ...done
     [exec] starting persister            ...done
     [exec] starting guid generator       ...done
     [exec] starting builtin applications ...done
     [exec] starting TCP listeners        ...done
     [exec]
     [exec] broker running
</pre>
<p>In another terminal, run Trixx:</p>
<pre class="code">
kyleburton@indigo64 ~/personal/projects/trixx[master]$ ant run-trixx
Buildfile: build.xml

run-trixx:
     [echo] Ensure you've run rabbit before this task...
     [java] "com.leftrightfold.trixx: *cookie*=FONEINRZCWQWZOERIHXH"
     [java] "com.leftrightfold.trixx: *server*=localhost"
     [java] "com.leftrightfold.trixx: *rabbit-instance=rabbit"
     [java] 2009-05-22 00:15:58.317::INFO:  Logging to STDERR via org.mortbay.log.StdErrLog
     [java] clojure.proxy.javax.servlet.http.HttpServlet
     [java] 2009-05-22 00:15:58.395::INFO:  jetty-6.1.15
     [java] 2009-05-22 00:16:00.462::INFO:  Started SocketConnector@0.0.0.0:8080
</pre>
<p><a href="http://github.com/aaronfeng/">Aaron&#8217;s</a> stated goal is to make Trixx a management console for RabbitMQ.  He just started implementing a RESTfull interface using <a href="http://github.com/weavejester/compojure/tree/master">Compojure</a> which you can hit with a browser after running <code>ant run-trixx</code>.</p>
<p>Now that things are easier to build and run I expect the development to go more smoothly.</p>
<p class="meta">Kyle Burton, 21 May 2009 &#8211; Wayne PA</p>]]></content:encoded>
    </item>
    
    <item>
      <title>Experience knows a Name</title>
      <link>http://blog.asymmetrical-view.com/2009/05/20/expeirence-knows-a-name.html</link>
      <comments>http://blog.asymmetrical-view.com/2009/05/20/expeirence-knows-a-name.html#comments</comments>

      <pubDate>2009-05-20T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2009/05/20/expeirence-knows-a-name.html</guid>

      <id>http://blog.asymmetrical-view.com/2009/05/20/expeirence-knows-a-name</id>
      <description><![CDATA[<h1>Experience knows a Name</h1>
<p>Reading <a href="http://blog.bitquabit.com/2009/05/20/your-language-features-are-my-libraries/">Your Language Features Are My Libraries</a>, a thought occurred to me.  Not about language features, but about people.</p>
<p>I see new developers latch onto the new languages and the features that they support (Java has garbage collection; Ruby lets you extend classes and makes DSLs easy; C# has list comprehensions; and so on).  I see new developers lead themselves down the road of re-implementing solutions when pre-existing libraries may have been available (sometimes core libraries).  I see senior developers lament that the junior devs aren&#8217;t paying attention to what already exists.</p>
<h3>Senior Developers have an Index</h3>
<p>Seasoned or experienced developers have a large mental index of existing example code, libraries, design patterns, frameworks and full application stacks.  Experienced developers can often qualify and evaluate suitable pre-existing approaches (existing language support, core libraries, available libraries, pre-existing applications) &#8211; much more frequently and with more success (where success is re-use rather than re-implementation) than junior developers.</p>
<p>I&#8217;m not so sure that the only reason for this is just that new developers don&#8217;t have the mental index of language features and libraries that more experienced developers do.</p>
<p>Both types of developers can use Google right (it&#8217;s a big &#8220;index&#8221; after all)?  Well&#8230;not in the same way.  Experienced developers have a higher chance of already understanding core aspects of the problem they are facing.  Experienced developers are more likely to know the commonly used names for many of the aspects of the problem they are facing.  So when they search, they&#8217;re searching for something very specific, something that is more likely to be found.</p>
<p>Junior developers will not be searching by name, rather by definition.  They search by using the phrases that describe what they&#8217;re after.  This isn&#8217;t as successful.  Look at the difference between searching for <a href="http://www.google.com/search?q=carbonated+sugar+water">carbonated sugar water</a> versus <a href="http://www.google.com/search?q=coca-cola">coca-cola</a>.</p>
<p>This has a huge impact on the likelihood that a suitable pre-existing solution will even be identified.  I have improved in this respect over the years &#8211; partly just by accumulating knowledge of the names of things (this is the idea that naming something or knowing its name gives you some amount of power over it).</p>
<p>Then we come to the issue of understanding the problem.  Developers will more often have to work to build a working model of the problem before any search or selection could take place.  Developers by their very nature will write code to help them develop understanding of a problem.  Writing a prototype is a very powerful tool for helping you understand a problem &#8211; if you can instruct a computer to perform a task, you must have a pretty good understanding of it.</p>
<p>Here&#8217;s the rub though, once you have a prototype, you have something with value.  It becomes less attractive to qualify and acquire an alternative when you already have a working, or close to working &#8220;bird in hand&#8221;.  Junior developers often over value their prototypes, partly due to the actual effort it took them to create it.  Senior developers create more minimal prototypes, only explore the core parts of the problem domain they don&#8217;t already understand &#8211; and often with different tools, not caring about input, output or fixed data models or well defined types.  The point is to learn just enough and senior developers are more prescient of what &#8216;just enough&#8217; is.</p>
<h3>Junior Developers Implement to Learn</h3>
<p>The transfer of the names of things of these patterns of problems, is a core value that developers get out of mentoring each other.</p>
<p>Junior developers implement to learn.  I encourage the junior developers I work with to write prototypes of existing algorithms and design patterns &#8211; it is vital practice and helps them develop a deeper understanding of problems.  I try to discuss with them what they did, why they did it and try to transfer terminology and discuss with them existing solutions that I may know of for contrast.</p>
<p>As they gain experience, they will know its name.</p>
<p class="meta">Kyle Burton, 20 May 2009 &#8211; King of Prussia PA</p>]]></description>
      <content:encoded><![CDATA[<h1>Experience knows a Name</h1>
<p>Reading <a href="http://blog.bitquabit.com/2009/05/20/your-language-features-are-my-libraries/">Your Language Features Are My Libraries</a>, a thought occurred to me.  Not about language features, but about people.</p>
<p>I see new developers latch onto the new languages and the features that they support (Java has garbage collection; Ruby lets you extend classes and makes DSLs easy; C# has list comprehensions; and so on).  I see new developers lead themselves down the road of re-implementing solutions when pre-existing libraries may have been available (sometimes core libraries).  I see senior developers lament that the junior devs aren&#8217;t paying attention to what already exists.</p>
<h3>Senior Developers have an Index</h3>
<p>Seasoned or experienced developers have a large mental index of existing example code, libraries, design patterns, frameworks and full application stacks.  Experienced developers can often qualify and evaluate suitable pre-existing approaches (existing language support, core libraries, available libraries, pre-existing applications) &#8211; much more frequently and with more success (where success is re-use rather than re-implementation) than junior developers.</p>
<p>I&#8217;m not so sure that the only reason for this is just that new developers don&#8217;t have the mental index of language features and libraries that more experienced developers do.</p>
<p>Both types of developers can use Google right (it&#8217;s a big &#8220;index&#8221; after all)?  Well&#8230;not in the same way.  Experienced developers have a higher chance of already understanding core aspects of the problem they are facing.  Experienced developers are more likely to know the commonly used names for many of the aspects of the problem they are facing.  So when they search, they&#8217;re searching for something very specific, something that is more likely to be found.</p>
<p>Junior developers will not be searching by name, rather by definition.  They search by using the phrases that describe what they&#8217;re after.  This isn&#8217;t as successful.  Look at the difference between searching for <a href="http://www.google.com/search?q=carbonated+sugar+water">carbonated sugar water</a> versus <a href="http://www.google.com/search?q=coca-cola">coca-cola</a>.</p>
<p>This has a huge impact on the likelihood that a suitable pre-existing solution will even be identified.  I have improved in this respect over the years &#8211; partly just by accumulating knowledge of the names of things (this is the idea that naming something or knowing its name gives you some amount of power over it).</p>
<p>Then we come to the issue of understanding the problem.  Developers will more often have to work to build a working model of the problem before any search or selection could take place.  Developers by their very nature will write code to help them develop understanding of a problem.  Writing a prototype is a very powerful tool for helping you understand a problem &#8211; if you can instruct a computer to perform a task, you must have a pretty good understanding of it.</p>
<p>Here&#8217;s the rub though, once you have a prototype, you have something with value.  It becomes less attractive to qualify and acquire an alternative when you already have a working, or close to working &#8220;bird in hand&#8221;.  Junior developers often over value their prototypes, partly due to the actual effort it took them to create it.  Senior developers create more minimal prototypes, only explore the core parts of the problem domain they don&#8217;t already understand &#8211; and often with different tools, not caring about input, output or fixed data models or well defined types.  The point is to learn just enough and senior developers are more prescient of what &#8216;just enough&#8217; is.</p>
<h3>Junior Developers Implement to Learn</h3>
<p>The transfer of the names of things of these patterns of problems, is a core value that developers get out of mentoring each other.</p>
<p>Junior developers implement to learn.  I encourage the junior developers I work with to write prototypes of existing algorithms and design patterns &#8211; it is vital practice and helps them develop a deeper understanding of problems.  I try to discuss with them what they did, why they did it and try to transfer terminology and discuss with them existing solutions that I may know of for contrast.</p>
<p>As they gain experience, they will know its name.</p>
<p class="meta">Kyle Burton, 20 May 2009 &#8211; King of Prussia PA</p>]]></content:encoded>
    </item>
    
    <item>
      <title>Exploring Quartz from Clojure</title>
      <link>http://blog.asymmetrical-view.com/2009/05/19/quartz-and-clojure.html</link>
      <comments>http://blog.asymmetrical-view.com/2009/05/19/quartz-and-clojure.html#comments</comments>

      <pubDate>2009-05-19T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2009/05/19/quartz-and-clojure.html</guid>

      <id>http://blog.asymmetrical-view.com/2009/05/19/quartz-and-clojure</id>
      <description><![CDATA[<h1>Exploring Quartz from Clojure</h1>
<p>From the <a href="http://www.opensymphony.com/quartz/">Quartz</a> website:</p>
<blockquote>
Quartz is a job scheduling system that can be integrated with, or used along side virtually any other software system. The term &#8220;job scheduler&#8221; seems to conjure different ideas for different people&#8230;in short, a job scheduler is a system that is responsible for executing (or notifying) other software components when a pre-determined (scheduled) time arrives.
</blockquote>
<p>I wanted to be able to explore how Quartz worked from <a href="http://clojure.org/">Clojure</a>.  Quartz executes <a href="http://www.opensymphony.com/quartz/api/org/quartz/Job.html">Jobs</a>.  You do not schedule job instances in Quartz though, instead you pass the <a href="http://www.opensymphony.com/quartz/api/org/quartz/Scheduler.html">scheduler</a> a factory, specifically a <a href="http://www.opensymphony.com/quartz/api/org/quartz/JobDetail.html">JobDetail</a>.  The JobDetail will specify the Class of the class implementing the job, which must support a no-arg constructor.  This meant I couldn&#8217;t use Clojure&#8217;s <a href="http://clojure.org/java_interop">proxy</a> to implement the Job instance &#8211; since it needed to be constructible via a call like Class.newInstance.  Looking briefly at the Quartz source it appears to be the technique used in at least the SimpleJobFactory.</p>
<h3>ClojureJob.java</h3>
<p>To enable the calling of Clojure from a Quartz Job I implemented a very basic <a href="http://github.com/kyleburton/sandbox/blob/master/clojure-utils/src/java/com/github/kyleburton/sandbox/quartz/ClojureJob.java">ClojureJob</a> class:</p>
<pre class="code">
package com.github.kyleburton.sandbox.quartz;

import clojure.lang.Namespace;
import clojure.lang.RT;
import clojure.lang.Symbol;
import clojure.lang.Var;
import clojure.lang.IFn;

import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

/**
 * Quartz Job class for executing a clojure function.  The clojure
 * function will take a single argument, the JobExecutionContext which
 * is passed to this Job's execute method.
 *
 * NB: There is no way to capture or propagate an error from the
 * called function back to the context where the job was scheduled.
 *
 * http://www.opensymphony.com/quartz/
 *
 * @author Kyle R. Burton &lt;kyle.burton@gmail.com&gt;
 */
public class ClojureJob implements Job {
  /** JobExecutionContext/JobDetail/JobDataMap Parameter for the namespace of the function that will be called. */
  public  static final String NAMESPACE_PARAMETER     = "job.clojure.namespace";
  /** JobExecutionContext/JobDetail/JobDataMap Parameter for the name of the function that will be called. */
  public  static final String FUNCTION_NAME_PARAMETER = "job.clojure.function";
  /** */
  public  static final String FUNCTION_PARAMETER = "job.clojure.fn";
  private static final Class CLASS = ClojureJob.class;

  /**
   * Quartz required no-arg constructor.  Does nothing.
   */
  public ClojureJob() {
  }

  /**
   * Execute implementation, look up the clojure function specified in
   * the JobDataMap, invoke it with the JobExecutionContext.
   * @param context the JobExecutionContext passed in by quartz
   * @throws JobExecutionContext if the function can not be looked up,
   * or if the function throws an exception.
   */
  @Override
  public void execute(JobExecutionContext context) throws JobExecutionException {
    if ( null != contextParameter(context,FUNCTION_PARAMETER) ) {
      executeFunction(context,(IFn)contextParameter(context,FUNCTION_PARAMETER));
      return;
    }

    executeVar(context);
  }

  private void executeVar( JobExecutionContext context) throws JobExecutionException {
    Var fn = lookupClojureFunction(context);
    if ( null == fn ) {
      throw new JobExecutionException(
        String.format(CLASS.getName() + ".execute: unable to find the specified function, namespace=%s; function=%s", 
                      contextParameterString(context,NAMESPACE_PARAMETER),
                      contextParameterString(context,FUNCTION_NAME_PARAMETER)));
    }

    try {
      fn.invoke(context);
    }
    catch(Exception ex) {
      throw new JobExecutionException(ex);
    }
  }

  private void executeFunction( JobExecutionContext context, IFn fn) throws JobExecutionException {
    try {
      fn.invoke(context);
    }
    catch(Exception ex) {
      throw new JobExecutionException(ex);
    }
  }

  /**
   * Helper function for pulling parameters from the JobDataMap
   *
   * @param JobExecutionException the context to pull the parameter from
   * @param name the parameter to pull from the JobDataMap
   * @return the string value from the JobDataMap
   */
  private String contextParameterString(JobExecutionContext context, String name) {
    return context.getJobDetail().getJobDataMap().getString(name);
  }

  private Object contextParameter(JobExecutionContext context, String name) {
    return context.getJobDetail().getJobDataMap().get(name);
  }

  /**
   * Helper function for looking up the clojure function specified in
   * the quartz job.
   *
   * @param JobExecutionException the context passed in from quartz
   * @return the clojure Var which is the function
   */
  private Var lookupClojureFunction(JobExecutionContext context) { 
    String namespaceName = contextParameterString(context,NAMESPACE_PARAMETER);
    String functionName  = contextParameterString(context,FUNCTION_NAME_PARAMETER);
    Symbol symNamespace  = Symbol.create(namespaceName);
    Namespace namespace  = Namespace.findOrCreate(symNamespace);
    return Var.intern(namespace,Symbol.create(functionName));
  }
}
</pre>
<p>This class calls a clojure function that is either looked up or one that is passed in via the JobDetails of the JobExecutionContext.  In the case when an actual function (Clojure IFn) is passed, it is called without checking to see if a named function is passed.  The JobExecutionContext is passed to the <tt>invoke</tt> call So that parameters can be passed through to the Clojure function in either case.</p>
<h3>quartz.clj</h3>
<p>This allowed me to then create and schedule jobs which are backed by clojure functions.  Here is <a href="http://github.com/kyleburton/sandbox/blob/master/clojure-utils/src/clj/com/github/kyleburton/sandbox/quartz.clj">quartz.clj</a></p>
<pre class="code">
(ns com.github.kyleburton.sandbox.quartz
  (:import (org.quartz SchedulerFactory Scheduler TriggerUtils JobDetail)
           (org.quartz.impl StdSchedulerFactory)
           (com.github.kyleburton.sandbox.quartz ClojureJob)))

(def *schedule-factory* (StdSchedulerFactory.))

(def *scheduler* (atom nil))

(defn ensure-scheduler-started []
  (if (or (not @*scheduler*)
          (.isShutdown @*scheduler*)
          (not (.isStarted @*scheduler*)))
    (do
      (reset! *scheduler* (.getScheduler *schedule-factory*))
      (.start @*scheduler*)
      true)
    nil))

(defn stop-scheduler []
  (if (and @*scheduler*
           (.isStarted @*scheduler*))
    (.shutdown @*scheduler*)))

(defn schedule-job [job-detail trigger]
  (ensure-scheduler-started)
  (.scheduleJob @*scheduler* job-detail trigger))

(defn delete-job [job-detail]
  (.deleteJob @*scheduler*
              (.getName job-detail)
              (.getGroup job-detail)))

(defn job-exists? [job-detail]
  (not (nil? (.getJobDetail @*scheduler*
                            (.getName job-detail)
                            (.getGroup job-detail)))))

(defn testfn [context]
  (prn (format "testfn: context=%s time=%s" 
               context
               (java.util.Date.))))

(defn quartz-test []
  (let [job-detail (JobDetail. "myJob" nil ClojureJob)
        trigger (doto (TriggerUtils/makeSecondlyTrigger 10)
                  (.setStartTime (TriggerUtils/getEvenSecondDate (java.util.Date.)))
                  (.setName "My Second Trigger"))]
    (.put (.getJobDataMap job-detail) ClojureJob/NAMESPACE_PARAMETER "com.github.kyleburton.sandbox.quartz")
    (.put (.getJobDataMap job-detail) ClojureJob/FUNCTION_NAME_PARAMETER "testfn")
    (schedule-job job-detail trigger)))

(defn quartz-test-fn [fn]
  (let [job-detail (JobDetail. "myJob" nil ClojureJob)
        trigger (doto (TriggerUtils/makeSecondlyTrigger 10)
                  (.setStartTime (TriggerUtils/getEvenSecondDate (java.util.Date.)))
                  (.setName "My Second Trigger"))]
    (.put (.getJobDataMap job-detail) ClojureJob/FUNCTION_PARAMETER fn)
    (schedule-job job-detail trigger)))


;; (quartz-test)
;; (stop-scheduler)
;; (def *count* (atom 0))
;; (quartz-test-fn (fn [context] 
;;                   (reset! *count* (inc @*count*))
;;                   (prn (format "anon scheduled function! context=%s called %d times!" context @*count*))))
;; (stop-scheduler)
</pre>
<p>To play with these pull down my <a href="http://github.com/kyleburton/sandbox/tree/master">sandbox</a> run <a href="http://ant.apache.org/">ant</a> in the clojure-utils sub directory with the <tt>fetch-deps</tt> and <tt>jar</tt> targets.</p>
<pre class="code">
kyle@indigo64 ~/personal/projects/sandbox/clojure-utils[master]$ ant fetch-deps jar
Buildfile: build.xml

fetch-deps:
      [get] Getting: http://asymmetrical-view.com/personal/repo//ant-1.7.0.jar
      [get] To: /home/mortis/personal/projects/sandbox/clojure-utils/lib/ant-1.7.0.jar
      ...and lots more...

compile:
    [mkdir] Created dir: /home/mortis/personal/projects/sandbox/clojure-utils/target/classes
    [javac] Compiling 1 source file to /home/mortis/personal/projects/sandbox/clojure-utils/target/classes

jar:  
      [jar] Building jar: /home/mortis/personal/projects/sandbox/clojure-utils/target/krb-clojure-utils-0.1.jar

BUILD SUCCESSFUL
Total time: 23 seconds
kyle@indigo64 ~/personal/projects/sandbox/clojure-utils[master]$ ant repl

</pre>
<p>You can use <tt>ant repl</tt> to run a Clojure <span class="caps">REPL</span> with the necessary dependencies on the classpath.   Paste or type in the example functions to see them in action:</p>
<pre class="code">
(quartz-test)
;; wait a bit to see it run (it should run every 10s)
;; stop the scheduler to remove all tasks
(stop-scheduler)

;; define an atom to hold the count
(def *count* (atom 0))
;; schedule an anonymous function
(quartz-test-fn (fn [context] 
                  (reset! *count* (inc @*count*))
                  (prn (format "anon scheduled function! context=%s called %d times!" context @*count*))))
;; wait a bit to see it run (every 10s)
;; stop and exit the JVM
(stop-scheduler)
(System/exit 0)
</pre>
<p>The next thing I&#8217;d like to do is implement a prototype scheduler service exposing Quartz over <a href="http://amqp.org/"><span class="caps">AMQP</span></a> (<a href="http://www.rabbitmq.com/">RabbitMQ</a>).</p>
<p class="meta">Kyle Burton, 19 May 2009 &#8211; Wayne PA</p>]]></description>
      <content:encoded><![CDATA[<h1>Exploring Quartz from Clojure</h1>
<p>From the <a href="http://www.opensymphony.com/quartz/">Quartz</a> website:</p>
<blockquote>
Quartz is a job scheduling system that can be integrated with, or used along side virtually any other software system. The term &#8220;job scheduler&#8221; seems to conjure different ideas for different people&#8230;in short, a job scheduler is a system that is responsible for executing (or notifying) other software components when a pre-determined (scheduled) time arrives.
</blockquote>
<p>I wanted to be able to explore how Quartz worked from <a href="http://clojure.org/">Clojure</a>.  Quartz executes <a href="http://www.opensymphony.com/quartz/api/org/quartz/Job.html">Jobs</a>.  You do not schedule job instances in Quartz though, instead you pass the <a href="http://www.opensymphony.com/quartz/api/org/quartz/Scheduler.html">scheduler</a> a factory, specifically a <a href="http://www.opensymphony.com/quartz/api/org/quartz/JobDetail.html">JobDetail</a>.  The JobDetail will specify the Class of the class implementing the job, which must support a no-arg constructor.  This meant I couldn&#8217;t use Clojure&#8217;s <a href="http://clojure.org/java_interop">proxy</a> to implement the Job instance &#8211; since it needed to be constructible via a call like Class.newInstance.  Looking briefly at the Quartz source it appears to be the technique used in at least the SimpleJobFactory.</p>
<h3>ClojureJob.java</h3>
<p>To enable the calling of Clojure from a Quartz Job I implemented a very basic <a href="http://github.com/kyleburton/sandbox/blob/master/clojure-utils/src/java/com/github/kyleburton/sandbox/quartz/ClojureJob.java">ClojureJob</a> class:</p>
<pre class="code">
package com.github.kyleburton.sandbox.quartz;

import clojure.lang.Namespace;
import clojure.lang.RT;
import clojure.lang.Symbol;
import clojure.lang.Var;
import clojure.lang.IFn;

import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

/**
 * Quartz Job class for executing a clojure function.  The clojure
 * function will take a single argument, the JobExecutionContext which
 * is passed to this Job's execute method.
 *
 * NB: There is no way to capture or propagate an error from the
 * called function back to the context where the job was scheduled.
 *
 * http://www.opensymphony.com/quartz/
 *
 * @author Kyle R. Burton &lt;kyle.burton@gmail.com&gt;
 */
public class ClojureJob implements Job {
  /** JobExecutionContext/JobDetail/JobDataMap Parameter for the namespace of the function that will be called. */
  public  static final String NAMESPACE_PARAMETER     = "job.clojure.namespace";
  /** JobExecutionContext/JobDetail/JobDataMap Parameter for the name of the function that will be called. */
  public  static final String FUNCTION_NAME_PARAMETER = "job.clojure.function";
  /** */
  public  static final String FUNCTION_PARAMETER = "job.clojure.fn";
  private static final Class CLASS = ClojureJob.class;

  /**
   * Quartz required no-arg constructor.  Does nothing.
   */
  public ClojureJob() {
  }

  /**
   * Execute implementation, look up the clojure function specified in
   * the JobDataMap, invoke it with the JobExecutionContext.
   * @param context the JobExecutionContext passed in by quartz
   * @throws JobExecutionContext if the function can not be looked up,
   * or if the function throws an exception.
   */
  @Override
  public void execute(JobExecutionContext context) throws JobExecutionException {
    if ( null != contextParameter(context,FUNCTION_PARAMETER) ) {
      executeFunction(context,(IFn)contextParameter(context,FUNCTION_PARAMETER));
      return;
    }

    executeVar(context);
  }

  private void executeVar( JobExecutionContext context) throws JobExecutionException {
    Var fn = lookupClojureFunction(context);
    if ( null == fn ) {
      throw new JobExecutionException(
        String.format(CLASS.getName() + ".execute: unable to find the specified function, namespace=%s; function=%s", 
                      contextParameterString(context,NAMESPACE_PARAMETER),
                      contextParameterString(context,FUNCTION_NAME_PARAMETER)));
    }

    try {
      fn.invoke(context);
    }
    catch(Exception ex) {
      throw new JobExecutionException(ex);
    }
  }

  private void executeFunction( JobExecutionContext context, IFn fn) throws JobExecutionException {
    try {
      fn.invoke(context);
    }
    catch(Exception ex) {
      throw new JobExecutionException(ex);
    }
  }

  /**
   * Helper function for pulling parameters from the JobDataMap
   *
   * @param JobExecutionException the context to pull the parameter from
   * @param name the parameter to pull from the JobDataMap
   * @return the string value from the JobDataMap
   */
  private String contextParameterString(JobExecutionContext context, String name) {
    return context.getJobDetail().getJobDataMap().getString(name);
  }

  private Object contextParameter(JobExecutionContext context, String name) {
    return context.getJobDetail().getJobDataMap().get(name);
  }

  /**
   * Helper function for looking up the clojure function specified in
   * the quartz job.
   *
   * @param JobExecutionException the context passed in from quartz
   * @return the clojure Var which is the function
   */
  private Var lookupClojureFunction(JobExecutionContext context) { 
    String namespaceName = contextParameterString(context,NAMESPACE_PARAMETER);
    String functionName  = contextParameterString(context,FUNCTION_NAME_PARAMETER);
    Symbol symNamespace  = Symbol.create(namespaceName);
    Namespace namespace  = Namespace.findOrCreate(symNamespace);
    return Var.intern(namespace,Symbol.create(functionName));
  }
}
</pre>
<p>This class calls a clojure function that is either looked up or one that is passed in via the JobDetails of the JobExecutionContext.  In the case when an actual function (Clojure IFn) is passed, it is called without checking to see if a named function is passed.  The JobExecutionContext is passed to the <tt>invoke</tt> call So that parameters can be passed through to the Clojure function in either case.</p>
<h3>quartz.clj</h3>
<p>This allowed me to then create and schedule jobs which are backed by clojure functions.  Here is <a href="http://github.com/kyleburton/sandbox/blob/master/clojure-utils/src/clj/com/github/kyleburton/sandbox/quartz.clj">quartz.clj</a></p>
<pre class="code">
(ns com.github.kyleburton.sandbox.quartz
  (:import (org.quartz SchedulerFactory Scheduler TriggerUtils JobDetail)
           (org.quartz.impl StdSchedulerFactory)
           (com.github.kyleburton.sandbox.quartz ClojureJob)))

(def *schedule-factory* (StdSchedulerFactory.))

(def *scheduler* (atom nil))

(defn ensure-scheduler-started []
  (if (or (not @*scheduler*)
          (.isShutdown @*scheduler*)
          (not (.isStarted @*scheduler*)))
    (do
      (reset! *scheduler* (.getScheduler *schedule-factory*))
      (.start @*scheduler*)
      true)
    nil))

(defn stop-scheduler []
  (if (and @*scheduler*
           (.isStarted @*scheduler*))
    (.shutdown @*scheduler*)))

(defn schedule-job [job-detail trigger]
  (ensure-scheduler-started)
  (.scheduleJob @*scheduler* job-detail trigger))

(defn delete-job [job-detail]
  (.deleteJob @*scheduler*
              (.getName job-detail)
              (.getGroup job-detail)))

(defn job-exists? [job-detail]
  (not (nil? (.getJobDetail @*scheduler*
                            (.getName job-detail)
                            (.getGroup job-detail)))))

(defn testfn [context]
  (prn (format "testfn: context=%s time=%s" 
               context
               (java.util.Date.))))

(defn quartz-test []
  (let [job-detail (JobDetail. "myJob" nil ClojureJob)
        trigger (doto (TriggerUtils/makeSecondlyTrigger 10)
                  (.setStartTime (TriggerUtils/getEvenSecondDate (java.util.Date.)))
                  (.setName "My Second Trigger"))]
    (.put (.getJobDataMap job-detail) ClojureJob/NAMESPACE_PARAMETER "com.github.kyleburton.sandbox.quartz")
    (.put (.getJobDataMap job-detail) ClojureJob/FUNCTION_NAME_PARAMETER "testfn")
    (schedule-job job-detail trigger)))

(defn quartz-test-fn [fn]
  (let [job-detail (JobDetail. "myJob" nil ClojureJob)
        trigger (doto (TriggerUtils/makeSecondlyTrigger 10)
                  (.setStartTime (TriggerUtils/getEvenSecondDate (java.util.Date.)))
                  (.setName "My Second Trigger"))]
    (.put (.getJobDataMap job-detail) ClojureJob/FUNCTION_PARAMETER fn)
    (schedule-job job-detail trigger)))


;; (quartz-test)
;; (stop-scheduler)
;; (def *count* (atom 0))
;; (quartz-test-fn (fn [context] 
;;                   (reset! *count* (inc @*count*))
;;                   (prn (format "anon scheduled function! context=%s called %d times!" context @*count*))))
;; (stop-scheduler)
</pre>
<p>To play with these pull down my <a href="http://github.com/kyleburton/sandbox/tree/master">sandbox</a> run <a href="http://ant.apache.org/">ant</a> in the clojure-utils sub directory with the <tt>fetch-deps</tt> and <tt>jar</tt> targets.</p>
<pre class="code">
kyle@indigo64 ~/personal/projects/sandbox/clojure-utils[master]$ ant fetch-deps jar
Buildfile: build.xml

fetch-deps:
      [get] Getting: http://asymmetrical-view.com/personal/repo//ant-1.7.0.jar
      [get] To: /home/mortis/personal/projects/sandbox/clojure-utils/lib/ant-1.7.0.jar
      ...and lots more...

compile:
    [mkdir] Created dir: /home/mortis/personal/projects/sandbox/clojure-utils/target/classes
    [javac] Compiling 1 source file to /home/mortis/personal/projects/sandbox/clojure-utils/target/classes

jar:  
      [jar] Building jar: /home/mortis/personal/projects/sandbox/clojure-utils/target/krb-clojure-utils-0.1.jar

BUILD SUCCESSFUL
Total time: 23 seconds
kyle@indigo64 ~/personal/projects/sandbox/clojure-utils[master]$ ant repl

</pre>
<p>You can use <tt>ant repl</tt> to run a Clojure <span class="caps">REPL</span> with the necessary dependencies on the classpath.   Paste or type in the example functions to see them in action:</p>
<pre class="code">
(quartz-test)
;; wait a bit to see it run (it should run every 10s)
;; stop the scheduler to remove all tasks
(stop-scheduler)

;; define an atom to hold the count
(def *count* (atom 0))
;; schedule an anonymous function
(quartz-test-fn (fn [context] 
                  (reset! *count* (inc @*count*))
                  (prn (format "anon scheduled function! context=%s called %d times!" context @*count*))))
;; wait a bit to see it run (every 10s)
;; stop and exit the JVM
(stop-scheduler)
(System/exit 0)
</pre>
<p>The next thing I&#8217;d like to do is implement a prototype scheduler service exposing Quartz over <a href="http://amqp.org/"><span class="caps">AMQP</span></a> (<a href="http://www.rabbitmq.com/">RabbitMQ</a>).</p>
<p class="meta">Kyle Burton, 19 May 2009 &#8211; Wayne PA</p>]]></content:encoded>
    </item>
    
    <item>
      <title>Introduction to Git talk at PLUG West Tonight at 7pm</title>
      <link>http://blog.asymmetrical-view.com/2009/05/18/intro-to-git.html</link>
      <comments>http://blog.asymmetrical-view.com/2009/05/18/intro-to-git.html#comments</comments>

      <pubDate>2009-05-18T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2009/05/18/intro-to-git.html</guid>

      <id>http://blog.asymmetrical-view.com/2009/05/18/intro-to-git</id>
      <description><![CDATA[<h1>Introduction to Git talk at <span class="caps">PLUG</span> West Tonight at 7pm</h1>
<p>I&#8217;m giving my <a href="http://github.com/kyleburton/introduction-to-git/tree/master">Introduction to Git</a> talk tonight at the <a href="http://www.phillylinux.org/west.html">West</a> chapter of the <a href="http://www.phillylinux.org/">Philadelphia Linux Users Group</a>.  I&#8217;m bringing some minor give-aways, usb drives and post-it note pads, in case that is enticing :).</p>
<div style="width:425px;text-align:left" id="__ss_1452995"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/kyleburton/intro-to-git?type=presentation" title="Intro To Git">Intro To Git</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=introtogit-090518104200-phpapp02&stripped_title=intro-to-git" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=introtogit-090518104200-phpapp02&stripped_title=intro-to-git" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/kyleburton">kyleburton</a>.</div></div>
<p class="meta">Kyle Burton, 17 May 2009 &#8211; Wayne PA</p>]]></description>
      <content:encoded><![CDATA[<h1>Introduction to Git talk at <span class="caps">PLUG</span> West Tonight at 7pm</h1>
<p>I&#8217;m giving my <a href="http://github.com/kyleburton/introduction-to-git/tree/master">Introduction to Git</a> talk tonight at the <a href="http://www.phillylinux.org/west.html">West</a> chapter of the <a href="http://www.phillylinux.org/">Philadelphia Linux Users Group</a>.  I&#8217;m bringing some minor give-aways, usb drives and post-it note pads, in case that is enticing :).</p>
<div style="width:425px;text-align:left" id="__ss_1452995"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/kyleburton/intro-to-git?type=presentation" title="Intro To Git">Intro To Git</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=introtogit-090518104200-phpapp02&stripped_title=intro-to-git" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=introtogit-090518104200-phpapp02&stripped_title=intro-to-git" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/kyleburton">kyleburton</a>.</div></div>
<p class="meta">Kyle Burton, 17 May 2009 &#8211; Wayne PA</p>]]></content:encoded>
    </item>
    
    <item>
      <title>Extending Jekyll</title>
      <link>http://blog.asymmetrical-view.com/2009/05/17/extending-jekyll.html</link>
      <comments>http://blog.asymmetrical-view.com/2009/05/17/extending-jekyll.html#comments</comments>

      <pubDate>2009-05-17T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2009/05/17/extending-jekyll.html</guid>

      <id>http://blog.asymmetrical-view.com/2009/05/17/extending-jekyll</id>
      <description><![CDATA[<h1>Extending Jekyll</h1>
<p>After using <a href="http://www.jekyllrb.com/">Jekyll</a> to build my personal website, I was having some issues with my stylesheet not being reloaded by <a href="http://www.mozilla.com/firefox/">Firefox</a>.  Frameworks like <a href="http://rubyonrails.org/">Ruby on Rails</a> provide an <span class="caps">HTML</span> helper that add a short querystring which is simply the last modification time of the file being linked to.  This interacts nicely with the browse&#8217;s cache since it can cache the stylesheet and when you change it, the <span class="caps">URL</span> will be different (with the new mtime) and the browser will load the new stylesheet.</p>
<p>Rails provides <code>stylesheet_link_tag</code>, which you use as follows:</p>
<pre class="code">
  &lt;%= stylesheet_link_tag 'app', :media =&gt; "all" %&gt;
</pre>
<p><code>stylesheet_link_tag</code></code> then renders the following <span class="caps">HTML</span>:</p>
<pre class="code">
  &lt;link href="/stylesheets/app.css?1234672637" media="all" rel="stylesheet" type="text/css" /&gt;
</pre>
<p>Where <code>1234672637I</code> is the last modification time (or mtime) of the stylesheet file.  I wanted to have the same feature in Jekyll.  Jekyll uses of the <a href="http://www.liquidmarkup.org/">Liquid</a> text templating system, and Liquid supports being extended allowing you to add your own filters, tags and tag-blocks.  Tags are used for inserting content:</p>
<pre class="code">
   &lt;content type="html"&gt;{ { post.content } }&lt;/content&gt;
</pre>
<p>Filters are used to transform content, an example from the <a href="http://github.com/mojombo/mojombo.github.com/blob/master/atom.xml">atom.xml</a> formats the date:</p>
<pre class="code">
   &lt;updated&gt;{ { post.date | date_to_xmlschema } }&lt;/updated&gt;
</pre>
<p>What I wanted to be able to write was something like:</p>
<pre class="code">
   { % stylesheet "/css/style.css" % }
</pre>
<p>Which meant I had to make a new tag.  I created the tag file <code>lib/jekyll/tags/stylesheet_link.rb</code>:</p>
<pre class="code">
  module Jekyll

    class StylesheetTag &lt; Liquid::Tag
      def initialize(tag_name, file, tokens)
        super
        @file = file
      end

      def find_stylesheet(context)
        file = @file
        file.strip!
        file.gsub! /^["']/, ""
        file.gsub! /["']$/, ""
        if ! file =~ /.[a-z]+$/
          file = "#{file}.css"
        end

        files = [File.join(context.registers[:site].source, @file),
                 # strip a leading slash
                 File.join(context.registers[:site].source, @file[1..-1]),
                 ]
        files.each {|file|
          if File.exists? file
            return file
          end
        }
        return file
      end

      def render(context)
        file = find_stylesheet(context)

        mtime = nil
        if ! File.exists?(file)
          warn "Stylesheet file: '#{@file}' not found (#{file})"
          mtime = rand 1000000000
        else
          mtime = File.mtime(file).to_i
        end

        return %Q{&lt;link rel="stylesheet" href="#{@file}?#{mtime}" type="text/css" media="screen, projection" /&gt;}
      end
    end

  end

  Liquid::Template.register_tag('stylesheet', Jekyll::StylesheetTag)
</pre>
<p>All tags derive from Liquid::Tag and implement both <code>initialize</code> and <code>render</code>.  In the constructor the <code>StylesheetTag</code> saves off the argument (file).  In <code>render</code> it attempts to find the css file and then either uses a random value or the mtime of the file (if it was found), finally returning the string representing the stylesheet link.</p>
<p>Finally I added the module to the list of requires in <code>lib/jekyll.rb</code> so it is loaded when Jekyll runs:</p>
<pre class="code">
  ...
  # internal requires
  require 'jekyll/core_ext'
  require 'jekyll/pager'
  require 'jekyll/site'
  require 'jekyll/convertible'
  require 'jekyll/layout'
  require 'jekyll/page'
  require 'jekyll/post'
  require 'jekyll/filters'
  require 'jekyll/tags/highlight'
  require 'jekyll/tags/include'
  require 'jekyll/tags/stylesheet_link'
  require 'jekyll/albino'
  ...
</pre>
<p>Once that was completed the stylesheet tag generated links with the mtime as a query parameter and my stylesheets no longer had the caching issue.  I&#8217;m offering my changes back to <a href="http://github.com/mojombo" title="mojombo">Tom Preston-Werner</a>, but you can fork or clone <a href="http://github.com/kyleburton/jekyll/tree/master">my repository</a> if you want to try them yourself.</p>
<p class="meta">Kyle Burton, 17 May 2009 &#8211; Wayne PA</p>]]></description>
      <content:encoded><![CDATA[<h1>Extending Jekyll</h1>
<p>After using <a href="http://www.jekyllrb.com/">Jekyll</a> to build my personal website, I was having some issues with my stylesheet not being reloaded by <a href="http://www.mozilla.com/firefox/">Firefox</a>.  Frameworks like <a href="http://rubyonrails.org/">Ruby on Rails</a> provide an <span class="caps">HTML</span> helper that add a short querystring which is simply the last modification time of the file being linked to.  This interacts nicely with the browse&#8217;s cache since it can cache the stylesheet and when you change it, the <span class="caps">URL</span> will be different (with the new mtime) and the browser will load the new stylesheet.</p>
<p>Rails provides <code>stylesheet_link_tag</code>, which you use as follows:</p>
<pre class="code">
  &lt;%= stylesheet_link_tag 'app', :media =&gt; "all" %&gt;
</pre>
<p><code>stylesheet_link_tag</code></code> then renders the following <span class="caps">HTML</span>:</p>
<pre class="code">
  &lt;link href="/stylesheets/app.css?1234672637" media="all" rel="stylesheet" type="text/css" /&gt;
</pre>
<p>Where <code>1234672637I</code> is the last modification time (or mtime) of the stylesheet file.  I wanted to have the same feature in Jekyll.  Jekyll uses of the <a href="http://www.liquidmarkup.org/">Liquid</a> text templating system, and Liquid supports being extended allowing you to add your own filters, tags and tag-blocks.  Tags are used for inserting content:</p>
<pre class="code">
   &lt;content type="html"&gt;{ { post.content } }&lt;/content&gt;
</pre>
<p>Filters are used to transform content, an example from the <a href="http://github.com/mojombo/mojombo.github.com/blob/master/atom.xml">atom.xml</a> formats the date:</p>
<pre class="code">
   &lt;updated&gt;{ { post.date | date_to_xmlschema } }&lt;/updated&gt;
</pre>
<p>What I wanted to be able to write was something like:</p>
<pre class="code">
   { % stylesheet "/css/style.css" % }
</pre>
<p>Which meant I had to make a new tag.  I created the tag file <code>lib/jekyll/tags/stylesheet_link.rb</code>:</p>
<pre class="code">
  module Jekyll

    class StylesheetTag &lt; Liquid::Tag
      def initialize(tag_name, file, tokens)
        super
        @file = file
      end

      def find_stylesheet(context)
        file = @file
        file.strip!
        file.gsub! /^["']/, ""
        file.gsub! /["']$/, ""
        if ! file =~ /.[a-z]+$/
          file = "#{file}.css"
        end

        files = [File.join(context.registers[:site].source, @file),
                 # strip a leading slash
                 File.join(context.registers[:site].source, @file[1..-1]),
                 ]
        files.each {|file|
          if File.exists? file
            return file
          end
        }
        return file
      end

      def render(context)
        file = find_stylesheet(context)

        mtime = nil
        if ! File.exists?(file)
          warn "Stylesheet file: '#{@file}' not found (#{file})"
          mtime = rand 1000000000
        else
          mtime = File.mtime(file).to_i
        end

        return %Q{&lt;link rel="stylesheet" href="#{@file}?#{mtime}" type="text/css" media="screen, projection" /&gt;}
      end
    end

  end

  Liquid::Template.register_tag('stylesheet', Jekyll::StylesheetTag)
</pre>
<p>All tags derive from Liquid::Tag and implement both <code>initialize</code> and <code>render</code>.  In the constructor the <code>StylesheetTag</code> saves off the argument (file).  In <code>render</code> it attempts to find the css file and then either uses a random value or the mtime of the file (if it was found), finally returning the string representing the stylesheet link.</p>
<p>Finally I added the module to the list of requires in <code>lib/jekyll.rb</code> so it is loaded when Jekyll runs:</p>
<pre class="code">
  ...
  # internal requires
  require 'jekyll/core_ext'
  require 'jekyll/pager'
  require 'jekyll/site'
  require 'jekyll/convertible'
  require 'jekyll/layout'
  require 'jekyll/page'
  require 'jekyll/post'
  require 'jekyll/filters'
  require 'jekyll/tags/highlight'
  require 'jekyll/tags/include'
  require 'jekyll/tags/stylesheet_link'
  require 'jekyll/albino'
  ...
</pre>
<p>Once that was completed the stylesheet tag generated links with the mtime as a query parameter and my stylesheets no longer had the caching issue.  I&#8217;m offering my changes back to <a href="http://github.com/mojombo" title="mojombo">Tom Preston-Werner</a>, but you can fork or clone <a href="http://github.com/kyleburton/jekyll/tree/master">my repository</a> if you want to try them yourself.</p>
<p class="meta">Kyle Burton, 17 May 2009 &#8211; Wayne PA</p>]]></content:encoded>
    </item>
    
    <item>
      <title>Getting Started With Jekyll</title>
      <link>http://blog.asymmetrical-view.com/2009/05/14/starting-wtih-jekyll.html</link>
      <comments>http://blog.asymmetrical-view.com/2009/05/14/starting-wtih-jekyll.html#comments</comments>

      <pubDate>2009-05-14T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2009/05/14/starting-wtih-jekyll.html</guid>

      <id>http://blog.asymmetrical-view.com/2009/05/14/starting-wtih-jekyll</id>
      <description><![CDATA[<h1>Getting Started With Jekyll</h1>
<p>I took at look at <a href="http://cbcg.net/">Toby Di Pasquale&#8217;s website</a> tonight and it inspired me to get around to sprucing up my own site.</p>
<p>Toby used <a href="http://www.jekyllrb.com/">Jekyll</a>, a site generation and maintenance.  Jekyll allows you to maintain your site using <a href="http://wiki.github.com/tobi/liquid">liquid</a> (a text based templating tool), <a href="http://www.yaml.org/">Yaml</a> (for configuration) and <a href="http://maruku.rubyforge.org/">Markdown</a> (a simplified wiki-ish style markup language).  Jekyll is a bit different from dynamic Blogging or publishing platforms like <a href="http://wordpress.org/">WordPress</a> in that it intentionally generates your site as static content.  Most of the other publishing platforms dynamically generate their content at the time the page is requested by the browser.</p>
<p>Jekyll allows you to refactor your content, still allowing you to use templates and simplified markup, while allowing your site to be completely static.  This means you can deploy your site (or blog) to servers where you only have a web-server and no application software &#8211; it also means that your site will perform as well as your web-server can serve up static content, which is about as fast as you can get.</p>
<p>Setting the site up with Jekyll took only a few minutes&#8230;tweaking the css for the site and adding in some basic content took me a few hours.</p>
<h3>Installation</h3>
<p>You will need <a href="http://www.ruby-lang.org/en/">Ruby</a> installed along with <a href="http://docs.rubygems.org/">RubyGems</a>.  You will not need <a href="http://rubyonrails.org/">Ruby on Rails</a>.  Once Ruby and Gem are set up, follow the remaining instructions in the <a href="http://wiki.github.com/mojombo/jekyll/install">installation guide</a>.  A good place to start is by cloning one of the <a href="http://wiki.github.com/mojombo/jekyll/sites">example sites</a>:</p>
kyle@asymmetrical-view ~/projects$ git clone git://github.com/mojombo/mojombo.github.com.git
<p>This will give you a point of reference for creating your own site.  I made a directory and am using &quot;git&quot;h:ttp://git-scm.com/ to version my site.</p>
<h3>Create your _config.yml</h3>
<p>I initially had an incomplete `_config.yml` when I first tried to run Jekyll and it raised an exception.  Start with the downloaded example or use mine:</p>
<pre class="code">
    destination: ./_site
    auto:        false
    lsi:         false
    server_port: 4000
    pygments:    true
    markdown:    maruku
    permalink:   date
    maruku:
      use_tex:   false
      use_divs:  false
      png_dir:   images/latex
      png_url:   /images/latex
</pre>
<h3>Directory Structure</h3>
<p>I created a sub-directory for each of the major areas in the site (posts, projects, contact, talks and about), a directory for the &#8216;blog&#8217; posts (_posts) and for the layouts.</p>
<pre class="code">
./site/_posts/2000-05-14-starting-with-jekyll.textile
./site/projects/index.html
./site/index.html
./site/contact/index.html
./site/css/style.css
./site/_layouts/post.html
./site/_layouts/default.html
./site/_config.yml
./site/about/index.html
</pre>
<h3>Set up a Layout</h3>
<p>In the examples you&#8217;ll see a layout file in _layouts/default.html</p>
<p>The layouts are your page templates.  The template has the surrounding portion of the <span class="caps">HTML</span> page, with an inner yield block for the actual page content:</p>
<pre class="code">
  &lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
  &lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en-us"&gt;
  &lt;head&gt;
  ...
  &lt;div class="content"&gt;
    &lt;div style="margin-left: 22%;"&gt;
  { { content } }
  &lt;/div&gt;
  &lt;/div&gt;
  ...
  &lt;/body&gt;
  &lt;/html&gt;
</pre>
<p>Then make use of your layout, for example in my <code>./site/index.html</code>, I have a <a href="http://wiki.github.com/mojombo/jekyll/yaml-front-matter">Yaml front matter</a> that specifies the layout and the page title.</p>
<pre class="code">
  ---
  layout: default
  title: Seeking No Barriers To Abstraction
  ---
  &lt;div class="index-body"&gt;
    &lt;h1&gt;Welcome to Asymmetrical View&lt;/h1&gt;

    &lt;p&gt;
      This is the home site of Kyle Burton on the Internet.
    &lt;/p&gt;

    &lt;h1&gt;Recent Posts&lt;/h1&gt;
    &lt;ul class="posts"&gt;
      { %% for post in site.posts limit:5 %% }
        &lt;li&gt;&lt;span&gt;{ { post.date | date_to_string } }&lt;/span&gt; &amp;raquo; &lt;a href="{ { post.url } }"&gt;{ { post.title } }&lt;/a&gt;&lt;/li&gt;
      { %% endfor %% }
    &lt;/ul&gt;
  &lt;/div&gt;
</pre>
<h3>Creating Posts</h3>
<p>My posts are all in textile (<a href="http://maruku.rubyforge.org/">markdown</a>) format, using a similar technique as with the html files they have a <a href="http://wiki.github.com/mojombo/jekyll/yaml-front-matter">front matter</a> section and then some main content in the markup:</p>
<pre class="code">
  ---
  layout: post
  title: Getting Started With Jekyll
  ---

  h1. { { page.title } }

  I took at look at &lt;a href="http://cbcg.net/"&gt;Toby Di Pasquale's website&lt;/a&gt; tonight and it inspired me to get around to sprucing up my own site.
  
</pre>
<h3>Building and Testing Your Site</h3>
<p>To build out your site, just run jekyll.  You can also run it in a simple server mode in which it will attempt to recognize when you change files (via their last modification time) and rebuild the effected portions of your site.  One thing to keep in mind is that when you run jekyll with <code>--auto</code> it will not report on exceptions as robustly as it will when only invoked to perform teh build.  The workflow I use involves perdiocally restarting the jekyll server and removing the site build directory:</p>
<pre class="code">
  mortis@kburton-lin ~/personal/projects/this-blog/site[this-blog*]$ rm -rf _site/ &amp;&amp; jekyll  --auto --server 4001
</pre>
<p>When I stop seeing my changes reflected in the site I&#8217;ll <span class="caps">CTRL</span>-C Jekyl and re-run that command.</p>
<h3>Conclusion</h3>
<p>Installing and learning Jekyll was easy and it provides me with a much lighter weight process for maintaining my personal web site.</p>
<p class="meta">Kyle Burton, 14 May 2009 &#8211; Wayne PA</p>]]></description>
      <content:encoded><![CDATA[<h1>Getting Started With Jekyll</h1>
<p>I took at look at <a href="http://cbcg.net/">Toby Di Pasquale&#8217;s website</a> tonight and it inspired me to get around to sprucing up my own site.</p>
<p>Toby used <a href="http://www.jekyllrb.com/">Jekyll</a>, a site generation and maintenance.  Jekyll allows you to maintain your site using <a href="http://wiki.github.com/tobi/liquid">liquid</a> (a text based templating tool), <a href="http://www.yaml.org/">Yaml</a> (for configuration) and <a href="http://maruku.rubyforge.org/">Markdown</a> (a simplified wiki-ish style markup language).  Jekyll is a bit different from dynamic Blogging or publishing platforms like <a href="http://wordpress.org/">WordPress</a> in that it intentionally generates your site as static content.  Most of the other publishing platforms dynamically generate their content at the time the page is requested by the browser.</p>
<p>Jekyll allows you to refactor your content, still allowing you to use templates and simplified markup, while allowing your site to be completely static.  This means you can deploy your site (or blog) to servers where you only have a web-server and no application software &#8211; it also means that your site will perform as well as your web-server can serve up static content, which is about as fast as you can get.</p>
<p>Setting the site up with Jekyll took only a few minutes&#8230;tweaking the css for the site and adding in some basic content took me a few hours.</p>
<h3>Installation</h3>
<p>You will need <a href="http://www.ruby-lang.org/en/">Ruby</a> installed along with <a href="http://docs.rubygems.org/">RubyGems</a>.  You will not need <a href="http://rubyonrails.org/">Ruby on Rails</a>.  Once Ruby and Gem are set up, follow the remaining instructions in the <a href="http://wiki.github.com/mojombo/jekyll/install">installation guide</a>.  A good place to start is by cloning one of the <a href="http://wiki.github.com/mojombo/jekyll/sites">example sites</a>:</p>
kyle@asymmetrical-view ~/projects$ git clone git://github.com/mojombo/mojombo.github.com.git
<p>This will give you a point of reference for creating your own site.  I made a directory and am using &quot;git&quot;h:ttp://git-scm.com/ to version my site.</p>
<h3>Create your _config.yml</h3>
<p>I initially had an incomplete `_config.yml` when I first tried to run Jekyll and it raised an exception.  Start with the downloaded example or use mine:</p>
<pre class="code">
    destination: ./_site
    auto:        false
    lsi:         false
    server_port: 4000
    pygments:    true
    markdown:    maruku
    permalink:   date
    maruku:
      use_tex:   false
      use_divs:  false
      png_dir:   images/latex
      png_url:   /images/latex
</pre>
<h3>Directory Structure</h3>
<p>I created a sub-directory for each of the major areas in the site (posts, projects, contact, talks and about), a directory for the &#8216;blog&#8217; posts (_posts) and for the layouts.</p>
<pre class="code">
./site/_posts/2000-05-14-starting-with-jekyll.textile
./site/projects/index.html
./site/index.html
./site/contact/index.html
./site/css/style.css
./site/_layouts/post.html
./site/_layouts/default.html
./site/_config.yml
./site/about/index.html
</pre>
<h3>Set up a Layout</h3>
<p>In the examples you&#8217;ll see a layout file in _layouts/default.html</p>
<p>The layouts are your page templates.  The template has the surrounding portion of the <span class="caps">HTML</span> page, with an inner yield block for the actual page content:</p>
<pre class="code">
  &lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
  &lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en-us"&gt;
  &lt;head&gt;
  ...
  &lt;div class="content"&gt;
    &lt;div style="margin-left: 22%;"&gt;
  { { content } }
  &lt;/div&gt;
  &lt;/div&gt;
  ...
  &lt;/body&gt;
  &lt;/html&gt;
</pre>
<p>Then make use of your layout, for example in my <code>./site/index.html</code>, I have a <a href="http://wiki.github.com/mojombo/jekyll/yaml-front-matter">Yaml front matter</a> that specifies the layout and the page title.</p>
<pre class="code">
  ---
  layout: default
  title: Seeking No Barriers To Abstraction
  ---
  &lt;div class="index-body"&gt;
    &lt;h1&gt;Welcome to Asymmetrical View&lt;/h1&gt;

    &lt;p&gt;
      This is the home site of Kyle Burton on the Internet.
    &lt;/p&gt;

    &lt;h1&gt;Recent Posts&lt;/h1&gt;
    &lt;ul class="posts"&gt;
      { %% for post in site.posts limit:5 %% }
        &lt;li&gt;&lt;span&gt;{ { post.date | date_to_string } }&lt;/span&gt; &amp;raquo; &lt;a href="{ { post.url } }"&gt;{ { post.title } }&lt;/a&gt;&lt;/li&gt;
      { %% endfor %% }
    &lt;/ul&gt;
  &lt;/div&gt;
</pre>
<h3>Creating Posts</h3>
<p>My posts are all in textile (<a href="http://maruku.rubyforge.org/">markdown</a>) format, using a similar technique as with the html files they have a <a href="http://wiki.github.com/mojombo/jekyll/yaml-front-matter">front matter</a> section and then some main content in the markup:</p>
<pre class="code">
  ---
  layout: post
  title: Getting Started With Jekyll
  ---

  h1. { { page.title } }

  I took at look at &lt;a href="http://cbcg.net/"&gt;Toby Di Pasquale's website&lt;/a&gt; tonight and it inspired me to get around to sprucing up my own site.
  
</pre>
<h3>Building and Testing Your Site</h3>
<p>To build out your site, just run jekyll.  You can also run it in a simple server mode in which it will attempt to recognize when you change files (via their last modification time) and rebuild the effected portions of your site.  One thing to keep in mind is that when you run jekyll with <code>--auto</code> it will not report on exceptions as robustly as it will when only invoked to perform teh build.  The workflow I use involves perdiocally restarting the jekyll server and removing the site build directory:</p>
<pre class="code">
  mortis@kburton-lin ~/personal/projects/this-blog/site[this-blog*]$ rm -rf _site/ &amp;&amp; jekyll  --auto --server 4001
</pre>
<p>When I stop seeing my changes reflected in the site I&#8217;ll <span class="caps">CTRL</span>-C Jekyl and re-run that command.</p>
<h3>Conclusion</h3>
<p>Installing and learning Jekyll was easy and it provides me with a much lighter weight process for maintaining my personal web site.</p>
<p class="meta">Kyle Burton, 14 May 2009 &#8211; Wayne PA</p>]]></content:encoded>
    </item>
    
    <item>
      <title>Introduction to Git talk at PLUG North Tonight at 7pm</title>
      <link>http://blog.asymmetrical-view.com/2009/05/11/intro-to-git.html</link>
      <comments>http://blog.asymmetrical-view.com/2009/05/11/intro-to-git.html#comments</comments>

      <pubDate>2009-05-11T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2009/05/11/intro-to-git.html</guid>

      <id>http://blog.asymmetrical-view.com/2009/05/11/intro-to-git</id>
      <description><![CDATA[<h1>Introduction to Git talk at <span class="caps">PLUG</span> North Tonight at 7pm</h1>
<p>I&#8217;m giving my <a href="http://github.com/kyleburton/introduction-to-git/tree/master">Introduction to Git</a> talk tonight at the <a href="http://www.phillylinux.org/north.html">north</a> chapter of the <a href="http://www.phillylinux.org/">Philadelphia Linux Users Group</a>.  I&#8217;m bringing some minor give-aways, usb drives and post-it note pads, in case that is enticing :).</p>
<div style="width:425px;text-align:left" id="__ss_1452995"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/kyleburton/intro-to-git?type=presentation" title="Intro To Git">Intro To Git</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=introtogit-090518104200-phpapp02&stripped_title=intro-to-git" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=introtogit-090518104200-phpapp02&stripped_title=intro-to-git" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/kyleburton">kyleburton</a>.</div></div>
<p class="meta">Kyle Burton, 11 May 2009 &#8211; Wayne PA</p>]]></description>
      <content:encoded><![CDATA[<h1>Introduction to Git talk at <span class="caps">PLUG</span> North Tonight at 7pm</h1>
<p>I&#8217;m giving my <a href="http://github.com/kyleburton/introduction-to-git/tree/master">Introduction to Git</a> talk tonight at the <a href="http://www.phillylinux.org/north.html">north</a> chapter of the <a href="http://www.phillylinux.org/">Philadelphia Linux Users Group</a>.  I&#8217;m bringing some minor give-aways, usb drives and post-it note pads, in case that is enticing :).</p>
<div style="width:425px;text-align:left" id="__ss_1452995"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/kyleburton/intro-to-git?type=presentation" title="Intro To Git">Intro To Git</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=introtogit-090518104200-phpapp02&stripped_title=intro-to-git" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=introtogit-090518104200-phpapp02&stripped_title=intro-to-git" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/kyleburton">kyleburton</a>.</div></div>
<p class="meta">Kyle Burton, 11 May 2009 &#8211; Wayne PA</p>]]></content:encoded>
    </item>
    
    <item>
      <title>Introduction to Git talk at PLUG Central Tonight at 7pm</title>
      <link>http://blog.asymmetrical-view.com/2009/05/06/intro-to-git.html</link>
      <comments>http://blog.asymmetrical-view.com/2009/05/06/intro-to-git.html#comments</comments>

      <pubDate>2009-05-06T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2009/05/06/intro-to-git.html</guid>

      <id>http://blog.asymmetrical-view.com/2009/05/06/intro-to-git</id>
      <description><![CDATA[<h1>Introduction to Git talk at <span class="caps">PLUG</span> Central Tonight at 7pm</h1>
<p>I&#8217;m giving my <a href="http://github.com/kyleburton/introduction-to-git/tree/master">Introduction to Git</a> talk tonight at <span class="caps">PLUG</span> Central the main chapter of the <a href="http://www.phillylinux.org/">Philadelphia Linux Users Group</a>.  I&#8217;m bringing some minor give-aways, usb drives and post-it note pads, in case that is enticing :).</p>
<div style="width:425px;text-align:left" id="__ss_1452995"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/kyleburton/intro-to-git?type=presentation" title="Intro To Git">Intro To Git</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=introtogit-090518104200-phpapp02&stripped_title=intro-to-git" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=introtogit-090518104200-phpapp02&stripped_title=intro-to-git" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/kyleburton">kyleburton</a>.</div></div>
<p class="meta">Kyle Burton, 06 May 2009 &#8211; Wayne PA</p>]]></description>
      <content:encoded><![CDATA[<h1>Introduction to Git talk at <span class="caps">PLUG</span> Central Tonight at 7pm</h1>
<p>I&#8217;m giving my <a href="http://github.com/kyleburton/introduction-to-git/tree/master">Introduction to Git</a> talk tonight at <span class="caps">PLUG</span> Central the main chapter of the <a href="http://www.phillylinux.org/">Philadelphia Linux Users Group</a>.  I&#8217;m bringing some minor give-aways, usb drives and post-it note pads, in case that is enticing :).</p>
<div style="width:425px;text-align:left" id="__ss_1452995"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/kyleburton/intro-to-git?type=presentation" title="Intro To Git">Intro To Git</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=introtogit-090518104200-phpapp02&stripped_title=intro-to-git" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=introtogit-090518104200-phpapp02&stripped_title=intro-to-git" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/kyleburton">kyleburton</a>.</div></div>
<p class="meta">Kyle Burton, 06 May 2009 &#8211; Wayne PA</p>]]></content:encoded>
    </item>
    
    <item>
      <title>List Comprehensions in Clojure</title>
      <link>http://blog.asymmetrical-view.com/2008/11/18/list-comprehensions-in-clojure.html</link>
      <comments>http://blog.asymmetrical-view.com/2008/11/18/list-comprehensions-in-clojure.html#comments</comments>

      <pubDate>2008-11-18T00:00:00-05:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2008/11/18/list-comprehensions-in-clojure.html</guid>

      <id>http://blog.asymmetrical-view.com/2008/11/18/list-comprehensions-in-clojure</id>
      <description><![CDATA[<h1>List Comprehensions in Clojure</h1>
<p>This is a basic example of the list comprehension support in <a href="http://clojure.org/">Clojure</a>, the same feature supported by <a href="http://erlang.org/">Erlang</a>, <a href="http://www.haskell.org/">Haskell</a> and Common Lisp (via a libraries like <a href="http://github.com/jmbr/incf-cl/tree/master">incf-cl</a>).</p>
<pre class="code">
;; generate the positions of a chess board:
(for [file "ABCDEFGH"
      rank (range 1 9)]
  (format "%c%d" file rank))

;; Evaluate and put the result into the buffer: C-u 8 C-x C-e
;; ("A1" "A2" "A3" "A4" "A5" "A6" "A7" "A8" 
;;  "B1" "B2" "B3" "B4" "B5" "B6" "B7" "B8" 
;;  "C1" "C2" "C3" "C4" "C5" "C6" "C7" "C8" 
;;  "D1" "D2" "D3" "D4" "D5" "D6" "D7" "D8" 
;;  "E1" "E2" "E3" "E4" "E5" "E6" "E7" "E8" 
;;  "F1" "F2" "F3" "F4" "F5" "F6" "F7" "F8" 
;;  "G1" "G2" "G3" "G4" "G5" "G6" "G7" "G8" 
;;  "H1" "H2" "H3" "H4" "H5" "H6" "H7" "H8")

(count (for [file "ABCDEFGH"
              rank (range 1 9)]
          (format "%c%d" file rank)))
;; Make sure it 8x8 (64)

;; the pythagorean triples example:
(for [aa (range 1 10)
      bb (range 1 10)
      cc (range 1 10)
      :when (= (* cc cc)
               (+ (* aa aa)
                  (* bb bb)))]
  (list aa bb cc))
;; ((3 4 5) (4 3 5))

;; all permutations
(defn all-permutations [things]
  (if (= 1 (count things))
    (list things)
    (for [head things
          tail (all-permutations (disj (set things) head))]
      (do
        (cons head tail)))))

(all-permutations '(a b c))
;; ((a c b) (a b c) (b a c) (b c a) (c a b) (c b a))

</pre>
<p class="meta">Kyle Burton, 11 Nov 2008 &#8211; Wayne PA</p>]]></description>
      <content:encoded><![CDATA[<h1>List Comprehensions in Clojure</h1>
<p>This is a basic example of the list comprehension support in <a href="http://clojure.org/">Clojure</a>, the same feature supported by <a href="http://erlang.org/">Erlang</a>, <a href="http://www.haskell.org/">Haskell</a> and Common Lisp (via a libraries like <a href="http://github.com/jmbr/incf-cl/tree/master">incf-cl</a>).</p>
<pre class="code">
;; generate the positions of a chess board:
(for [file "ABCDEFGH"
      rank (range 1 9)]
  (format "%c%d" file rank))

;; Evaluate and put the result into the buffer: C-u 8 C-x C-e
;; ("A1" "A2" "A3" "A4" "A5" "A6" "A7" "A8" 
;;  "B1" "B2" "B3" "B4" "B5" "B6" "B7" "B8" 
;;  "C1" "C2" "C3" "C4" "C5" "C6" "C7" "C8" 
;;  "D1" "D2" "D3" "D4" "D5" "D6" "D7" "D8" 
;;  "E1" "E2" "E3" "E4" "E5" "E6" "E7" "E8" 
;;  "F1" "F2" "F3" "F4" "F5" "F6" "F7" "F8" 
;;  "G1" "G2" "G3" "G4" "G5" "G6" "G7" "G8" 
;;  "H1" "H2" "H3" "H4" "H5" "H6" "H7" "H8")

(count (for [file "ABCDEFGH"
              rank (range 1 9)]
          (format "%c%d" file rank)))
;; Make sure it 8x8 (64)

;; the pythagorean triples example:
(for [aa (range 1 10)
      bb (range 1 10)
      cc (range 1 10)
      :when (= (* cc cc)
               (+ (* aa aa)
                  (* bb bb)))]
  (list aa bb cc))
;; ((3 4 5) (4 3 5))

;; all permutations
(defn all-permutations [things]
  (if (= 1 (count things))
    (list things)
    (for [head things
          tail (all-permutations (disj (set things) head))]
      (do
        (cons head tail)))))

(all-permutations '(a b c))
;; ((a c b) (a b c) (b a c) (b c a) (c a b) (c b a))

</pre>
<p class="meta">Kyle Burton, 11 Nov 2008 &#8211; Wayne PA</p>]]></content:encoded>
    </item>
    
    <item>
      <title>Cloud Con East 2008</title>
      <link>http://blog.asymmetrical-view.com/2008/10/21/cloud-con-east-notes.html</link>
      <comments>http://blog.asymmetrical-view.com/2008/10/21/cloud-con-east-notes.html#comments</comments>

      <pubDate>2008-10-21T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2008/10/21/cloud-con-east-notes.html</guid>

      <id>http://blog.asymmetrical-view.com/2008/10/21/cloud-con-east-notes</id>
      <description><![CDATA[<h1>Cloud Con East 2008</h1>
<p>Overall <a href="http://www.chariotsolutions.com/">Chariot Solutions</a> <a href="http://www.cloudconeast.com/">Computing Among The Clouds</a> was a great conference.</p>
<p>Cloud computing is not well defined and mostly correlates to the movement of applications, services and compute resources (machines, storage, queuing services) into hosted data centers and billed based on usage.  It brings with it concepts of dynamic provisioning and relinquishing of resources.</p>
<p>So, how do you evaluate the current cloud offerings?</p>
<h3>Stick With Your Own Data Center If</h3>
<h5>You have a steady baseline load.</h5>
<p><span class="caps">AWS</span>, used 24&#215;7&#215;365 is more expensive (in 2008) than owning and hosting physical machines in terms of capex for many organizations.</p>
<h5>You have hard SLAs</h5>
<p>If you need more than 3 or 4 9&#8217;s, you are better off with more traditional hosting or your own data center.  Currently <span class="caps">AWS</span> doesn&#8217;t guarantee up-time as well as many medium and large business can with their own dedicated IT staffs and data centers.</p>
<h5>You can handle your peak loads</h5>
<p>If you have constant processing loads or have an <span class="caps">SLA</span> that requires you to have enough spare capacity to handle any given peak, then you&#8217;re better served with your own data center.  There is no reason to rent capacity if you already have it.</p>
<h5>You have sensitive data</h5>
<p>You may require more certainty about where the data gets stored and who has access to it.  This is likely to be a legislative or contractual issue than organizational.  Though there are cloud computing platforms and initiatives that are working towards security data data protection certifications.</p>
<h3>On Demand (<span class="caps">AWS</span> EC2) Is Right For You If</h3>
<h5>You have intermittent load</h5>
<p>Your needs scale up and then can scale back down, thus saving on keeping spare capacity on-line.</p>
<h5>You can plan for the Peaks</h5>
<p>If you can anticipate load spikes, then you will have time to provision resources to handle those loads.</p>
<h5>You have no capitol budget</h5>
<p>If you have no capitol budget but must do large scale testing or data analysis, then renting resources will be significantly cheaper than buying hardware.</p>
<h5>You want to charge based on utilization</h5>
<p>You have a service where you can charge in direct proportion to utilization rather than based on capacity.</p>
<h3>Higher Level Application Stacks, PaaS Google App Engine</h3>
<p>Keep in mind these are new and the space is still being explored, more will appear.   Models will develop around these PaaS providers [Platform as a Service], more languages and frameworks will be supported &#8211; though they will mostly will be based on those that can be easily hosted, sandboxed and run-time instrumented, which is why you&#8217;re seeing Python first and Java following closely along.</p>
<p>These providers hide the provisioning from you.  Google&#8217;s offering dynamically scales your application up and down based on utilization.  This provides a significant reduction in your design and administrative overhead for web development projects.</p>
<p>Simplicity of application development <em>and</em> scalability are rarely found in existing technologies, this will be one of the more interesting segments to watch mature.</p>
<p>Organizations and individuals are starting to learn how they need to change the design of their services and applications to take better advantage of the Cloud.  It takes a change in mind-set &#8211; the phrase was dropped &#8220;Machine Instances are the new processes&#8221; and I think that&#8217;s an appropriate framing of one of the changes in mindset for taking advantage of the mass of resources that is becoming available.</p>
<p>Changing your software to be more easily bootstrapped, eliminate the assumption that you have access to local, disk based services &#8211; everything is pulled remotely, use URLs, and services &#8211; don&#8217;t assume local interfaces, assume remote.  Design to come up / boot faster &#8211; scaling up / down quickly you don&#8217;t get the same amortization over time for start up costs.  Design with the crash fast mentality &#8211; as robust as these systems are, you should still design with the idea that the system could go away at any moment.  In addition to the benefit of quickly recovering from unexpected outages, this allows you to scale <em>down</em> faster, not just up.  Keep your persistent data in the providers data stores and use the provided queuing systems to distribute work.</p>
<h3>Gaining Wider Acceptance</h3>
<p>There are some things these offerings need to do to gain wider acceptance.</p>
<p>Harder SLAs will develop as there is more competition.  Higher level tools will develop on top of the instance-based cloud offerings (EC2) to allow for more automated provisioning &#8211; this will make it easier for you, but as easy as the PaaS stacks like <span class="caps">GAE</span> will make it.</p>
<p>We&#8217;ll see tools and offerings develop that will come down towards traditional data centers to allow a simpler mixing of a traditional service with bleed over to the cloud as resources need to be scaled up but also so that you can have control over the processing of your (sensitive) data in your own protected environment but push generic activity up into the cloud as necessary.</p>
<h3>Other notable happenings</h3>
<p>Microsoft is creating AMIs for Windows on EC2.</p>
<p>Google just announced that Java will be a supported App Engine development language &#8211; previously only Python was supported.</p>
<h3>Haskell in the corporate environment</h3>
<p>This session seemed out of place for the event &#8211; not really Cloud oriented.  Though I personally see Functional Programming being a larger industry trend and something that facilitates concurrency and parallelization.  It follows from structured -&gt; procedural -&gt; object oriented -&gt; functional &#8211; with respect to the time line of coming out of academia at least, not necessarily the idea of one being &#8216;higher level&#8217; than the other &#8211; though so far, time has implied that with the other programming paradigms.</p>
<p>The presenter, Jeff Polakow, is using it extensively at his current employer.</p>
<p>Those kinds of firms (Wall St.) allow a lot of latitude to the technical staff, so its easier to experiment (R&amp;D) with new technologies.  It&#8217;s much harder for a company like my own to decide to take on something like this &#8211; it&#8217;s hard to find developers who know how to develop, deploy, monitor and design with these technologies.</p>
<p>Functional Programming trend is being pushed into industry by the shift to multi-core, the past difficulties of developing concurrent, the more wide spread need for parallel/distributed applications (concurrency is the new garbage collection &#8211; it will become something that developers no longer control manually), the need for infrastructural level automatic scaling, and the easier path to robustness that languages like Erlang offer.</p>
<p>In languages like Java, you have to take into consideration all the libraries (where the default development practice in many cases is to not consider the re-entrancy &#8211; you can&#8217;t make the assumption that code is thread-safe in Java) you&#8217;re using with respect to their referential transparency &#8211; it&#8217;s not the default.  In the FP languages referential transparency is the <em>default</em> case, so you can, in general, make that assumption.  The underlying stack can also make that assumption about your code as well &#8211; which is why the concurrency / distribution model is less coupled to the implementation than it is in the more imperative languages.</p>
<h3>Horizontal Scaling with HiveDB</h3>
<p>CafePress has a <em>large</em> catalog.  I was surprised to hear that they have 265 million products across all their customers catalogs.  They have a low margin based on the aggregate amount of data they have to store and serve up, so commercial solutions like Oracle were just not an option for them simply due to cost.</p>
<p>Cafe spent time analyzing their options and didn&#8217;t find anything that fit their needs (cost, performance, on-line resharding), and went down the path of creating a more scalable data storage architecture themselves.</p>
<p>The solution they created performs better, scales better, is more robust and has a better <span class="caps">SLA</span> than many of the commercial solutions (their words).</p>
<p>Cafe&#8217;s <span class="caps">DAL</span> is effectively a hibernate extension that uses MySQL to do data partitioning (pseudo-automatically) by using a set of replicated MySQL databases as a catalog to map to where the data is stored for your shard (replicated 3x).  The system supports dynamic repartitioning &#8211; migration of shards away from a shard-host to get less busy data away from data that is more &#8216;hot&#8217; &#8211; the busiest data sets end up on their own shard-node with everything else having been pushed away from them.</p>
<p>They only need to &#8216;lock&#8217; is for a single user when migrating their data off the shard.  This is a write-lock, not a read lock &#8211; it only keeps the user from updating their own catalog of products while the move is taking place.  Most users never notice when this happens.  The system as a whole doesn&#8217;t go down (their words).  The MySQL catalogs are replicated (3 machines, master-master, writing to 1) and can be upgraded by taking 1 of the 3 out of the cluster at a time.  The same kind of approach goes for the other sharing servers.</p>
<h3>Panel Discussion</h3>
<p>The panel discussion was most memorable for how Chris and Toby seemed to dominate the discussion.</p>
<h3>Hive and Hadoop</h3>
<p>Hive is a data storage system developed on top of Hadoop with its own query language (HiveQL), built by Facebook.  The goals are a bit different from HiveDB &#8211; HiveDB is more for <span class="caps">OLTP</span>, while Hive is more for large-scale analytics.  Being built on top of Hadoop, HiveDB is much more batch oriented.  Facebook uses it for doing analytics, data-mining, and machine-learning of their user and transactional data sets (logs, user activities, etc.) to mine out aggregate and trending intelligence from the large data set.</p>
<p>Interesting fact: Facebook&#8217;s Hive sees <strong>2Tb</strong> of growth <em>per</em> <strong><em>day</em></strong>.</p>
<h3>Building Scalable Web Applications with Google App Engine</h3>
<p>PaaS stacks like <span class="caps">GAE</span> take a more managed environment approach than the more raw or primitive services provided by <span class="caps">AWS</span> style on-demand services.  The two fit into different use cases though and, <span class="caps">IMO</span>, one will not necessarily eliminate the other.</p>
<p><span class="caps">GAE</span> takes away from you all the concerns about deployment, production architecture, system management or administration.  It gives you a data store with an OO <span class="caps">API</span>, and a web-app development environment that you develop your application within.  There are things you can&#8217;t do, for example, you can&#8217;t run arbitrary software or services on <span class="caps">GAE</span> like you can on the more machine-image based cloud services (<span class="caps">AWS</span> EC2).</p>
<p>What you gain from giving up those capabilities is Google&#8217;s infrastructure for scaling, it becomes <em>your</em> infrastructure for scaling.  Your app is designed in a pseudo-functional way &#8211; the stack encourages you to design your app to perform all dynamism at put/post time and to just render/display at get time.  This approach helps with the scaling of the system.  Storage location transparency helps with spooling up other instances of the app in disparate data centers, etc.</p>
<p>This kind of stack really makes it easy to develop the most common case of web applications &#8211; it is both easy to do and it scales.  This is a combination that you rarely see in a platform or technology.</p>
<p>I see these kinds of stacks as becoming more established and a large part of Internet based application development &#8211; I think that more organizations will offer these kind of stacks across more technologies.</p>
<p>My advice: You should sign up for an account and try <a href="http://code.google.com/appengine/"><span class="caps">GAE</span></a> out.</p>
<h3>Developing and Deploying Java applications on Amazon EC2</h3>
<p>Chris Richardson has created cloud-tools, a package of utilities (and a <a href="http://maven.apache.org/">maven</a> plug-in) for provisioning EC2 instances, pushing your application up and executing tasks across your cluster of instances.  The tools look like they make it very easy to get your Java app into EC2.</p>
<h2>Conclusion</h2>
<p>The main theme I took away from it is that on-demand computing is a continuing trend.  Services will continue to appear and be developed that will make taking advantage of these resource pools easier and more cost effective.</p>
<p>The trend for physical data centers will continue to become more and more outsourced to organizations that can provide those services with greater economy of scale.  Currently Amazon&#8217;s offerings are slightly more expensive than a hosted system that you own &#8211; in the case where you need up-time or have high constant utilization.  More guidelines are being developed showing when the trade off is appropriate.  As a trend, cloud computing is still new and not well defined &#8211; it is likely that these trade offs will shift &#8211; even as soon as over the next few years (eg: it is likely, in my opinion, that the raw cost of 24&#215;7 allocation for SMBs will fall below the cost of ownership due to these on-demand provider&#8217;s economies of scale).</p>
<p>We&#8217;re past the point of asking if your organization can make use of these on-demand providers and to the point where you should be identifying the areas where you can realize savings by taking advantage of these services.</p>
<p class="meta">Kyle Burton, 21 Oct 2008 &#8211; Malvern PA</p>]]></description>
      <content:encoded><![CDATA[<h1>Cloud Con East 2008</h1>
<p>Overall <a href="http://www.chariotsolutions.com/">Chariot Solutions</a> <a href="http://www.cloudconeast.com/">Computing Among The Clouds</a> was a great conference.</p>
<p>Cloud computing is not well defined and mostly correlates to the movement of applications, services and compute resources (machines, storage, queuing services) into hosted data centers and billed based on usage.  It brings with it concepts of dynamic provisioning and relinquishing of resources.</p>
<p>So, how do you evaluate the current cloud offerings?</p>
<h3>Stick With Your Own Data Center If</h3>
<h5>You have a steady baseline load.</h5>
<p><span class="caps">AWS</span>, used 24&#215;7&#215;365 is more expensive (in 2008) than owning and hosting physical machines in terms of capex for many organizations.</p>
<h5>You have hard SLAs</h5>
<p>If you need more than 3 or 4 9&#8217;s, you are better off with more traditional hosting or your own data center.  Currently <span class="caps">AWS</span> doesn&#8217;t guarantee up-time as well as many medium and large business can with their own dedicated IT staffs and data centers.</p>
<h5>You can handle your peak loads</h5>
<p>If you have constant processing loads or have an <span class="caps">SLA</span> that requires you to have enough spare capacity to handle any given peak, then you&#8217;re better served with your own data center.  There is no reason to rent capacity if you already have it.</p>
<h5>You have sensitive data</h5>
<p>You may require more certainty about where the data gets stored and who has access to it.  This is likely to be a legislative or contractual issue than organizational.  Though there are cloud computing platforms and initiatives that are working towards security data data protection certifications.</p>
<h3>On Demand (<span class="caps">AWS</span> EC2) Is Right For You If</h3>
<h5>You have intermittent load</h5>
<p>Your needs scale up and then can scale back down, thus saving on keeping spare capacity on-line.</p>
<h5>You can plan for the Peaks</h5>
<p>If you can anticipate load spikes, then you will have time to provision resources to handle those loads.</p>
<h5>You have no capitol budget</h5>
<p>If you have no capitol budget but must do large scale testing or data analysis, then renting resources will be significantly cheaper than buying hardware.</p>
<h5>You want to charge based on utilization</h5>
<p>You have a service where you can charge in direct proportion to utilization rather than based on capacity.</p>
<h3>Higher Level Application Stacks, PaaS Google App Engine</h3>
<p>Keep in mind these are new and the space is still being explored, more will appear.   Models will develop around these PaaS providers [Platform as a Service], more languages and frameworks will be supported &#8211; though they will mostly will be based on those that can be easily hosted, sandboxed and run-time instrumented, which is why you&#8217;re seeing Python first and Java following closely along.</p>
<p>These providers hide the provisioning from you.  Google&#8217;s offering dynamically scales your application up and down based on utilization.  This provides a significant reduction in your design and administrative overhead for web development projects.</p>
<p>Simplicity of application development <em>and</em> scalability are rarely found in existing technologies, this will be one of the more interesting segments to watch mature.</p>
<p>Organizations and individuals are starting to learn how they need to change the design of their services and applications to take better advantage of the Cloud.  It takes a change in mind-set &#8211; the phrase was dropped &#8220;Machine Instances are the new processes&#8221; and I think that&#8217;s an appropriate framing of one of the changes in mindset for taking advantage of the mass of resources that is becoming available.</p>
<p>Changing your software to be more easily bootstrapped, eliminate the assumption that you have access to local, disk based services &#8211; everything is pulled remotely, use URLs, and services &#8211; don&#8217;t assume local interfaces, assume remote.  Design to come up / boot faster &#8211; scaling up / down quickly you don&#8217;t get the same amortization over time for start up costs.  Design with the crash fast mentality &#8211; as robust as these systems are, you should still design with the idea that the system could go away at any moment.  In addition to the benefit of quickly recovering from unexpected outages, this allows you to scale <em>down</em> faster, not just up.  Keep your persistent data in the providers data stores and use the provided queuing systems to distribute work.</p>
<h3>Gaining Wider Acceptance</h3>
<p>There are some things these offerings need to do to gain wider acceptance.</p>
<p>Harder SLAs will develop as there is more competition.  Higher level tools will develop on top of the instance-based cloud offerings (EC2) to allow for more automated provisioning &#8211; this will make it easier for you, but as easy as the PaaS stacks like <span class="caps">GAE</span> will make it.</p>
<p>We&#8217;ll see tools and offerings develop that will come down towards traditional data centers to allow a simpler mixing of a traditional service with bleed over to the cloud as resources need to be scaled up but also so that you can have control over the processing of your (sensitive) data in your own protected environment but push generic activity up into the cloud as necessary.</p>
<h3>Other notable happenings</h3>
<p>Microsoft is creating AMIs for Windows on EC2.</p>
<p>Google just announced that Java will be a supported App Engine development language &#8211; previously only Python was supported.</p>
<h3>Haskell in the corporate environment</h3>
<p>This session seemed out of place for the event &#8211; not really Cloud oriented.  Though I personally see Functional Programming being a larger industry trend and something that facilitates concurrency and parallelization.  It follows from structured -&gt; procedural -&gt; object oriented -&gt; functional &#8211; with respect to the time line of coming out of academia at least, not necessarily the idea of one being &#8216;higher level&#8217; than the other &#8211; though so far, time has implied that with the other programming paradigms.</p>
<p>The presenter, Jeff Polakow, is using it extensively at his current employer.</p>
<p>Those kinds of firms (Wall St.) allow a lot of latitude to the technical staff, so its easier to experiment (R&amp;D) with new technologies.  It&#8217;s much harder for a company like my own to decide to take on something like this &#8211; it&#8217;s hard to find developers who know how to develop, deploy, monitor and design with these technologies.</p>
<p>Functional Programming trend is being pushed into industry by the shift to multi-core, the past difficulties of developing concurrent, the more wide spread need for parallel/distributed applications (concurrency is the new garbage collection &#8211; it will become something that developers no longer control manually), the need for infrastructural level automatic scaling, and the easier path to robustness that languages like Erlang offer.</p>
<p>In languages like Java, you have to take into consideration all the libraries (where the default development practice in many cases is to not consider the re-entrancy &#8211; you can&#8217;t make the assumption that code is thread-safe in Java) you&#8217;re using with respect to their referential transparency &#8211; it&#8217;s not the default.  In the FP languages referential transparency is the <em>default</em> case, so you can, in general, make that assumption.  The underlying stack can also make that assumption about your code as well &#8211; which is why the concurrency / distribution model is less coupled to the implementation than it is in the more imperative languages.</p>
<h3>Horizontal Scaling with HiveDB</h3>
<p>CafePress has a <em>large</em> catalog.  I was surprised to hear that they have 265 million products across all their customers catalogs.  They have a low margin based on the aggregate amount of data they have to store and serve up, so commercial solutions like Oracle were just not an option for them simply due to cost.</p>
<p>Cafe spent time analyzing their options and didn&#8217;t find anything that fit their needs (cost, performance, on-line resharding), and went down the path of creating a more scalable data storage architecture themselves.</p>
<p>The solution they created performs better, scales better, is more robust and has a better <span class="caps">SLA</span> than many of the commercial solutions (their words).</p>
<p>Cafe&#8217;s <span class="caps">DAL</span> is effectively a hibernate extension that uses MySQL to do data partitioning (pseudo-automatically) by using a set of replicated MySQL databases as a catalog to map to where the data is stored for your shard (replicated 3x).  The system supports dynamic repartitioning &#8211; migration of shards away from a shard-host to get less busy data away from data that is more &#8216;hot&#8217; &#8211; the busiest data sets end up on their own shard-node with everything else having been pushed away from them.</p>
<p>They only need to &#8216;lock&#8217; is for a single user when migrating their data off the shard.  This is a write-lock, not a read lock &#8211; it only keeps the user from updating their own catalog of products while the move is taking place.  Most users never notice when this happens.  The system as a whole doesn&#8217;t go down (their words).  The MySQL catalogs are replicated (3 machines, master-master, writing to 1) and can be upgraded by taking 1 of the 3 out of the cluster at a time.  The same kind of approach goes for the other sharing servers.</p>
<h3>Panel Discussion</h3>
<p>The panel discussion was most memorable for how Chris and Toby seemed to dominate the discussion.</p>
<h3>Hive and Hadoop</h3>
<p>Hive is a data storage system developed on top of Hadoop with its own query language (HiveQL), built by Facebook.  The goals are a bit different from HiveDB &#8211; HiveDB is more for <span class="caps">OLTP</span>, while Hive is more for large-scale analytics.  Being built on top of Hadoop, HiveDB is much more batch oriented.  Facebook uses it for doing analytics, data-mining, and machine-learning of their user and transactional data sets (logs, user activities, etc.) to mine out aggregate and trending intelligence from the large data set.</p>
<p>Interesting fact: Facebook&#8217;s Hive sees <strong>2Tb</strong> of growth <em>per</em> <strong><em>day</em></strong>.</p>
<h3>Building Scalable Web Applications with Google App Engine</h3>
<p>PaaS stacks like <span class="caps">GAE</span> take a more managed environment approach than the more raw or primitive services provided by <span class="caps">AWS</span> style on-demand services.  The two fit into different use cases though and, <span class="caps">IMO</span>, one will not necessarily eliminate the other.</p>
<p><span class="caps">GAE</span> takes away from you all the concerns about deployment, production architecture, system management or administration.  It gives you a data store with an OO <span class="caps">API</span>, and a web-app development environment that you develop your application within.  There are things you can&#8217;t do, for example, you can&#8217;t run arbitrary software or services on <span class="caps">GAE</span> like you can on the more machine-image based cloud services (<span class="caps">AWS</span> EC2).</p>
<p>What you gain from giving up those capabilities is Google&#8217;s infrastructure for scaling, it becomes <em>your</em> infrastructure for scaling.  Your app is designed in a pseudo-functional way &#8211; the stack encourages you to design your app to perform all dynamism at put/post time and to just render/display at get time.  This approach helps with the scaling of the system.  Storage location transparency helps with spooling up other instances of the app in disparate data centers, etc.</p>
<p>This kind of stack really makes it easy to develop the most common case of web applications &#8211; it is both easy to do and it scales.  This is a combination that you rarely see in a platform or technology.</p>
<p>I see these kinds of stacks as becoming more established and a large part of Internet based application development &#8211; I think that more organizations will offer these kind of stacks across more technologies.</p>
<p>My advice: You should sign up for an account and try <a href="http://code.google.com/appengine/"><span class="caps">GAE</span></a> out.</p>
<h3>Developing and Deploying Java applications on Amazon EC2</h3>
<p>Chris Richardson has created cloud-tools, a package of utilities (and a <a href="http://maven.apache.org/">maven</a> plug-in) for provisioning EC2 instances, pushing your application up and executing tasks across your cluster of instances.  The tools look like they make it very easy to get your Java app into EC2.</p>
<h2>Conclusion</h2>
<p>The main theme I took away from it is that on-demand computing is a continuing trend.  Services will continue to appear and be developed that will make taking advantage of these resource pools easier and more cost effective.</p>
<p>The trend for physical data centers will continue to become more and more outsourced to organizations that can provide those services with greater economy of scale.  Currently Amazon&#8217;s offerings are slightly more expensive than a hosted system that you own &#8211; in the case where you need up-time or have high constant utilization.  More guidelines are being developed showing when the trade off is appropriate.  As a trend, cloud computing is still new and not well defined &#8211; it is likely that these trade offs will shift &#8211; even as soon as over the next few years (eg: it is likely, in my opinion, that the raw cost of 24&#215;7 allocation for SMBs will fall below the cost of ownership due to these on-demand provider&#8217;s economies of scale).</p>
<p>We&#8217;re past the point of asking if your organization can make use of these on-demand providers and to the point where you should be identifying the areas where you can realize savings by taking advantage of these services.</p>
<p class="meta">Kyle Burton, 21 Oct 2008 &#8211; Malvern PA</p>]]></content:encoded>
    </item>
    
    <item>
      <title>Common Lisp - destructuring-bind</title>
      <link>http://blog.asymmetrical-view.com/2008/09/18/destructuring-bind.html</link>
      <comments>http://blog.asymmetrical-view.com/2008/09/18/destructuring-bind.html#comments</comments>

      <pubDate>2008-09-18T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2008/09/18/destructuring-bind.html</guid>

      <id>http://blog.asymmetrical-view.com/2008/09/18/destructuring-bind</id>
      <description><![CDATA[<h1>Common Lisp &#8211; destructuring-bind</h1>
<p>Destructuring bind examples in Common Lisp:</p>
<pre class="code">
;; This is a typical usage, for pulling apart a list
(destructuring-bind
      (first second)
    '(1 2)
  (format t "~%~%;;; =&gt; first:~a second:~a~&amp;" first second))
;;; &gt; first:1 second:2

;; You can also pull apart improper lists:
(destructuring-bind
      (first . second)
    '(1 . 2)
  (format t "~%~%;;; =&gt; first:~a second:~a~&amp;" first second))

;;; &gt; first:1 second:2

;; The first argument to destructuring-bind is a lambda list, but you
;; can grab the remainder by either using a dotted list:

(destructuring-bind
      (first second . stuff)
    '(1 2 3 4 5)
  (format t "~%~%;;; =&gt; first:~a second:~a rest:~a~&amp;" first second stuff))

;;; =&gt; first:1 second:2 rest:(3 4 5)

;; or you can grab the remainder with &amp;rest, just like you do for
;; functions that take a variable number of arguments:
(destructuring-bind
      (first second &amp;rest stuff)
    '(1 2 3 4 5)
  (format t "~%~%;;; =&gt; first:~a second:~a rest:~a~&amp;" first second stuff))

;;; =&gt; first:1 second:2 rest:(3 4 5)

;; It really is a lambda list, you can use default parameters:
(destructuring-bind
      (first second &amp;optional (third 'default))
    '(1 2)
  (format t "~%~%;;; =&gt; first:~a second:~a third:~a~&amp;" first second third))

;;; =&gt; first:1 second:2 third:DEFAULT

(destructuring-bind
      (first second &amp;optional (third 'default))
    '(1 2 3)
  (format t "~%~%;;; =&gt; first:~a second:~a third:~a~&amp;" first second third))

;;; =&gt; first:1 second:2 third:3

;; And you can use keyword parameters:
(destructuring-bind
      (first second &amp;key third)
    '(1 2 :third 3)
  (format t "~%~%;;; =&gt; first:~a second:~a third:~a~&amp;" first second third))

;;; =&gt; first:1 second:2 third:3

;; Finally, you can use it to 'unparse' trees as well, which is a
;; really great feature, since your variable declaration matches the
;; 'shape' of the data strucutre you're pulling apart.  This technique
;; is really handy for dealing with XML after it's been converted to
;; s-expressions.
(destructuring-bind
      (a (b (c d e (f g) h i j)) &amp;rest remainder)
    '(1 (2 (3 4 5 (6 7) 8 9 10)) 11 12 13 14 15)
  (format t
          "~%~%;;; =&gt; a:~a b:~a c:~a d:~a e:~a f:~a g:~a h:~a i:~a j:~a remainder:~a ~&amp;"
          a b c d e f g h i j remainder))

;;; =&gt; a:1 b:2 c:3 d:4 e:5 f:6 g:7 h:8 i:9 j:10 remainder:(11 12 13 14 15)

</pre>]]></description>
      <content:encoded><![CDATA[<h1>Common Lisp &#8211; destructuring-bind</h1>
<p>Destructuring bind examples in Common Lisp:</p>
<pre class="code">
;; This is a typical usage, for pulling apart a list
(destructuring-bind
      (first second)
    '(1 2)
  (format t "~%~%;;; =&gt; first:~a second:~a~&amp;" first second))
;;; &gt; first:1 second:2

;; You can also pull apart improper lists:
(destructuring-bind
      (first . second)
    '(1 . 2)
  (format t "~%~%;;; =&gt; first:~a second:~a~&amp;" first second))

;;; &gt; first:1 second:2

;; The first argument to destructuring-bind is a lambda list, but you
;; can grab the remainder by either using a dotted list:

(destructuring-bind
      (first second . stuff)
    '(1 2 3 4 5)
  (format t "~%~%;;; =&gt; first:~a second:~a rest:~a~&amp;" first second stuff))

;;; =&gt; first:1 second:2 rest:(3 4 5)

;; or you can grab the remainder with &amp;rest, just like you do for
;; functions that take a variable number of arguments:
(destructuring-bind
      (first second &amp;rest stuff)
    '(1 2 3 4 5)
  (format t "~%~%;;; =&gt; first:~a second:~a rest:~a~&amp;" first second stuff))

;;; =&gt; first:1 second:2 rest:(3 4 5)

;; It really is a lambda list, you can use default parameters:
(destructuring-bind
      (first second &amp;optional (third 'default))
    '(1 2)
  (format t "~%~%;;; =&gt; first:~a second:~a third:~a~&amp;" first second third))

;;; =&gt; first:1 second:2 third:DEFAULT

(destructuring-bind
      (first second &amp;optional (third 'default))
    '(1 2 3)
  (format t "~%~%;;; =&gt; first:~a second:~a third:~a~&amp;" first second third))

;;; =&gt; first:1 second:2 third:3

;; And you can use keyword parameters:
(destructuring-bind
      (first second &amp;key third)
    '(1 2 :third 3)
  (format t "~%~%;;; =&gt; first:~a second:~a third:~a~&amp;" first second third))

;;; =&gt; first:1 second:2 third:3

;; Finally, you can use it to 'unparse' trees as well, which is a
;; really great feature, since your variable declaration matches the
;; 'shape' of the data strucutre you're pulling apart.  This technique
;; is really handy for dealing with XML after it's been converted to
;; s-expressions.
(destructuring-bind
      (a (b (c d e (f g) h i j)) &amp;rest remainder)
    '(1 (2 (3 4 5 (6 7) 8 9 10)) 11 12 13 14 15)
  (format t
          "~%~%;;; =&gt; a:~a b:~a c:~a d:~a e:~a f:~a g:~a h:~a i:~a j:~a remainder:~a ~&amp;"
          a b c d e f g h i j remainder))

;;; =&gt; a:1 b:2 c:3 d:4 e:5 f:6 g:7 h:8 i:9 j:10 remainder:(11 12 13 14 15)

</pre>]]></content:encoded>
    </item>
    
    <item>
      <title>Introduction to Lisp talk at PLUG North Tonight at 7pm</title>
      <link>http://blog.asymmetrical-view.com/2008/08/11/introduction-to-lisp.html</link>
      <comments>http://blog.asymmetrical-view.com/2008/08/11/introduction-to-lisp.html#comments</comments>

      <pubDate>2008-08-11T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2008/08/11/introduction-to-lisp.html</guid>

      <id>http://blog.asymmetrical-view.com/2008/08/11/introduction-to-lisp</id>
      <description><![CDATA[<h1>Introduction to Lisp talk at <span class="caps">PLUG</span> North Tonight at 7pm</h1>
<p>I&#8217;m giving my Introduction to Lisp talk tonight at the <a href="http://www.phillylinux.org/north.html">north</a> chapter of the <a href="http://www.phillylinux.org/">Philadelphia Linux Users Group</a>.</p>
<div style="width:425px;text-align:left" id="__ss_1453033"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/kyleburton/introduction-to-lisp?type=presentation" title="Introduction To Lisp">Introduction To Lisp</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=introduction-to-lisp-090518105029-phpapp01&stripped_title=introduction-to-lisp" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=introduction-to-lisp-090518105029-phpapp01&stripped_title=introduction-to-lisp" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/kyleburton">kyleburton</a>.</div></div>
<p class="meta">Kyle Burton, 11 Aug 2008 &#8211; Wayne PA</p>]]></description>
      <content:encoded><![CDATA[<h1>Introduction to Lisp talk at <span class="caps">PLUG</span> North Tonight at 7pm</h1>
<p>I&#8217;m giving my Introduction to Lisp talk tonight at the <a href="http://www.phillylinux.org/north.html">north</a> chapter of the <a href="http://www.phillylinux.org/">Philadelphia Linux Users Group</a>.</p>
<div style="width:425px;text-align:left" id="__ss_1453033"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/kyleburton/introduction-to-lisp?type=presentation" title="Introduction To Lisp">Introduction To Lisp</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=introduction-to-lisp-090518105029-phpapp01&stripped_title=introduction-to-lisp" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=introduction-to-lisp-090518105029-phpapp01&stripped_title=introduction-to-lisp" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/kyleburton">kyleburton</a>.</div></div>
<p class="meta">Kyle Burton, 11 Aug 2008 &#8211; Wayne PA</p>]]></content:encoded>
    </item>
    
    <item>
      <title>A Survey of Fuzzy String Matching Algorithms at PLUG Central Tonight at 7pm</title>
      <link>http://blog.asymmetrical-view.com/2008/08/06/fuzzy-string.html</link>
      <comments>http://blog.asymmetrical-view.com/2008/08/06/fuzzy-string.html#comments</comments>

      <pubDate>2008-08-06T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2008/08/06/fuzzy-string.html</guid>

      <id>http://blog.asymmetrical-view.com/2008/08/06/fuzzy-string</id>
      <description><![CDATA[<h1>A Survey of Fuzzy String Matching Algorithms at <span class="caps">PLUG</span> Central Tonight at 7pm</h1>
<p>I&#8217;m giving my Survey of Fuzzy String Matching Algorithms talk tonight at the central chapter of the <a href="http://www.phillylinux.org/">Philadelphia Linux Users Group</a>.</p>
<div style="width:425px;text-align:left" id="__ss_822817"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/kyleburton/fuzzy-string-matching?type=presentation" title="Fuzzy String Matching">Fuzzy String Matching</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=fuzzy-string-matching-7107&stripped_title=fuzzy-string-matching" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=fuzzy-string-matching-7107&stripped_title=fuzzy-string-matching" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/kyleburton">kyleburton</a>.</div></div>
<p class="meta">Kyle Burton, 06 Aug 2008 &#8211; Wayne PA</p>]]></description>
      <content:encoded><![CDATA[<h1>A Survey of Fuzzy String Matching Algorithms at <span class="caps">PLUG</span> Central Tonight at 7pm</h1>
<p>I&#8217;m giving my Survey of Fuzzy String Matching Algorithms talk tonight at the central chapter of the <a href="http://www.phillylinux.org/">Philadelphia Linux Users Group</a>.</p>
<div style="width:425px;text-align:left" id="__ss_822817"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/kyleburton/fuzzy-string-matching?type=presentation" title="Fuzzy String Matching">Fuzzy String Matching</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=fuzzy-string-matching-7107&stripped_title=fuzzy-string-matching" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=fuzzy-string-matching-7107&stripped_title=fuzzy-string-matching" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/kyleburton">kyleburton</a>.</div></div>
<p class="meta">Kyle Burton, 06 Aug 2008 &#8211; Wayne PA</p>]]></content:encoded>
    </item>
    
    <item>
      <title>OSCon Day 1</title>
      <link>http://blog.asymmetrical-view.com/2008/07/21/oscon-day-1.html</link>
      <comments>http://blog.asymmetrical-view.com/2008/07/21/oscon-day-1.html#comments</comments>

      <pubDate>2008-07-21T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2008/07/21/oscon-day-1.html</guid>

      <id>http://blog.asymmetrical-view.com/2008/07/21/oscon-day-1</id>
      <description><![CDATA[<h1>OSCon Day 1</h1>
<h3>Morning</h3>
<p>Andrew and I arrived for <a href="http://en.oreilly.com/oscon2008/">OScon 2008</a> registration and took advantage of the continental breakfast before heading up to the Intro to Python.</p>
<p>O&#8217;Reilly had the registration process pretty streamlined.  They had a long bank of laptops which you needed only enter your registration code, or your email address (if you registered on the OSCon conference web site).  Register, then walk up to the materials station and pick up your ID and badge card.</p>
<p>There were plenty of juices, coffee, fruit and pastries.  There was also plenty of seating.  To either <a href="http://conferences.oreillynet.com/">O&#8217;Reilly&#8217;s</a> or the <a href="http://www.oregoncc.org/">Oregon Conference Center&#8217;s</a> credit, things were very well organized.</p>
<h3>Python in 3 Hours</h3>
<p>The first conference room we were in must have had seating for a few hundred people and it was effectively full.  There was limited space for each attendee and their items (it was at least cramped for me) &#8211; though they anticipated a laptop per person &#8211; so there were plenty of power strips laid along every other row of tables within easy reach of every single seat.  It was well planned and laid out.</p>
<p>The <a href="http://en.oreilly.com/oscon2008/public/schedule/detail/2488">intro to Python</a> got underway at 8:30 and although it was geared toward an audience with some programming experience, it assumed (as the title suggested) no python experience.  <a href="http://en.oreilly.com/oscon2008/public/schedule/speaker/4913">Steve Holden</a> was a great speaker, filling in twice with anecdotes while technical issues were worked out with equipment (once was a mis-configuration of his laptop, the other was a power interruption).</p>
<p><a href="http://www.python.org/">Python</a> is a very capable language.  It is more consistent about its OO and syntax when compared to <a href="http://www.perl.org/">Perl</a>.  The python community is also a lot bigger on the use of common conventions.  This is mostly focused on formatting (one expression per line), in-line documentation and coding style in general.</p>
<p>Functions are first class types, you can assign a function to a variable, you can implement the equivalent of funcall and apply in python.  Functions can be passed as arguments.  Python supports positional parameters, default values for function params and calling functions, any function, with positional arguments, named arguments, a tuple of arguments (similar to funcall), or a dictionary (an indirect way of using named arguments).</p>
<p>Python actually has a lot of features which were inspired by functional programming (including one of my favorites: <a href="http://en.wikipedia.org/wiki/List_comprehension">list comprehensions</a>).</p>
<p>Python is byte-compiled, like Java.  You write code in a .py file, and the first time it is loaded as a module (import), python compiles the code for you.  The time stamp check of the .pyc vs the .py file is transparently handled by python &#8211; no explicit make or compile step.</p>
<p>Strings are immutable, which is something that helps <a href="http://www.jython.org/">Jython</a> be a natural fit in the <span class="caps">JVM</span>.</p>
<p>Python supports list destructuring, based on tuples.  It&#8217;s easier to show an example than to try to explain:</p>
<pre class="code">
  a, (b, c) = (1, (2, 3))

  print a,b,c =&gt; 1, 2, 3
</pre>
<p>Tuples, and this kind of binding syntax, are widely used in processing things like lists, and maps.</p>
<p>An interesting feature of the language is the pair of functions, local() and gobal().  local() returns a dictionary (Python&#8217;s name for a Map), of all of the variable bindings (and values) that are visible in the current scope (exclusive of global variables).  globals() returns the variables in the entire module&#8217;s scope (not local, lexical or class scope, and not global in the sense of a Perl global &#8211; not universally global).</p>
<h5>Other Highlights</h5>
<p>The <code>yield()</code> form, is like a weak kind of continuation.</p>
<p><code>for</code>, and <code>while</code> loops can have an else clause which is executed when the form does not execute.</p>
<p>The Python try/catch form (try/except/finally) can have an else form, again, which is executed if no exception was thrown in the try block.</p>
<h3>Introduction to Django</h3>
<p>After a break for lunch, both Andrew and I attended the Introduction to <a href="http://www.djangoproject.com/">Django</a>, presented by <a href="http://djangopeople.net/jacobian/">Jacob Kaplan-Moss</a>.</p>
<p>Django is an <span class="caps">MVC</span> framework for Python for rapid development of interactive web sites.  It is an <span class="caps">MVC</span> framework very much in the spirit of <a href="http://rubyonrails.org/">Ruby on Rails</a> &#8211; I&#8217;ve done some work in Rails and the parallels are very close between the two frameworks.</p>
<p>Django has a code generation framework, an <span class="caps">ORM</span> layer (which is very similar to Rails&#8217; ActiveRecord), an html template system (with a default syntax based on PHPs smarty template system), and integrated support for testing.</p>
<p>Django has an interesting testing feature called doctests.  If you&#8217;ve worked with an interactive language with a <span class="caps">REPL</span>, you have probably used it to explore the behavior of code and to informally test the code.  Doctests are a way of (almost literally) taking a cut and paste of the interactive session and vivifying the transcript as a regression test.  I like the idea of a recorded test, but as Andrew and I talked about it he convinced me that the literal representation wasn&#8217;t the best choice for implementing those kinds of tests. I do like the reduction of effort that comes with that kind of testing and recognize the inherent informality of it.</p>
<p>All that said, Django (like Rails) is big on doing test driven development.</p>
<p>I looked up the status of Django on Jython and apparently it&#8217;s close to being a 1.0 release (nothing I&#8217;d recommend for use at my employer at the moment, but <a href="http://www.sun.com/">Sun</a> has hired people to work on Jython and Django is one of the frameworks they are concerned with supporting).</p>
<p>I&#8217;m looking forward to tomorrow.</p>]]></description>
      <content:encoded><![CDATA[<h1>OSCon Day 1</h1>
<h3>Morning</h3>
<p>Andrew and I arrived for <a href="http://en.oreilly.com/oscon2008/">OScon 2008</a> registration and took advantage of the continental breakfast before heading up to the Intro to Python.</p>
<p>O&#8217;Reilly had the registration process pretty streamlined.  They had a long bank of laptops which you needed only enter your registration code, or your email address (if you registered on the OSCon conference web site).  Register, then walk up to the materials station and pick up your ID and badge card.</p>
<p>There were plenty of juices, coffee, fruit and pastries.  There was also plenty of seating.  To either <a href="http://conferences.oreillynet.com/">O&#8217;Reilly&#8217;s</a> or the <a href="http://www.oregoncc.org/">Oregon Conference Center&#8217;s</a> credit, things were very well organized.</p>
<h3>Python in 3 Hours</h3>
<p>The first conference room we were in must have had seating for a few hundred people and it was effectively full.  There was limited space for each attendee and their items (it was at least cramped for me) &#8211; though they anticipated a laptop per person &#8211; so there were plenty of power strips laid along every other row of tables within easy reach of every single seat.  It was well planned and laid out.</p>
<p>The <a href="http://en.oreilly.com/oscon2008/public/schedule/detail/2488">intro to Python</a> got underway at 8:30 and although it was geared toward an audience with some programming experience, it assumed (as the title suggested) no python experience.  <a href="http://en.oreilly.com/oscon2008/public/schedule/speaker/4913">Steve Holden</a> was a great speaker, filling in twice with anecdotes while technical issues were worked out with equipment (once was a mis-configuration of his laptop, the other was a power interruption).</p>
<p><a href="http://www.python.org/">Python</a> is a very capable language.  It is more consistent about its OO and syntax when compared to <a href="http://www.perl.org/">Perl</a>.  The python community is also a lot bigger on the use of common conventions.  This is mostly focused on formatting (one expression per line), in-line documentation and coding style in general.</p>
<p>Functions are first class types, you can assign a function to a variable, you can implement the equivalent of funcall and apply in python.  Functions can be passed as arguments.  Python supports positional parameters, default values for function params and calling functions, any function, with positional arguments, named arguments, a tuple of arguments (similar to funcall), or a dictionary (an indirect way of using named arguments).</p>
<p>Python actually has a lot of features which were inspired by functional programming (including one of my favorites: <a href="http://en.wikipedia.org/wiki/List_comprehension">list comprehensions</a>).</p>
<p>Python is byte-compiled, like Java.  You write code in a .py file, and the first time it is loaded as a module (import), python compiles the code for you.  The time stamp check of the .pyc vs the .py file is transparently handled by python &#8211; no explicit make or compile step.</p>
<p>Strings are immutable, which is something that helps <a href="http://www.jython.org/">Jython</a> be a natural fit in the <span class="caps">JVM</span>.</p>
<p>Python supports list destructuring, based on tuples.  It&#8217;s easier to show an example than to try to explain:</p>
<pre class="code">
  a, (b, c) = (1, (2, 3))

  print a,b,c =&gt; 1, 2, 3
</pre>
<p>Tuples, and this kind of binding syntax, are widely used in processing things like lists, and maps.</p>
<p>An interesting feature of the language is the pair of functions, local() and gobal().  local() returns a dictionary (Python&#8217;s name for a Map), of all of the variable bindings (and values) that are visible in the current scope (exclusive of global variables).  globals() returns the variables in the entire module&#8217;s scope (not local, lexical or class scope, and not global in the sense of a Perl global &#8211; not universally global).</p>
<h5>Other Highlights</h5>
<p>The <code>yield()</code> form, is like a weak kind of continuation.</p>
<p><code>for</code>, and <code>while</code> loops can have an else clause which is executed when the form does not execute.</p>
<p>The Python try/catch form (try/except/finally) can have an else form, again, which is executed if no exception was thrown in the try block.</p>
<h3>Introduction to Django</h3>
<p>After a break for lunch, both Andrew and I attended the Introduction to <a href="http://www.djangoproject.com/">Django</a>, presented by <a href="http://djangopeople.net/jacobian/">Jacob Kaplan-Moss</a>.</p>
<p>Django is an <span class="caps">MVC</span> framework for Python for rapid development of interactive web sites.  It is an <span class="caps">MVC</span> framework very much in the spirit of <a href="http://rubyonrails.org/">Ruby on Rails</a> &#8211; I&#8217;ve done some work in Rails and the parallels are very close between the two frameworks.</p>
<p>Django has a code generation framework, an <span class="caps">ORM</span> layer (which is very similar to Rails&#8217; ActiveRecord), an html template system (with a default syntax based on PHPs smarty template system), and integrated support for testing.</p>
<p>Django has an interesting testing feature called doctests.  If you&#8217;ve worked with an interactive language with a <span class="caps">REPL</span>, you have probably used it to explore the behavior of code and to informally test the code.  Doctests are a way of (almost literally) taking a cut and paste of the interactive session and vivifying the transcript as a regression test.  I like the idea of a recorded test, but as Andrew and I talked about it he convinced me that the literal representation wasn&#8217;t the best choice for implementing those kinds of tests. I do like the reduction of effort that comes with that kind of testing and recognize the inherent informality of it.</p>
<p>All that said, Django (like Rails) is big on doing test driven development.</p>
<p>I looked up the status of Django on Jython and apparently it&#8217;s close to being a 1.0 release (nothing I&#8217;d recommend for use at my employer at the moment, but <a href="http://www.sun.com/">Sun</a> has hired people to work on Jython and Django is one of the frameworks they are concerned with supporting).</p>
<p>I&#8217;m looking forward to tomorrow.</p>]]></content:encoded>
    </item>
    
    <item>
      <title>A Survey of Fuzzy String Matching Algorithms at Philly Lambda</title>
      <link>http://blog.asymmetrical-view.com/2008/06/26/fuzzy-string.html</link>
      <comments>http://blog.asymmetrical-view.com/2008/06/26/fuzzy-string.html#comments</comments>

      <pubDate>2008-06-26T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2008/06/26/fuzzy-string.html</guid>

      <id>http://blog.asymmetrical-view.com/2008/06/26/fuzzy-string</id>
      <description><![CDATA[<h1>A Survey of Fuzzy String Matching Algorithms at Philly Lambda</h1>
<p>I&#8217;m giving my Survey of Fuzzy String Matching Algorithms talk tonight at <a href="http://groups.google.com/group/philly-lambda">Philly Lambda</a> hosted by <a href="http://www.algorithmics.com/EN/">Algorithmics</a>, See you at 7.</p>
<div style="width:425px;text-align:left" id="__ss_822817"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/kyleburton/fuzzy-string-matching?type=presentation" title="Fuzzy String Matching">Fuzzy String Matching</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=fuzzy-string-matching-7107&stripped_title=fuzzy-string-matching" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=fuzzy-string-matching-7107&stripped_title=fuzzy-string-matching" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/kyleburton">kyleburton</a>.</div></div>
<p class="meta">Kyle Burton, 25 Jun 2008 &#8211; Wayne PA</p>]]></description>
      <content:encoded><![CDATA[<h1>A Survey of Fuzzy String Matching Algorithms at Philly Lambda</h1>
<p>I&#8217;m giving my Survey of Fuzzy String Matching Algorithms talk tonight at <a href="http://groups.google.com/group/philly-lambda">Philly Lambda</a> hosted by <a href="http://www.algorithmics.com/EN/">Algorithmics</a>, See you at 7.</p>
<div style="width:425px;text-align:left" id="__ss_822817"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/kyleburton/fuzzy-string-matching?type=presentation" title="Fuzzy String Matching">Fuzzy String Matching</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=fuzzy-string-matching-7107&stripped_title=fuzzy-string-matching" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=fuzzy-string-matching-7107&stripped_title=fuzzy-string-matching" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/kyleburton">kyleburton</a>.</div></div>
<p class="meta">Kyle Burton, 25 Jun 2008 &#8211; Wayne PA</p>]]></content:encoded>
    </item>
    
    <item>
      <title>Idempotency or Singleton Memoization in Perl</title>
      <link>http://blog.asymmetrical-view.com/2008/06/18/idempotency-or-singleton-memoization.html</link>
      <comments>http://blog.asymmetrical-view.com/2008/06/18/idempotency-or-singleton-memoization.html#comments</comments>

      <pubDate>2008-06-18T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2008/06/18/idempotency-or-singleton-memoization.html</guid>

      <id>http://blog.asymmetrical-view.com/2008/06/18/idempotency-or-singleton-memoization</id>
      <description><![CDATA[<h1>Idempotency or Singleton Memoization in Perl</h1>
<p>This is an example of a factory for creating a function who&#8217;s body will only fire once, returning the first computed result each time it is invoked thereafter.</p>
<pre class="code">
sub makeDoOnce {
  my($sub) = @_;
  my $alreadyDone = undef;
  my @result      = undef;
  my $exception   = undef;
  return sub {
    die $exception if $exception;
    if ($alreadyDone) {return wantarray ? @result : $result[0];}

    eval {
      my $w = wantarray;
      if (not defined $w) {             $sub-&gt;(@_)}
      if ($w)             {@result    = $sub-&gt;(@_)}
      else                {$result[0] = $sub-&gt;(@_)}
    };
    $exception = $@ if $@;
    die $exception if $exception;
    $alreadyDone = 1;
    return wantarray ? @result : $result[0];
  };
}
</pre>
<p>This works by creating a <a href="http://en.wikipedia.org/wiki/Closure_(computer_science%29">closure</a> over the <code>$alreadyDone</code>, <code>@result</code> and <code>$exception</code> variables.  Within the returned sub, any exception is re-thrown, if the result was previously computed, it is returned.  If no exception or previous result was calculated, then the original function is invoked, storing off the exception or result and returning or throwing as appropriate.</p>
<p>An example usage is:</p>
<pre class="code">
  my $getStartTime = makeDoOnce(sub { time });
  print "We started at: ", scalar(localtime $getStartTime-&gt;()), "\n";
  sleep 5;
  print "We started at: ", scalar(localtime $getStartTime-&gt;()), "\n";
</pre>
<p>I often use this pattern for one-time initializations (loading plugin systems, ensuring file structures exist, etc), where I want the time of call to be flexible but the action it performs to happen only one time.</p>
<p class="meta">Kyle Burton, 18 Jun 2008 &#8211; Wayne PA</p>]]></description>
      <content:encoded><![CDATA[<h1>Idempotency or Singleton Memoization in Perl</h1>
<p>This is an example of a factory for creating a function who&#8217;s body will only fire once, returning the first computed result each time it is invoked thereafter.</p>
<pre class="code">
sub makeDoOnce {
  my($sub) = @_;
  my $alreadyDone = undef;
  my @result      = undef;
  my $exception   = undef;
  return sub {
    die $exception if $exception;
    if ($alreadyDone) {return wantarray ? @result : $result[0];}

    eval {
      my $w = wantarray;
      if (not defined $w) {             $sub-&gt;(@_)}
      if ($w)             {@result    = $sub-&gt;(@_)}
      else                {$result[0] = $sub-&gt;(@_)}
    };
    $exception = $@ if $@;
    die $exception if $exception;
    $alreadyDone = 1;
    return wantarray ? @result : $result[0];
  };
}
</pre>
<p>This works by creating a <a href="http://en.wikipedia.org/wiki/Closure_(computer_science%29">closure</a> over the <code>$alreadyDone</code>, <code>@result</code> and <code>$exception</code> variables.  Within the returned sub, any exception is re-thrown, if the result was previously computed, it is returned.  If no exception or previous result was calculated, then the original function is invoked, storing off the exception or result and returning or throwing as appropriate.</p>
<p>An example usage is:</p>
<pre class="code">
  my $getStartTime = makeDoOnce(sub { time });
  print "We started at: ", scalar(localtime $getStartTime-&gt;()), "\n";
  sleep 5;
  print "We started at: ", scalar(localtime $getStartTime-&gt;()), "\n";
</pre>
<p>I often use this pattern for one-time initializations (loading plugin systems, ensuring file structures exist, etc), where I want the time of call to be flexible but the action it performs to happen only one time.</p>
<p class="meta">Kyle Burton, 18 Jun 2008 &#8211; Wayne PA</p>]]></content:encoded>
    </item>
    
    <item>
      <title>Basic Data Analysis at the Unix shell</title>
      <link>http://blog.asymmetrical-view.com/2008/04/28/data-analysis-in-the-unix-shell.html</link>
      <comments>http://blog.asymmetrical-view.com/2008/04/28/data-analysis-in-the-unix-shell.html#comments</comments>

      <pubDate>2008-04-28T00:00:00-04:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2008/04/28/data-analysis-in-the-unix-shell.html</guid>

      <id>http://blog.asymmetrical-view.com/2008/04/28/data-analysis-in-the-unix-shell</id>
      <description><![CDATA[<h1>Basic Data Analysis at the Unix shell</h1>
<p>I often prefer the shell and Unix utilities to having to wait to load data into a relational database or MS Access.  There are plenty of cases when an <span class="caps">RDBMS</span> is a better choice &#8211; especially when what you&#8217;re doing requires joins.  At the shell it&#8217;s often possible to not even have to transform the encoding of the files before analyzing them.  I have developed a couple of recipes for doing some <span class="caps">SQL</span> equivalents at the shell.  These are a few that I just used so they&#8217;re fresh in my mind.  Most of the time all it takes is a bit of imagination about how to create a simple data-flow by learning and composing a small handful of the ubiquitous Unix utilities.</p>
<p>All these examples will also work within the <a href="http://www.cygwin.com/">Cygwin</a> environment for Windows, or at a Terminal in OS X (especially when combined with the additional software available via <a href="http://www.finkproject.org/">Fink</a> or <a href="http://www.macports.org/">Mac Ports</a> projects.</p>
<h3>Counting Records</h3>
<pre class="code">"SELECT COUNT(*) FROM TABLE"</pre>
<p>Just selecting the count of records from an input file is one of the easiest things to accomplish (if your file is already line-oriented). The <tt>wc</tt>, or word count, utility can do this easily.  By default it counts characters, words and lines.  With &#8216;-l&#8217; it will emit only the count of lines.</p>
<pre class="code">
  user@host:~/data$ wc -l table.tab
  10
</pre>
<p>If you want to ignore the header, start with the second line (see the next example for a more thorough explanation):</p>
<pre class="code">
  user@host:~/data$ tail -n +2 | table.tab
  9
</pre>
<h3>Counting Distinct Values from a Column</h3>
<pre class="code">"SELECT COUNT(DISTINCT(FIELD1)) FROM TABLE"</pre>
<p>For getting a distinct count of values in a column:</p>
<pre class="code">
  user@host:~/data$ cut -f1 table.tab | tail -n +2 | sort | uniq -c
</pre>
<p>This operations starts with the <tt>cut</tt> utility.  <tt>cut</tt>  allows you to take particular columns from a tab-delimited file, or character ranges from a fixed-width file.  <tt>cut</tt> also allows you to specify the delimiter &#8211; but be warned that the commonly encountered <span class="caps">CSV</span> format is more complex than <tt>cut</tt> can handle (<span class="caps">CSV</span> can support embedded delimiters and quote characters, which are beyond the scope of what <tt>cut</tt> attempts to handle).  The usage of <tt>cut</tt> takes the first column out of the input file.</p>
<p>The next part is the <tt>tail</tt> command.  <tt>tail</tt> outputs the end or &#8216;tail&#8217; of a file.  The &#8216;-n&#8217; option instructs <tt>tail</tt> to emit a specific number of lines (counted from the end of the file) when no &#8216;+&#8217; sign is present on the number.  The &#8216;+&#8217; tells <tt>tail</tt> to start at the second line from the beginning (in stead of from the end).  This effectively discards the header line.</p>
<p>Then the values from the first column themselves are sorted.  This is necessary for the <tt>uniq</tt> command, which will only collapse or count duplicate lines when they are adjacent.</p>
<p>Finally we reduce duplicate lines with <tt>uniq</tt>.  The &#8216;-c&#8217; tells <tt>uniq</tt> to emit the count of duplicates when collapsing them.</p>
<h3>Dealing with various file archive types</h3>
<p>I often work with files in zip archives and tar (unix tape archive) archives, sometimes with additional compression applied to them (.Z, unix compress; .gz, gzip; and .bz2, bzip).  It is possible to work with these files without having to unarchive or decompress them permanently if all you need is a simple count of lines or to only process them once.</p>
<h4>Pulling a file from a Zip Archive</h4>
<p>To pull one or more files from within a zip archive, and send them to another command (as part of a pipeline):</p>
<pre class="code">
  user@host:~/data$ unzip -l archive.zip
  Archive: archive.zip
    Length    Date   Time   Name
   --------   ----   ----   ----
        34  04-28-08 11:01  table1.tab
        56  04-28-08 11:01  table1.tab
  user@host:~/data$ unzip -c archive.zip table1.tab table2.tab | wc -l
  36
</pre>
<p>That example uses the <tt>unzip</tt> command to pull 2 files out and send them to standard output (the <tt>-c</tt> option to unzip instructs it to print the files to standard out rather than extract them to the file system).  Those two files were then sent to <tt>wc</tt> to get the combined line (record) count for the two files.  We don&#8217;t have to worry about cleaning up the two files after the command has completed since they were never written to disk.</p>
<p class="meta">Kyle Burton, 28 Apr 2008 &#8211; Wayne PA</p>]]></description>
      <content:encoded><![CDATA[<h1>Basic Data Analysis at the Unix shell</h1>
<p>I often prefer the shell and Unix utilities to having to wait to load data into a relational database or MS Access.  There are plenty of cases when an <span class="caps">RDBMS</span> is a better choice &#8211; especially when what you&#8217;re doing requires joins.  At the shell it&#8217;s often possible to not even have to transform the encoding of the files before analyzing them.  I have developed a couple of recipes for doing some <span class="caps">SQL</span> equivalents at the shell.  These are a few that I just used so they&#8217;re fresh in my mind.  Most of the time all it takes is a bit of imagination about how to create a simple data-flow by learning and composing a small handful of the ubiquitous Unix utilities.</p>
<p>All these examples will also work within the <a href="http://www.cygwin.com/">Cygwin</a> environment for Windows, or at a Terminal in OS X (especially when combined with the additional software available via <a href="http://www.finkproject.org/">Fink</a> or <a href="http://www.macports.org/">Mac Ports</a> projects.</p>
<h3>Counting Records</h3>
<pre class="code">"SELECT COUNT(*) FROM TABLE"</pre>
<p>Just selecting the count of records from an input file is one of the easiest things to accomplish (if your file is already line-oriented). The <tt>wc</tt>, or word count, utility can do this easily.  By default it counts characters, words and lines.  With &#8216;-l&#8217; it will emit only the count of lines.</p>
<pre class="code">
  user@host:~/data$ wc -l table.tab
  10
</pre>
<p>If you want to ignore the header, start with the second line (see the next example for a more thorough explanation):</p>
<pre class="code">
  user@host:~/data$ tail -n +2 | table.tab
  9
</pre>
<h3>Counting Distinct Values from a Column</h3>
<pre class="code">"SELECT COUNT(DISTINCT(FIELD1)) FROM TABLE"</pre>
<p>For getting a distinct count of values in a column:</p>
<pre class="code">
  user@host:~/data$ cut -f1 table.tab | tail -n +2 | sort | uniq -c
</pre>
<p>This operations starts with the <tt>cut</tt> utility.  <tt>cut</tt>  allows you to take particular columns from a tab-delimited file, or character ranges from a fixed-width file.  <tt>cut</tt> also allows you to specify the delimiter &#8211; but be warned that the commonly encountered <span class="caps">CSV</span> format is more complex than <tt>cut</tt> can handle (<span class="caps">CSV</span> can support embedded delimiters and quote characters, which are beyond the scope of what <tt>cut</tt> attempts to handle).  The usage of <tt>cut</tt> takes the first column out of the input file.</p>
<p>The next part is the <tt>tail</tt> command.  <tt>tail</tt> outputs the end or &#8216;tail&#8217; of a file.  The &#8216;-n&#8217; option instructs <tt>tail</tt> to emit a specific number of lines (counted from the end of the file) when no &#8216;+&#8217; sign is present on the number.  The &#8216;+&#8217; tells <tt>tail</tt> to start at the second line from the beginning (in stead of from the end).  This effectively discards the header line.</p>
<p>Then the values from the first column themselves are sorted.  This is necessary for the <tt>uniq</tt> command, which will only collapse or count duplicate lines when they are adjacent.</p>
<p>Finally we reduce duplicate lines with <tt>uniq</tt>.  The &#8216;-c&#8217; tells <tt>uniq</tt> to emit the count of duplicates when collapsing them.</p>
<h3>Dealing with various file archive types</h3>
<p>I often work with files in zip archives and tar (unix tape archive) archives, sometimes with additional compression applied to them (.Z, unix compress; .gz, gzip; and .bz2, bzip).  It is possible to work with these files without having to unarchive or decompress them permanently if all you need is a simple count of lines or to only process them once.</p>
<h4>Pulling a file from a Zip Archive</h4>
<p>To pull one or more files from within a zip archive, and send them to another command (as part of a pipeline):</p>
<pre class="code">
  user@host:~/data$ unzip -l archive.zip
  Archive: archive.zip
    Length    Date   Time   Name
   --------   ----   ----   ----
        34  04-28-08 11:01  table1.tab
        56  04-28-08 11:01  table1.tab
  user@host:~/data$ unzip -c archive.zip table1.tab table2.tab | wc -l
  36
</pre>
<p>That example uses the <tt>unzip</tt> command to pull 2 files out and send them to standard output (the <tt>-c</tt> option to unzip instructs it to print the files to standard out rather than extract them to the file system).  Those two files were then sent to <tt>wc</tt> to get the combined line (record) count for the two files.  We don&#8217;t have to worry about cleaning up the two files after the command has completed since they were never written to disk.</p>
<p class="meta">Kyle Burton, 28 Apr 2008 &#8211; Wayne PA</p>]]></content:encoded>
    </item>
    
    <item>
      <title>SRFI-26's cut macro</title>
      <link>http://blog.asymmetrical-view.com/2008/01/30/srfi-26-s-cut-macro.html</link>
      <comments>http://blog.asymmetrical-view.com/2008/01/30/srfi-26-s-cut-macro.html#comments</comments>

      <pubDate>2008-01-30T00:00:00-05:00</pubDate>
      <dc:creator>Kyle Burton</dc:creator>
      <!-- <category><![CDATA[Philly Lambda]]></category> -->
      <guid isPermaLink="false">http://blog.asymmetrical-view.com/2008/01/30/srfi-26-s-cut-macro.html</guid>

      <id>http://blog.asymmetrical-view.com/2008/01/30/srfi-26-s-cut-macro</id>
      <description><![CDATA[<h1><span class="caps">SRFI</span>-26&#8217;s cut macro</h1>
<p>I&#8217;m working on an <a href="http://asymmetrical-view.com/lisp-presentation/">introduction to lisp presentation</a> for <a href="http://www.phillylinux.org/west.html">Plug West</a>.  I&#8217;m trying to think through examples of macros which are a good demonstration of what they&#8217;re for.  Towards that end I picked Scheme&#8217;s srfi-26&#8217;s cut macro, which allows for specialization of argument, and try to extend it in a couple of ways.  Below is the example code, including a simplified cut, a recursive (or tree) cut, and a pattern cut (which allows the cut points to be named).</p>
<pre class="code">
  ;; the scheme cut macro...srfi-26, when written as:
  ;;
  ;;  (cut #'format "~a~&amp;" &lt;&gt;)
  ;;
  ;; it produces:
  ;;
  ;; =&gt; #'(lambda (x) (format "~a~&amp;" x))
  ;;
  ;; 'Lifting' the '&lt;&gt;' out of the form as an argument to the generated lambda.
  ;; It's 'flat' though, it'd be nice to have something which could work
  ;; on any form...a recursive cut, which is what we'll write, first a helper:
  
  (defmacro aprog1 (it &amp;rest body)
    "Anaphoric prog1, returns the value of the first expression,
  executing all subsequent expressions for their side effects.  It binds
  the symbol 'it' to the result of the first expression.  This can also
  be seen as a 'construct and initialize' pattern.
  
    (aprog1
      (make-hash-table :test #'equal)
      (setf (gethash \"a\" it) 1)
      (setf (gethash \"b\" it) 2)
      (setf (gethash \"c\" it) 3))
    =&gt; #&lt;HASH-TABLE :TEST EQUAL :COUNT 3 {BE49831}&gt;
  
  "
    `(let ((it ,it))
       ,@body
       it))
  
  (defmacro cut (fn &amp;rest body)
    "srfi-26's cut in Common Lisp, some examples:

  (cut #'cons (+ a 1) &lt;&gt;) is the same as (lambda (x2) (cons (+ a 1) x2))
  (cut #'list 1 &lt;&gt; 3 &lt;&gt; 5) is the same as (lambda (x2 x4) (list 1 x2 3 x4 5))
  (cut #'list) is the same as (lambda () (list))
  (cut #'list 1 &lt;&gt; 3 &lt;...&gt;) is the same as (lambda (x2 . xs) (apply list 1 x2 3 xs))
  
  The following form is not supported in this version:

    (cut &lt;&gt; a b) is the same as (lambda (f) (f a b))

  Scheme does that simply by virte that it is a Lisp-1, I didn't go through the
  effort of doing the check. "
    (let* ((formals (list))
           (new-body
            (mapcar #'(lambda (item)
                        (if (equal '&lt;&gt; item)
                            (aprog1
                             (gensym)
                             (push it formals)
                             it)
                            item))
                    body)))
      `#'(lambda ,(reverse formals)
           (funcall ,fn ,@new-body))))

  ;; lets take a look at an expansion and try a couple of examples  
  ;; (macroexpand-1 '(cut #'format t "~a: ~a~&amp;" "thing" &lt;&gt;))
  ;; (funcall (cut #'format t "~a: ~a~&amp;" "thing" &lt;&gt;) 10)
  ;; (funcall (cut #'format t "~a: ~a~&amp;" &lt;&gt; &lt;&gt;) "thing" 10)

  ;; Our next helper, the visitor pattern, invoke the function 
  ;; on each non-branch (leaf node) element in the tree, replacing
  ;; the existing value with fn's result.  NB: this is a depth first 
  ;; search.
  (defun map-tree (fn tree)
    (cond ((null tree)
           tree)
          ((not (listp tree))
           (funcall fn tree))
          (t
           (mapcar #'(lambda (elt) (map-tree fn elt)) tree))))
  
  ;; test it out, this should increment each number in the tree:
  ;; (map-tree #'(lambda (elt) (format t "x:~a~&amp;" elt) (1+ elt)) '(1 2 (3 4 (5 6 (7)))))
  
  ;; With those tools we can enhance cut to use map-tree instead of map, providing
  ;; the recursive search for cut points.
  (defmacro rcut (&amp;rest body)
    (let* ((formals (list))
           (new-body
            (map-tree #'(lambda (elt)
                          (if (equalp '&lt;&gt; elt)
                              (aprog1
                               (gensym)
                               (push it formals)
                               it)
                              elt))
                      body)))
      `#'(lambda ,(reverse formals)
           ,@new-body)))
  
  ;; see what it expands to
  (macroexpand-1
   '(rcut
     (cond ((&gt; &lt;&gt; 1)
            (format t "first arg was &gt;1, second arg is: ~a~&amp;" &lt;&gt;))
           (t
            (format t "first arg was &lt;1, third arg is: ~a~&amp;" &lt;&gt;)))))
  

  ;; test out the resulting function  
  (let ((fn
         (rcut
          (cond ((&gt; &lt;&gt; 1)
                 (format t "first arg was &gt;1, second arg is: ~a~&amp;" &lt;&gt;))
                (t
                 (format t "first arg was &lt;1, third arg is: ~a~&amp;" &lt;&gt;))))))
    (funcall fn 1/2 'a 'b)
    (funcall fn 2/1 'a 'b))
  
  
  
  
  ;; that's all well and good, but the whole depth first ordering can
  ;; be hard to think through with respect to how it maps to the
  ;; ordering of the function arguments.  What we want to try next
  ;; is pcut (pattern cut), for example:
  ;; 
  ;;    (pcut
  ;;      (cond ((&gt; ?fst 1)
  ;;             (format t "first arg (~a) was &gt;1, x is: ~a~&amp;" ?fst ?x))
  ;;            (t
  ;;             (format t "first arg (~a) was &lt;1, x is: ~a, y is:~a~&amp;" ?fst ?x ?y)))
  ;;
  ;; The ordering still mattes, it's still depth-first, but now we can re-use arguments by 
  ;; name, without inventing new locals.

  ;; Helper predicate to see if we have a cut pattern symbol  
  (defun starts-with-? (sym)
    (equal "?"  (subseq (format nil "~a" sym) 0 1)))
  
  ;; the main difference here is DRY (don't repeat yourself, 
  ;; only capture each named binding once), and use the #'starts-with-? 
  ;; predicate instead of the equality test (#'equalp).
  (defmacro pcut (&amp;rest body)
    (let* ((formals (list))
           (fml-hash (make-hash-table :test #'equal))
           (new-body
            (map-tree #'(lambda (elt)
                          (if (starts-with-? elt)
                              (aprog1
                               (or (gethash elt fml-hash)
                                   (aprog1
                                    (gensym)
                                    (push it formals)
                                    (setf (gethash elt fml-hash) it)
                                    it))
                               it)
                              elt))
                      body)))
      `#'(lambda ,(reverse formals)
           ,@new-body)))

  ;; take a look at the expansion
  (macroexpand-1
   '(pcut
          (cond ((&gt; ?fst 1)
                 (format t "first arg (~a) was &gt;1, x is: ~a~&amp;" ?fst ?x))
                (t
                 (format t "first arg (~a) was &lt;1, x is: ~a, y is:~a~&amp;" ?fst ?x ?y)))))
    
  ;; test out the expansion
  (let ((fn (pcut
             (cond ((&gt; ?fst 1)
                    (format t "first arg (~a) was &gt;1, x is: ~a~&amp;" ?fst ?x))
                   (t
                    (format t "first arg (~a) was &lt;1, x is: ~a, y is:~a~&amp;" ?fst ?x ?y))))))
    (funcall fn 1/2 'a 'b)
    (funcall fn 2/1 'a 'b))
</pre>
<h3>Conclusion</h3>
<p>Hopefully these are useful pedagalogical examples of macros in Common Lisp.</p>
<p class="meta">Kyle Burton, 30 Jan 2008 &#8211; Wayne PA</p>]]></description>
      <content:encoded><![CDATA[<h1><span class="caps">SRFI</span>-26&#8217;s cut macro</h1>
<p>I&#8217;m working on an <a href="http://asymmetrical-view.com/lisp-presentation/">introduction to lisp presentation</a> for <a href="http://www.phillylinux.org/west.html">Plug West</a>.  I&#8217;m trying to think through examples of macros which are a good demonstration of what they&#8217;re for.  Towards that end I picked Scheme&#8217;s srfi-26&#8217;s cut macro, which allows for specialization of argument, and try to extend it in a couple of ways.  Below is the example code, including a simplified cut, a recursive (or tree) cut, and a pattern cut (which allows the cut points to be named).</p>
<pre class="code">
  ;; the scheme cut macro...srfi-26, when written as:
  ;;
  ;;  (cut #'format "~a~&amp;" &lt;&gt;)
  ;;
  ;; it produces:
  ;;
  ;; =&gt; #'(lambda (x) (format "~a~&amp;" x))
  ;;
  ;; 'Lifting' the '&lt;&gt;' out of the form as an argument to the generated lambda.
  ;; It's 'flat' though, it'd be nice to have something which could work
  ;; on any form...a recursive cut, which is what we'll write, first a helper:
  
  (defmacro aprog1 (it &amp;rest body)
    "Anaphoric prog1, returns the value of the first expression,
  executing all subsequent expressions for their side effects.  It binds
  the symbol 'it' to the result of the first expression.  This can also
  be seen as a 'construct and initialize' pattern.
  
    (aprog1
      (make-hash-table :test #'equal)
      (setf (gethash \"a\" it) 1)
      (setf (gethash \"b\" it) 2)
      (setf (gethash \"c\" it) 3))
    =&gt; #&lt;HASH-TABLE :TEST EQUAL :COUNT 3 {BE49831}&gt;
  
  "
    `(let ((it ,it))
       ,@body
       it))
  
  (defmacro cut (fn &amp;rest body)
    "srfi-26's cut in Common Lisp, some examples:

  (cut #'cons (+ a 1) &lt;&gt;) is the same as (lambda (x2) (cons (+ a 1) x2))
  (cut #'list 1 &lt;&gt; 3 &lt;&gt; 5) is the same as (lambda (x2 x4) (list 1 x2 3 x4 5))
  (cut #'list) is the same as (lambda () (list))
  (cut #'list 1 &lt;&gt; 3 &lt;...&gt;) is the same as (lambda (x2 . xs) (apply list 1 x2 3 xs))
  
  The following form is not supported in this version:

    (cut &lt;&gt; a b) is the same as (lambda (f) (f a b))

  Scheme does that simply by virte that it is a Lisp-1, I didn't go through the
  effort of doing the check. "
    (let* ((formals (list))
           (new-body
            (mapcar #'(lambda (item)
                        (if (equal '&lt;&gt; item)
                            (aprog1
                             (gensym)
                             (push it formals)
                             it)
                            item))
                    body)))
      `#'(lambda ,(reverse formals)
           (funcall ,fn ,@new-body))))

  ;; lets take a look at an expansion and try a couple of examples  
  ;; (macroexpand-1 '(cut #'format t "~a: ~a~&amp;" "thing" &lt;&gt;))
  ;; (funcall (cut #'format t "~a: ~a~&amp;" "thing" &lt;&gt;) 10)
  ;; (funcall (cut #'format t "~a: ~a~&amp;" &lt;&gt; &lt;&gt;) "thing" 10)

  ;; Our next helper, the visitor pattern, invoke the function 
  ;; on each non-branch (leaf node) element in the tree, replacing
  ;; the existing value with fn's result.  NB: this is a depth first 
  ;; search.
  (defun map-tree (fn tree)
    (cond ((null tree)
           tree)
          ((not (listp tree))
           (funcall fn tree))
          (t
           (mapcar #'(lambda (elt) (map-tree fn elt)) tree))))
  
  ;; test it out, this should increment each number in the tree:
  ;; (map-tree #'(lambda (elt) (format t "x:~a~&amp;" elt) (1+ elt)) '(1 2 (3 4 (5 6 (7)))))
  
  ;; With those tools we can enhance cut to use map-tree instead of map, providing
  ;; the recursive search for cut points.
  (defmacro rcut (&amp;rest body)
    (let* ((formals (list))
           (new-body
            (map-tree #'(lambda (elt)
                          (if (equalp '&lt;&gt; elt)
                              (aprog1
                               (gensym)
                               (push it formals)
                               it)
                              elt))
                      body)))
      `#'(lambda ,(reverse formals)
           ,@new-body)))
  
  ;; see what it expands to
  (macroexpand-1
   '(rcut
     (cond ((&gt; &lt;&gt; 1)
            (format t "first arg was &gt;1, second arg is: ~a~&amp;" &lt;&gt;))
           (t
            (format t "first arg was &lt;1, third arg is: ~a~&amp;" &lt;&gt;)))))
  

  ;; test out the resulting function  
  (let ((fn
         (rcut
          (cond ((&gt; &lt;&gt; 1)
                 (format t "first arg was &gt;1, second arg is: ~a~&amp;" &lt;&gt;))
                (t
                 (format t "first arg was &lt;1, third arg is: ~a~&amp;" &lt;&gt;))))))
    (funcall fn 1/2 'a 'b)
    (funcall fn 2/1 'a 'b))
  
  
  
  
  ;; that's all well and good, but the whole depth first ordering can
  ;; be hard to think through with respect to how it maps to the
  ;; ordering of the function arguments.  What we want to try next
  ;; is pcut (pattern cut), for example:
  ;; 
  ;;    (pcut
  ;;      (cond ((&gt; ?fst 1)
  ;;             (format t "first arg (~a) was &gt;1, x is: ~a~&amp;" ?fst ?x))
  ;;            (t
  ;;             (format t "first arg (~a) was &lt;1, x is: ~a, y is:~a~&amp;" ?fst ?x ?y)))
  ;;
  ;; The ordering still mattes, it's still depth-first, but now we can re-use arguments by 
  ;; name, without inventing new locals.

  ;; Helper predicate to see if we have a cut pattern symbol  
  (defun starts-with-? (sym)
    (equal "?"  (subseq (format nil "~a" sym) 0 1)))
  
  ;; the main difference here is DRY (don't repeat yourself, 
  ;; only capture each named binding once), and use the #'starts-with-? 
  ;; predicate instead of the equality test (#'equalp).
  (defmacro pcut (&amp;rest body)
    (let* ((formals (list))
           (fml-hash (make-hash-table :test #'equal))
           (new-body
            (map-tree #'(lambda (elt)
                          (if (starts-with-? elt)
                              (aprog1
                               (or (gethash elt fml-hash)
                                   (aprog1
                                    (gensym)
                                    (push it formals)
                                    (setf (gethash elt fml-hash) it)
                                    it))
                               it)
                              elt))
                      body)))
      `#'(lambda ,(reverse formals)
           ,@new-body)))

  ;; take a look at the expansion
  (macroexpand-1
   '(pcut
          (cond ((&gt; ?fst 1)
                 (format t "first arg (~a) was &gt;1, x is: ~a~&amp;" ?fst ?x))
                (t
                 (format t "first arg (~a) was &lt;1, x is: ~a, y is:~a~&amp;" ?fst ?x ?y)))))
    
  ;; test out the expansion
  (let ((fn (pcut
             (cond ((&gt; ?fst 1)
                    (format t "first arg (~a) was &gt;1, x is: ~a~&amp;" ?fst ?x))
                   (t
                    (format t "first arg (~a) was &lt;1, x is: ~a, y is:~a~&amp;" ?fst ?x ?y))))))
    (funcall fn 1/2 'a 'b)
    (funcall fn 2/1 'a 'b))
</pre>
<h3>Conclusion</h3>
<p>Hopefully these are useful pedagalogical examples of macros in Common Lisp.</p>
<p class="meta">Kyle Burton, 30 Jan 2008 &#8211; Wayne PA</p>]]></content:encoded>
    </item>
    
  </channel>

</rss>
