<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title>serialized.net</title>
  <link href="http://serialized.net/atom.xml" rel="self"/>
  <link href="http://serialized.net/"/>
  <updated>2012-02-13T16:22:54-08:00</updated>
  <id>http://serialized.net/</id>
  <author>
    <name>Joshua Barratt</name>
    
  </author>

  
  <entry>
    <title>Using R and `ggplot2` to Contemplate Relocation</title>
    <link href="http://serialized.net/2012/02/using-r-and-ggplot2-to-contemplate-relocation/"/>
    <updated>2012-02-13T14:23:00-08:00</updated>
    <id>http://serialized.net/2012/02/using-r-and-ggplot2-to-contemplate-relocation</id>
    <content type="html">&lt;p&gt;My wife and I are entertaining a still heavily &amp;#8220;what-if&amp;#8221; idea: migrating
away from Southern California into the greener (and, it turns out, greyer) lands of
the Pacific Northwest. (Portland seems particularly &amp;#8220;us&amp;#8221;.)&lt;/p&gt;

&lt;p&gt;One big problem (and there are plenty of other problems that come up when you&amp;#8217;re
thinking about a major move) is the weather. Having
both lived our lives calling Central and Southern California &amp;#8220;home&amp;#8221;,
we&amp;#8217;ve gotten spoiled by sunny, warm days being the norm.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve been using R quite a bit at &lt;a href=&quot;http://mediatemple.net&quot;&gt;work&lt;/a&gt;, so
answering the question of &amp;#8220;how bad &lt;strong&gt;is&lt;/strong&gt; the weather, really?&amp;#8221; seemed like the
perfect place to apply it.&lt;/p&gt;

&lt;h3&gt;Problem 1: Get some data.&lt;/h3&gt;

&lt;p&gt;I searched for a few minutes and found that the Weather Underground has
&lt;a href=&quot;http://www.wunderground.com/history/airport/KPDX/1991/1/1/CustomHistory.html?dayend=1&amp;amp;monthend=1&amp;amp;yearend=2012&amp;amp;req_city=NA&amp;amp;req_state=NA&amp;amp;req_statename=NA&quot;&gt;historical information&lt;/a&gt;
online, with handy links to getting it in CSV format. The only problem
was that it seemed to only work a year at a time, so I bodged a quick
&lt;code&gt;perl&lt;/code&gt; script to download what was needed. (Cleaner links to all the
code is available in my &lt;a href=&quot;https://github.com/jbarratt/r&quot;&gt;R github repo&lt;/a&gt;)&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;6&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;7&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;8&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;9&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;10&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;11&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;12&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;13&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;14&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;15&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;16&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;17&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;18&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;19&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;20&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;perl&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$day&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$month&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$year&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;localtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nv&quot;&gt;$month&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$year&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1900&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$uri_a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;http://www.wunderground.com/history/airport/$code&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$uri_b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;1/1/CustomHistory.html?dayend=$day&amp;amp;monthend=$month&amp;amp;yearend=$year&amp;amp;req_city=NA&amp;amp;req_state=NA&amp;amp;req_statename=NA&amp;amp;format=1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%seen&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1991&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$year&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$csv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;$uri_a/$i/$uri_b&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/\n/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$csv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;s/&amp;lt;br\s+\/&amp;gt;//&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/,/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;defined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;defined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$seen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;      &lt;span class=&quot;nv&quot;&gt;$seen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;      &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;$line\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;The closest airport (which seems to be how the historical data is
stored) to us is Van Nuys, so I pulled that CSV as well.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;perl&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nv&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;./&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fetch_weather&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KPDX&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KPDX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;csv&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nv&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;./&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fetch_weather&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KVNY&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KVNY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;csv&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;Problem 2: Import the data into R&lt;/h3&gt;

&lt;p&gt;Thankfully, the CSV data from the Underground is pretty clean. (A few
NA&amp;#8217;s, but nothing major.) So, basic loading of the file is cake.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;6&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;7&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;8&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;9&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;10&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;11&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;12&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;13&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;14&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;15&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;16&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;17&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;18&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;19&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;20&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;21&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;22&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;23&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;r&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;citydiff &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;city1_name&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; city1_logfile&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; city2_name&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; city2_logfile&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  first_city &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; read.csv&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;city1_logfile&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  second_city &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; read.csv&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;city2_logfile&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;c1&quot;&gt;# Attach the name to each table&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  first_city&lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;city &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; city1_name&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  second_city&lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;city &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; city2_name&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;c1&quot;&gt;# join the tables together in holy matrimony&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  weather &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; rbind&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;first_city&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; second_city&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;c1&quot;&gt;# &#8230; and make the city name an unordered factor&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  weather&lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;city &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; factor&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;weather&lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;city&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; levels&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;c&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;city1_name&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; city2_name&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;c1&quot;&gt;# Fix up precipitation (it came in as a factor)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  weather&lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;PrecipitationIn &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; as.numeric&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;weather&lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;PrecipitationIn&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;c1&quot;&gt;# and parse the date field&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  weather&lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;PST &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; as.Date&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;weather&lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;PST&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;%Y-%m-%d&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;m&quot;&gt;&#8230;..&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;(It&amp;#8217;s throwing a warning about a factor that I don&amp;#8217;t understand, but it seems to be working overall, so I&amp;#8217;m not really sure what&amp;#8217;s going on there. I even broke out R&amp;#8217;s &lt;a href=&quot;http://www.stats.uwo.ca/faculty/murdoch/software/debuggingR/debug.shtml&quot;&gt;awesome debugger&lt;/a&gt; to no avail.)&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s look at the data.&lt;/p&gt;

&lt;h4&gt;Basic Temperature distribution&lt;/h4&gt;

&lt;p&gt;The first thing to do is just toss all the temperatures (there are
14,000+ of them since 1991) into a probability distribution, just to see
where they fall. This is good use for &lt;code&gt;qplot&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;r&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;qplot&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;Max.TemperatureF&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; color&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;city&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; data &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; weather&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; geom&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;density&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;img src=&quot;http://serialized.net/images/r_relocation/overall_temp_ranges.png&quot; width=&quot;572&quot; height=&quot;354&quot;&gt;&lt;/p&gt;

&lt;p&gt;The curves are similar, obviously offset from each
other by about 20 degrees F; but the Portland curve has a sharper back
slope &amp;#8211; meaning that temperatures do fall in the 30-50 range, but more
often hit 50-90.&lt;/p&gt;

&lt;p&gt;Ok, temps are interesting, but let&amp;#8217;s see how they fall across the year.
We could look month by month, or day by day, but that feels &amp;#8220;too
coarse&amp;#8221; and &amp;#8220;too granular&amp;#8221; respectively. I chose to break things out by week of the
year. The trick here is to use &lt;code&gt;as.POSIXlt()&lt;/code&gt; to interpret our &lt;code&gt;Date&lt;/code&gt;,
then modulo the day of year by 7. The &lt;code&gt;sapply&lt;/code&gt; is just to fix the case
(leap year?) where a single date would end up in the 53rd week of the
year &amp;#8211; this just clamps them all to 52.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;r&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;weather&lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;weeknum &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; sapply&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; as.POSIXlt&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;weather&lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;PST&lt;span class=&quot;p&quot;&gt;)$&lt;/span&gt;yday &lt;span class=&quot;o&quot;&gt;%/%&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; min&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;52&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)})&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;So, I really fell in love (all over again) with &lt;code&gt;ggplot2&lt;/code&gt; while making this graph.
Check it out:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://serialized.net/images/r_relocation/temps_over_year.png&quot; width=&quot;572&quot; height=&quot;354&quot;&gt;&lt;/p&gt;

&lt;p&gt;And the code:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;6&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;7&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;8&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;r&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;ggplot&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;weather&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; aes&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;weeknum&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; Max.TemperatureF&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; colour&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;Max.TemperatureF&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; facet_grid&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;city~&lt;span class=&quot;m&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; geom_point&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;alpha&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; position&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;position_jitter&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;width&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; scale_colour_gradient&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;low&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;blue&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; high&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;red&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; geom_hline&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;yintercept&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; geom_hline&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;yintercept&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; geom_smooth&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;method&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;loess&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; size&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; scale_x_continuous&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;formatter&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; format&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;strptime&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;paste&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;1990 1 &amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; x&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; format&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;%Y %w %U&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;%B&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; xlab&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Month&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; ylab&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Maximum Temperature (F)&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Breaking it down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;using the weather data frame we made, with &lt;code&gt;weeknum&lt;/code&gt; on the x axis, and &lt;code&gt;Max.TemperatureF&lt;/code&gt; on the y axis and keying the colorization&lt;/li&gt;
&lt;li&gt;Facet the graph (make multiple sections), one for each city in our data set&lt;/li&gt;
&lt;li&gt;Draw the data with points, at opacity set to 1/6, so points that get plotted a lot will end up darker, and jittered a bit to smooth things out&lt;/li&gt;
&lt;li&gt;Color the data points with a gradient, from blue to red. (Nice for intuitive hot/cold display)&lt;/li&gt;
&lt;li&gt;Put horizontal lines at 60 and 90 degrees (The points at which it starts to feel &amp;#8220;chilly&amp;#8221; and &amp;#8220;hot&amp;#8221;)&lt;/li&gt;
&lt;li&gt;Run a smoothed line through the whole thing to make the center more obvious&lt;/li&gt;
&lt;li&gt;Convert the x axis from being hard-to-comprehend &amp;#8220;week numbers&amp;#8221; back to months&lt;/li&gt;
&lt;li&gt;Then put good labels on the X and Y axis&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;It&amp;#8217;s really readable, beauitful, and was actually shockingly simple to make. (Other than remapping the X axis. That was fun. The trick is to take a week number, tag it into an arbitrary year with an arbitrary day (so &lt;code&gt;strptime&lt;/code&gt; can parse it), then reformat &lt;strong&gt;that&lt;/strong&gt; date as &lt;code&gt;%B&lt;/code&gt;, being the full date string. There&amp;#8217;s got to be a better way&amp;#8230;. but that worked!)&lt;/p&gt;

&lt;p&gt;So what does the image actually tell us about the weather? Hopefully,
it&amp;#8217;s obvious. In Portland, December to February are pretty consistently
chilly. In the summer, it occasionally gets hot, but between May and
October it&amp;#8217;s pretty perfect.&lt;/p&gt;

&lt;p&gt;In Van Nuys, it&amp;#8217;s rare to be chilly, but in June to October, get ready
to run your AC.&lt;/p&gt;

&lt;h4&gt;It&amp;#8217;s not just about the temperature&lt;/h4&gt;

&lt;p&gt;So, it&amp;#8217;s nice not to need a sweatshirt for the temperature, but what
about the gray? It can be warm and still depressingly dark outside.
Thankfully, the data set includes a cloud cover metric!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Station_model#Cloud_cover&quot;&gt;Cloud Cover&lt;/a&gt; is
a number from 0-8, representing the amount of the sky which is
covered&amp;#8230;. by cloud.&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s take a quick peek at the distribution with &lt;code&gt;qplot&lt;/code&gt;, sending a
smooth line (and leaving the raw week numbers this time) through the
data:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;r&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;qplot&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;weeknum&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; CloudCover&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; data &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; weather&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; geom&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;smooth&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; color&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;city&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; span&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;img src=&quot;http://serialized.net/images/r_relocation/cloud_cover_by_week.png&quot; width=&quot;572&quot; height=&quot;354&quot;&gt;&lt;/p&gt;

&lt;p&gt;So, the cities have similar curves, also offset (by about 3, or 37%
cloud cover). In the middle of the summer, Van Nuys typically has around
18% cover, and Portland 43%. So: Portland is Cloudy. &lt;strong&gt;Myth Confirmed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Breaking out &lt;code&gt;ggplot2&lt;/code&gt;, we can get a much clearer picture of how cloudy
it is:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://serialized.net/images/r_relocation/cloud_cover_improved.png&quot; width=&quot;572&quot; height=&quot;354&quot;&gt;&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;6&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;7&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;r&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;ggplot&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;weather&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; aes&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;weeknum&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; CloudCover&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; colour&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;CloudCover&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; facet_grid&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;city~&lt;span class=&quot;m&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; geom_point&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;position&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;position_jitter&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;width&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; height&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; alpha&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;I&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; geom_smooth&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;size&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; scale_colour_gradient&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;low&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;blue&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; high&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;black&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; scale_x_continuous&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;formatter&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; format&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;strptime&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;paste&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;1990 1 &amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; x&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; format&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;%Y %w %U&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;%B&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; xlab&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Month&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; ylab&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Cloud Cover&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;It&amp;#8217;s using basically the same method as for the temperature graph,
except I modeled the cloud cover as a color range from blue to black.
(Awww, cute.)&lt;/p&gt;

&lt;p&gt;You can see something interesting when you compare it back to the
temperature graphs: the cold days correlate with the cloudy days pretty
well! So, the winter is sucky-cold and sucky-gray all at the same time.
At least you get it out of the way all at once (while the days are
short, too!)&lt;/p&gt;

&lt;p&gt;So how nice &lt;strong&gt;is&lt;/strong&gt; the spring and summer?&lt;/p&gt;

&lt;h4&gt;It&amp;#8217;s just a perfect day&lt;/h4&gt;

&lt;p&gt;What might a perfect day look like?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Comfortable temperature (60-90 degrees)&lt;/li&gt;
&lt;li&gt;Not too cloudy (Less than 50% cloud cover)&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;It turns out that&amp;#8217;s an easy query to make against the data frame.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;r&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;weather&lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;ideal &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;k-Variable&quot;&gt;F&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;weather &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; within&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;weather&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    ideal&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;Max.TemperatureF &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; Max.TemperatureF &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;90&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; CloudCover &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;k-Variable&quot;&gt;T&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;weather&lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;ideal &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; as.logical&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;weather&lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;ideal&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Make a new column called &lt;code&gt;ideal&lt;/code&gt; and fill it with &lt;code&gt;F&lt;/code&gt;&amp;#8217;s, then change the
value to &lt;code&gt;T&lt;/code&gt; wherever those conditions are met &amp;#8211; then convert the whole
thing to a logical (boolean) type. Easy!&lt;/p&gt;

&lt;p&gt;So now we can see where &amp;#8220;ideal&amp;#8221; versus &amp;#8220;not-ideal&amp;#8221; days fall across the
year. Week-by-week would probably be too noisy for this, so I added a
column for &lt;code&gt;month&lt;/code&gt; to the data frame as well.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;r&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;weather&lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;month &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; factor&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;format&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;weather&lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;PST&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;%B&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; order&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;TRUE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; levels&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;c&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;January&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;February&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;March&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;April&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;May&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;June&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;July&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;August&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;September&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;October&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;November&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;December&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;img src=&quot;http://serialized.net/images/r_relocation/ideal_by_month.png&quot; width=&quot;572&quot; height=&quot;354&quot;&gt;&lt;/p&gt;

&lt;p&gt;A much simpler incarnation of &lt;code&gt;ggplot&lt;/code&gt; this time:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;r&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;ggplot&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;weather&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; aes&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;month&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; fill&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;ideal&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; geom_histogram&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; facet_grid&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;city~&lt;span class=&quot;m&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; opts&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;axis.text.x  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; theme_text&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;angle&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; size&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;And the results are again interesting; I would not have bet on November
having the most ideal days here in Southern California, but it makes
sense. And, July-September, over 1/2 the Portland days are ideal ones!
(&lt;em&gt;cough&lt;/em&gt;, like basically every month in Van Nuys.)&lt;/p&gt;

&lt;p&gt;(Of course, anyone who&amp;#8217;s been to Van Nuys can attest to the fact that, no matter how
great the weather is, you&amp;#8217;re very unlikely to have a perfect day &lt;em&gt;in
general.&lt;/em&gt; Because you&amp;#8217;re &lt;strong&gt;in Van Nuys&lt;/strong&gt;.)&lt;/p&gt;

&lt;p&gt;So just to quickly summarize the data:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;r&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;ideal_days &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; weather&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;weather&lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;ideal&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;TRUE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,]&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;qplot&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;city&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;ideal_days&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;img src=&quot;http://serialized.net/images/r_relocation/ideal_summary.png&quot; width=&quot;572&quot; height=&quot;354&quot;&gt;&lt;/p&gt;

&lt;p&gt;Portland has about 42% of the &amp;#8220;ideal days&amp;#8221; that Van Nuys does. Which, given everything else that &lt;a href=&quot;http://www.youtube.com/watch?v=AVmq9dq6Nsg&quot;&gt;Portland&amp;#8217;s got going for it&lt;/a&gt; is actually still a pretty good result.&lt;/p&gt;

&lt;p&gt;That gives me an idea&amp;#8230; I bet I can point R at some Crime, Traffic, School, and Cost of Living statistics to get a more well-rounded picture :)&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Screencasting Presentations With Screenflow</title>
    <link href="http://serialized.net/2011/11/screencasting-presentations-with-screenflow/"/>
    <updated>2011-11-18T12:42:00-08:00</updated>
    <id>http://serialized.net/2011/11/screencasting-presentations-with-screenflow</id>
    <content type="html">&lt;p&gt;I&amp;#8217;ve been really enjoying screencasting my presentations, and have come
up with a nice workflow using the (commercial) Mac app &lt;a href=&quot;http://www.telestream.net/screen-flow/&quot;&gt;ScreenFlow&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Watch the video for the full details, but the basic process is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Record the screen while you give the presentation in &amp;#8220;presenter mode&amp;#8221; (so notes are available)&lt;/li&gt;
&lt;li&gt;Also record video from your computer&amp;#8217;s camera&lt;/li&gt;
&lt;li&gt;Crop down to just the slide portion of the presenter view&lt;/li&gt;
&lt;li&gt;Overlay the video on the slides and make it fully transparent (Opacity 0%)&lt;/li&gt;
&lt;li&gt;Skim through the video, watching for slide changes as cues&lt;/li&gt;
&lt;li&gt;Insert video actions (⌘K) and flip the Opacity between (100%/0%) to
show the slide or the video.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;At this point, I can come up with a very nice &amp;#8216;canned version&amp;#8217; of a
presentation in only slightly more than the time it takes to simply give the presentation. It&amp;#8217;s also a great way to rehearse!&lt;/p&gt;

&lt;p&gt;In the video I also recommend the &lt;a href=&quot;http://www.amazon.com/gp/product/B001R76D42?ie=UTF8&amp;amp;tag=httpserianet-20&amp;amp;linkCode=shr&amp;amp;camp=213733&amp;amp;creative=393185&amp;amp;creativeASIN=B001R76D42&amp;amp;ref_=sr_1_1&amp;amp;qid=1321651654&amp;amp;sr=8-1&quot;&gt;Samson Go Mic&lt;/a&gt;, ($40) which I&amp;#8217;ve been nothing but happy with.&lt;/p&gt;

&lt;p&gt;(The full list of &lt;a href=&quot;http://www.telestream.net/pdfs/technical/screenflow-shortcuts.pdf&quot;&gt;Screenflow Keyboard Shortcuts&lt;/a&gt; is good to keep handy.)&lt;/p&gt;

&lt;iframe src=&quot;http://player.vimeo.com/video/32279774?title=0&amp;amp;byline=0&amp;amp;portrait=0&quot; width=&quot;400&quot; height=&quot;255&quot; frameborder=&quot;0&quot; webkitAllowFullScreen mozallowfullscreen allowFullScreen&gt;&lt;/iframe&gt;


&lt;p&gt;A technical side note: the video quality in the beginng of the video is a
little off. The actual &amp;#8220;presentation&amp;#8221; was in 4:3, but the application
demo was widescreen. This meant a bit of &lt;code&gt;ffmpeg&lt;/code&gt; magic, (attaching
&amp;#8216;letterboxes&amp;#8217; to the sides to make it effectively widescreen) so I could glue
the two videos together. When you actually use this method to simply
give a presentation, it ends up looking even nicer.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8221;&gt;&lt;span class=&#8217;line&#8217;&gt;$ ffmpeg -i Presentation.mov -s 560x416 -r 30000/1001 -padleft 46 -padright 48 -vcodec libx264 -vpre hq -acodec libf@c -ac 2 -ar 48000 -ab 192k PresentationLetterbox.mov&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;

</content>
  </entry>
  
  <entry>
    <title>Going Fast With GMail&#8217;s Keyboard Shortcuts</title>
    <link href="http://serialized.net/2011/11/going-fast-with-gmails-keyboard-shortcuts/"/>
    <updated>2011-11-16T17:26:00-08:00</updated>
    <id>http://serialized.net/2011/11/going-fast-with-gmails-keyboard-shortcuts</id>
    <content type="html">&lt;p&gt;I&amp;#8217;m frequently surprised by how many people don&amp;#8217;t know about the awesome &lt;a href=&quot;http://mail.google.com/support/bin/answer.py?answer=6594&quot;&gt;GMail keyboard shortcuts&lt;/a&gt; that are built in to the web application. (And yes, this is the 1 billionth google hit on this topic, but the battle against ignorance is won post by post!)&lt;/p&gt;

&lt;p&gt;I use them constantly, and they really help churn through the inbox efficiently and effectively.&lt;/p&gt;

&lt;p&gt;First, you need to turn them on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Settings (Gear icon) -&gt; General -&gt; Keyboard Shortcuts On&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Click the link above to see the overall list, but the basics I always use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;x&lt;/strong&gt; =&gt; select a message&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;e&lt;/strong&gt; =&gt; archive a message&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;j&lt;/strong&gt;/&lt;strong&gt;k&lt;/strong&gt; =&gt; Move to next/previous conversation&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Just those 4 keys will let you BLAST through conversations that don&amp;#8217;t apply to you. I often end up doing (x,j,x,j,x,j,e) (select 3 conversations, then archive the lot of them in one swoop.) If it&amp;#8217;s spam, or something I know I&amp;#8217;ll never need again, replace &amp;#8217;&lt;strong&gt;e&lt;/strong&gt;&amp;#8217; with &amp;#8217;&lt;strong&gt;#&lt;/strong&gt;&amp;#8217; (&lt;em&gt;delete&lt;/em&gt;)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;#&lt;/strong&gt; =&gt; delete selected conversation&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Ok, so sometimes you actually need to read a conversation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;o&lt;/strong&gt; =&gt; open the conversation under the cursor for reading&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Our good friend &amp;#8217;&lt;strong&gt;x&lt;/strong&gt;&amp;#8217; will pop you right back to the main view, with the current message selected.
So if there&amp;#8217;s a lot of messages I need to read, (o,x,j,o,x,j,&amp;#8230;.  e) will be reading through them all, then archiving the bunch.&lt;/p&gt;

&lt;p&gt;If it&amp;#8217;s one of those conversations that you think will go on for a while
and isn&amp;#8217;t relevant, the wonderful &lt;strong&gt;m&lt;/strong&gt; (&lt;em&gt;mute&lt;/em&gt;) will pre-archive the
rest of the conversation, without you having to deal with it popping
back up later! (I have to imagine there are some monster and
interminable threads that happen in the googleplex.)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;m&lt;/strong&gt; =&gt; mute the conversation&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;And then there&amp;#8217;s replying! Using shortcuts gets you another gorgeous side effect, way lower risk of accidentally reply-all&amp;#8217;ing.&lt;/p&gt;

&lt;p&gt;When you have a message selected&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;r&lt;/strong&gt; =&gt; reply&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;a&lt;/strong&gt; =&gt; reply-all&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;f&lt;/strong&gt; =&gt; forward&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Boom. Tasty efficiency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: &lt;a href=&quot;https://twitter.com/naydichev&quot;&gt;@naydichev&lt;/a&gt; reminds me of
the most important shortcut of all:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;?&lt;/strong&gt; =&gt; help (show all commands.)&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <title>Using Ogres to Improve Your Designs</title>
    <link href="http://serialized.net/2011/10/using-ogres-to-improve-your-designs/"/>
    <updated>2011-10-21T18:01:00-07:00</updated>
    <id>http://serialized.net/2011/10/using-ogres-to-improve-your-designs</id>
    <content type="html">&lt;h2&gt;The problem&lt;/h2&gt;

&lt;p&gt;Creating new designs (in whatever domain) is always a bit of a tightrope walk &amp;#8211; especially as an organization grows. How much do we try and figure out in advance, vs learning and adjusting as we go? How many people do we involve at what stage of the process?&lt;/p&gt;

&lt;p&gt;When the design you&amp;#8217;re working on will be largely owned and maintained by a 24x7 operations team, this &amp;#8220;involvement&amp;#8221; aspect can be particularly vital. It&amp;#8217;s hard to imagine building a great and coherent design with 20+ people, but 20+ people still have to be full educated about how the system works, (largely) satisfied with the decisions that are made &amp;#8211; and, more importantly, have &lt;strong&gt;years&lt;/strong&gt; of collective experience that can help find weak points or make vital improvement suggestions.&lt;/p&gt;

&lt;h2&gt;An approach&lt;/h2&gt;

&lt;p&gt;Our current strategy is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;have a small team produce designs/prototypes/working code&lt;/li&gt;
&lt;li&gt;have periodic larger-scale reviews for education, analysis and feedback.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;What those &amp;#8220;reviews&amp;#8221; look like is a design that is, itself, undergoing incremental learning and feedback.&lt;/p&gt;

&lt;p&gt;Our first stabs at it were fine, but clearly could be improved a lot. We brought the team together, walked through some slides, and did Q&amp;amp;A. In that format, though, there&amp;#8217;s a pretty low upper bound on the number of people that can contribute at any moment. 20+ people in a &amp;#8220;one person talks&amp;#8221; scenario means a lot of standing around, which isn&amp;#8217;t a great use of anyone&amp;#8217;s time, and isn&amp;#8217;t likely to even end up granting much attention and focus.&lt;/p&gt;

&lt;p&gt;This week, we attempted at &amp;#8220;version 2&amp;#8221;, which while still not perfect, was a lot better.&lt;/p&gt;

&lt;h1&gt;Objectives&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Actually make the product great. (Or, barring that, &amp;#8220;better.&amp;#8221;)&lt;/li&gt;
&lt;li&gt;Create more (actual) shared ownership and understanding of the design.&lt;/li&gt;
&lt;li&gt;Enhance the social network between the teams so that ad-hoc collaboration becomes more likely in future.&lt;/li&gt;
&lt;li&gt;Improve shared vocabulary and methods around value and risk management (which we are &lt;a href=&quot;http://discovermagazine.com/2011/jul-aug/11-what-you-dont-know-can-kill-you&quot;&gt;bad at doing intuitively&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Make good use of everyone&amp;#8217;s time: be engaging and effective.&lt;/li&gt;
&lt;li&gt;Have fun!&lt;/li&gt;
&lt;/ol&gt;


&lt;h1&gt;How It Works, and what was that you were saying about Ogres?&lt;/h1&gt;

&lt;h2&gt;Background&lt;/h2&gt;

&lt;p&gt;I love the book &lt;a href=&quot;http://goo.gl/GMR8e&quot;&gt;Gamestorming&lt;/a&gt;. It&amp;#8217;s full of frameworks and patterns for having more than a few people interact in ways that&amp;#8217;s both engaging and effective.&lt;/p&gt;

&lt;p&gt;The review we did was based on the Gamestorming game &lt;a href=&quot;http://www.gogamestorm.com/?p=572&quot;&gt;Challenge Cards&lt;/a&gt;.
In brief, you form two teams: one team creates challenges to the design, the other creates solutions.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;The challenge team picks a card from the deck and plays it on the table, describing a scene or event where the issue might realistically arise. The solution team must then pick a card from their deck that addresses the challenge. If they have a solution they get a point, and if they don’t have a solution the challenge team gets a point. The teams then work together to design a card that addresses that challenge.&lt;/p&gt;&lt;/blockquote&gt;


&lt;p&gt;For fun, and to emphasize the game aspect (and dampen issues with taking criticism personally), I brought in a silly element of making the &amp;#8220;solution team&amp;#8221; be Knights, defending a castle &amp;#8211; and the &amp;#8220;challenge team&amp;#8221; be gnarly Ogres.&lt;/p&gt;

&lt;p&gt;The art and concepts were introduced in some pre-made cards for playing the game, and in the slide deck that introduced the game to the players. (All of that can be downloaded at the end of the post.)&lt;/p&gt;

&lt;h2&gt;Gameplay&lt;/h2&gt;

&lt;p&gt;&lt;img class=&quot;right&quot; src=&quot;http://serialized.net/images/KnightRoundtableSmall.jpg&quot; width=&quot;240&quot; height=&quot;180&quot; title=&quot;The Knights prepare their defense&quot; &gt;&lt;/p&gt;

&lt;p&gt;The basic flow of the event (which took about 90 minutes total, each step being timeboxed) was:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get together, and do a brief review of the current design (focusing on recent changes, and in-progress work.) People get handouts of the architecture to review through the game.&lt;/li&gt;
&lt;li&gt;Split into two teams, Knights and Ogres, both of whom headed to their own rooms. (Anyone could choose to be on either team.)&lt;/li&gt;
&lt;li&gt;As a group, use the &lt;a href=&quot;http://www.gogamestorm.com/?p=470&quot;&gt;Heuristic Ideation Technique&lt;/a&gt; (more on that below) to brainstorm approaches for solution/challenge.&lt;/li&gt;
&lt;li&gt;Form smaller groups, and create the cards for the Challenge.&lt;/li&gt;
&lt;li&gt;Meet back up, and play through the decks as described above.&lt;/li&gt;
&lt;li&gt;Reconvene as a larger group and debrief.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;&lt;img class=&quot;right&quot; src=&quot;http://serialized.net/images/InCombatSmall.jpg&quot; width=&quot;240&quot; height=&quot;180&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Heuristic Ideation?&lt;/h2&gt;

&lt;p&gt;This is a clunky name for a &lt;a href=&quot;http://www.gogamestorm.com/?p=470&quot;&gt;simple and cool idea&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I used it to help brainstorm points of potential weakness in the design &amp;#8211; breaking things down into &amp;#8220;attributes and actions&amp;#8221; and &amp;#8220;components.&amp;#8221;&lt;/p&gt;

&lt;p&gt;Attributes are things &lt;em&gt;about&lt;/em&gt; the system: Capacity, Security, Reliability, &amp;#8230;
Actions are things we know can &lt;em&gt;change&lt;/em&gt; in the system: Upgrade, Deploy, Replace, Fail, &amp;#8230;.&lt;/p&gt;

&lt;p&gt;Components cover &lt;em&gt;physical&lt;/em&gt; things: Hard Drive, Network Port, Switch, CPU, DIMM, &amp;#8230;.
They also cover &lt;em&gt;logical&lt;/em&gt; things, like Authentication System, Filesystem, User Interface, &amp;#8230;&lt;/p&gt;

&lt;p&gt;I knew we&amp;#8217;d end up with large enough lists that the grid layout called for in Heuristic Ideation wouldn&amp;#8217;t work &amp;#8211; our boards aren&amp;#8217;t that big &amp;#8211; so opted for this 2 column layout:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://serialized.net/images/HeuristicIdeationRiff.jpg&quot; width=&quot;480&quot; height=&quot;360&quot;&gt;&lt;/p&gt;

&lt;p&gt;You can apply each attribute or action in the left column to each of the
components on the right; by the time you get through all of them, you&amp;#8217;ll
have really thought through possible fragile areas of the system.&lt;/p&gt;

&lt;p&gt;For example, take &amp;#8216;Filesystem&amp;#8217; as a component; we can discuss it&amp;#8217;s
capacity, security, reliability, as well as what happens if we upgrade
it, run a deploy of new code, if it fails, &amp;#8230; and so on. Then, think
about all of those attributes and actions applied to the next component!
(Say, a network switch.)&lt;/p&gt;

&lt;h2&gt;Comparative Risk&lt;/h2&gt;

&lt;p&gt;Instead of just using blank index cards, I threw a bit of layout at it.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://serialized.net/images/CompletedCards.jpg&quot; title=&quot;&quot; &gt;&lt;/p&gt;

&lt;p&gt;The extra fields help scope the risk a bit. (Obviously they are all going to be wild-ass guesses, but they still let us group things by order of magnitude.) Primarily, they&amp;#8217;re just there to get people talking in these kinds of terms about relative possible impacts of unlikely things.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;#ragemode&lt;/strong&gt; tag came from one of our customers who was on the bad end of a miscommunication surrounding some backups, and how fresh they were, (a bit &lt;em&gt;too&lt;/em&gt; fresh, in his case), leading to them losing some data. It refers to the fact that some things, when they go wrong, give us the reaction &amp;#8220;hey, it&amp;#8217;s the internet, these things happen.&amp;#8221; Others are &lt;strong&gt;infuriating&lt;/strong&gt;. So it&amp;#8217;s an attempt to let us weight possible failures by emotional impact.&lt;/p&gt;

&lt;p&gt;When 2 cards are paired up, you can just do the math:&lt;/p&gt;

&lt;p&gt;(Time to detect + Time to repair) * Customers Impacted * Expected times per year that this freakish thing might happen * #ragemode == A very fuzzy estimate of &amp;#8220;customer-minutes of impact per year.&amp;#8221;&lt;/p&gt;

&lt;h2&gt;Lessons&lt;/h2&gt;

&lt;p&gt;It was a lot of fun, and met (to at least some degree) all of the objectives I had for it. We&amp;#8217;re still going through the cards and learning from them.&lt;/p&gt;

&lt;p&gt;However, there was a lot of room for improvement.&lt;/p&gt;

&lt;p&gt;First, Heuristic Ideation is awesome. We can use that in all kinds of different scenarios. I&amp;#8217;m writing up a list of the Components/Actions/Attributes the teams brainstormed for the wiki, so we can use and further develop them in the future.&lt;/p&gt;

&lt;p&gt;The biggest improvement to the game is in the Challenge/Solution dynamic. The Challenges tended to be very specific. (&amp;#8220;Filesystem gets corrupted.&amp;#8221;) However, the Solutions have to be pretty generic. (&amp;#8220;Reinstall the server from scratch and restore from backup.&amp;#8221;) Technically, that counted as a point-worthy exchange for the defense, but it didn&amp;#8217;t really help us explore the problem.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;right&quot; src=&quot;http://serialized.net/images/GiveUpSmall.jpg&quot; width=&quot;180&quot; height=&quot;240&quot; title=&quot;A good example of an overly generic defense&quot; &gt;&lt;/p&gt;

&lt;p&gt;I&amp;#8217;d like to try it this way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Still have the Knights do their defensive planning, but not actually make cards in advance&lt;/li&gt;
&lt;li&gt;When the challenge card is played, come up with (on the fly) the best solution we can currently execute.

&lt;ul&gt;
&lt;li&gt;If that is &amp;#8220;good enough&amp;#8221; (as decided by the players, or arbitrated by the facilitator), the Knights get a point.&lt;/li&gt;
&lt;li&gt;If it&amp;#8217;s not, then the Ogres get the point, and then the two teams move on to collaboratively coming up with the solution.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;That should keep the focus more on what really matters, and at the level of specifics, and less on the technicalities of &amp;#8220;is your vague defensive card applicable here or not.&amp;#8221;&lt;/p&gt;

&lt;p&gt;A neat thing we discovered was that if someone proposed an attack for which our &amp;#8220;defenses&amp;#8221; were already good enough, that was a good data point that training/documentation/education needed to be beefed up around that aspect.&lt;/p&gt;

&lt;p&gt;One of the Operations Managers had a great suggestion: now that everyone gets the basics, use this framework for fire drills. (Now known as &amp;#8220;surprise attacks&amp;#8221; or &amp;#8220;Ogre Rush!&amp;#8221;) Just pop into the NOC with a few of the &amp;#8220;Attack&amp;#8221; cards all filled out, and make sure people are solid on what the procedure would be to deal with that.&lt;/p&gt;

&lt;h1&gt;Share and Enjoy&lt;/h1&gt;

&lt;p&gt;Please feel free to rip off any part of this that was useful at all.
I have compiled both PDF versions of the instructional slide deck and playing cards, as well as the original Keynote files.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://serialized.net/images/KnightsVOgres.zip&quot;&gt;Knights vs Ogres Game Materials&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I made my best effort to track down royalty free art &amp;#8211; please contact me if I&amp;#8217;ve inadvertently used something of yours!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>An Iteration of the Lean Meetings Concept</title>
    <link href="http://serialized.net/2011/09/an-iteration-of-the-lean-meetings-concept/"/>
    <updated>2011-09-28T09:44:00-07:00</updated>
    <id>http://serialized.net/2011/09/an-iteration-of-the-lean-meetings-concept</id>
    <content type="html">&lt;p&gt;The &lt;a href=&quot;http://personalkanban.com/pk/blog&quot;&gt;Personal Kanban blog&lt;/a&gt; ran a
great pair of articles on &amp;#8220;Lean Meetings&amp;#8221; (&lt;a href=&quot;http://www.personalkanban.com/pk/designpatterns/democratize-meetings-with-personal-kanban/&quot;&gt;part 1&lt;/a&gt;,
&lt;a href=&quot;http://www.personalkanban.com/pk/expert/lean-meetings-2-semper-gumby/&quot;&gt;part 2&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;I recommend reading through them to get more context for what follows,
but I&amp;#8217;ll re-share one of the biggest insights: the point of a meeting is
to &lt;em&gt;have a conversation.&lt;/em&gt; Pre-set agendas feel like best practice, but
they can get in the way of that &amp;#8216;true goal&amp;#8217; more often than not.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Control, agendas, and procedures impeded conversation, focusing on the&lt;br/&gt;structure of the meeting rather than the topics at hand. If you want&lt;br/&gt;people to engage in and feel they’ve derived value from your meeting,&lt;br/&gt;make them feel respected, not restricted.&lt;/p&gt;&lt;/blockquote&gt;


&lt;p&gt;After having orchestrated a few meetings using this idea, some helpful
practices have emerged, which seemed worth sharing.&lt;/p&gt;

&lt;p&gt;The basic framework still holds:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Framework&lt;/em&gt;: Draw a Personal Kanban&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Personal Agendas&lt;/em&gt;: Invite all attendees to write their topics on sticky
notes&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Democratization&lt;/em&gt;: Invite all attendees to vote on the topics on the table (each person gets two votes)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Group Agenda:&lt;/em&gt; Prioritize the sticky notes&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Discuss&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;The riffs on that list are:&lt;/p&gt;

&lt;h2&gt;Framework&lt;/h2&gt;

&lt;p&gt;We found that converting (To Do, Doing, Done) to (To Do, &lt;em&gt;Goals&lt;/em&gt;, Doing,
&lt;em&gt;Takeaways&lt;/em&gt;, Done) has been helpful.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://serialized.net/images/LeanMeetingKanban.png&quot; title=&quot;Lean Meeting Kanban&quot; &gt;&lt;/p&gt;

&lt;p&gt;Here is what those new substeps entail:&lt;/p&gt;

&lt;h3&gt;Goals&lt;/h3&gt;

&lt;p&gt;Before we actually start discussing a topic, create a shared
understanding of what we hope to get out of it.
Paraphrasing David Allen, &amp;#8220;what does &amp;#8216;wild success&amp;#8217; look like at the end of
this?&amp;#8221; What is the value we need to deliver to our customers
or organization by the time we&amp;#8217;re done?&lt;/p&gt;

&lt;p&gt;Concretely, this can come down to basic things. Plan fall employee
event? The goals might be &amp;#8220;Define vision, date, coordinator, and
budget.&amp;#8221;&lt;/p&gt;

&lt;p&gt;It can also be fuzzier: &amp;#8220;Understand each other&amp;#8217;s feelings about this
topic.&amp;#8221;&lt;/p&gt;

&lt;p&gt;In practice, it&amp;#8217;s been interesting how hard it can be for a team to get this
articulated &amp;#8211; and there&amp;#8217;s a high correlation between &amp;#8220;hard to find
goals&amp;#8221; and &amp;#8220;conversations that would wander and go nowhere.&amp;#8221;&lt;/p&gt;

&lt;p&gt;Mechanically, as is hinted at in the diagram above, we found it natural
to add a new sticky with the goals on it as a &amp;#8220;rider&amp;#8221; to the original
topic note. That kept the goals clear and visible to everyone, and they
were referred to frequently.&lt;/p&gt;

&lt;h3&gt;Takeaways&lt;/h3&gt;

&lt;p&gt;This is probably implicit in what it means to move a topic from &amp;#8220;Doing&amp;#8221;
into &amp;#8220;Done&amp;#8221;, but it&amp;#8217;s helpful as a reminder. &amp;#8220;Who is responsible for
taking things away from this item?&amp;#8221; It&amp;#8217;s a good hook for recording
things, especially if there&amp;#8217;s no formal note-taker.&lt;/p&gt;

&lt;p&gt;We also use this as a hook to make sure to consider how any conclusions
(or lack thereof) need to be communicated to the wider group that was
not in attendance at the meeting.&lt;/p&gt;

&lt;h2&gt;Personal Agendas&lt;/h2&gt;

&lt;p&gt;At this point we&amp;#8217;ve only really used this idea as-written, but I&amp;#8217;m
curious to play with various
brainstorming/&lt;a href=&quot;http://en.wikipedia.org/wiki/Gamestorming&quot;&gt;gamestorming&lt;/a&gt; or focusing techniques to
help generate higher-value items for the team to choose from, rather
than those that happen to be top-of-mind for the participants (or have
been recorded in their own trusted systems.)&lt;/p&gt;

&lt;p&gt;We did bring an idea from Kanban in &amp;#8211; &amp;#8216;item types.&amp;#8217; This was helpful at
an all-day monthly meeting one of our teams have. We created a special
designation (color of sticky works, as pictured above, or a separate section in the backlog)
for items that are &amp;#8221;&lt;em&gt;Today Or They Die&lt;/em&gt;&amp;#8221; &amp;#8211; things which will happen
between now and the next meeting, regardless of if we discuss them or
not. If it&amp;#8217;s December 1, and your next Meeting is Jan 1, you should
probably make your Christmas plans.&lt;/p&gt;

&lt;p&gt;This can help with voting; those items may still not end up getting
selected for discussion, but at least the team has a shared
understanding that we&amp;#8217;re letting the opportunity pass.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s mentioned in the linked articles, but the feature of being able to
discover new items &amp;#8220;on the fly&amp;#8221; and work them seamlessly into the
backlog is amazingly useful. In life &lt;a href=&quot;http://en.wikipedia.org/wiki/Dirk_Gently#Holistic_detective&quot;&gt;things are fundamentally interconnected&lt;/a&gt;
so it&amp;#8217;s to be expected and encouraged that we&amp;#8217;ll discover or create things that
&lt;em&gt;need&lt;/em&gt; discussion as a &lt;em&gt;function of&lt;/em&gt; discussion. Agendas hate this idea.&lt;/p&gt;

&lt;h2&gt;Democratization&lt;/h2&gt;

&lt;p&gt;The &amp;#8216;everyone gets N votes&amp;#8217; method works well. We also experimented with a few other methods of prioritization:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;If you only get to discuss one thing today&amp;#8230;&amp;#8221;: each member gets to select one item to bring into To Do. Perhaps more Socialist than Democratic, but it was a nice way to start off the day.&lt;/li&gt;
&lt;li&gt;&amp;#8220;Lightning Round&amp;#8221;: Are there any topics remaining in the backlog we can get through productively in 5 minutes or less? This was a fun way to get back into things after a lunch break, but somewhat risky &amp;#8211; one of the items selected turned into a 45 minute discussion.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;One challenge with voting early in the discussion, particularly for
all-day meetings, is allowing priority to evolve over time as perspectives and
time pressures change. Using voting just to bring a few items into the ready queue, and
then voting again (from scratch) to repopulate when it empties, seemed to work well.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;This way of organizing meetings has really enhanced the quality of our
discussions and the value they deliver. It ends up feeling much more
natural &amp;#8211; still providing the compass and context we&amp;#8217;re frustrated
about not having in a truly chaotic meeting, without the rigidity and
creator bias that an agenda brings. After two separate meetings,
participants made comments like &amp;#8220;that was the most productive and
engaging meeting I&amp;#8217;ve ever been a part of.&amp;#8221; That&amp;#8217;s reason enough to
continue exploring!&lt;/p&gt;

&lt;p&gt;Thanks again to &lt;a href=&quot;https://twitter.com/ourfounder&quot;&gt;Jim&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/sprezzatura&quot;&gt;Tonianne&lt;/a&gt;
for the education and inspiration.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Getting more Signal from your Noise</title>
    <link href="http://serialized.net/2011/02/getting-more-signal-from-your-noise/"/>
    <updated>2011-02-24T00:00:00-08:00</updated>
    <id>http://serialized.net/2011/02/getting-more-signal-from-your-noise</id>
    <content type="html">&lt;p&gt;At &lt;a href=&quot;http://www.socallinuxexpo.org/scale9x/&quot;&gt;SCALE 9x&lt;/a&gt; I presented a talk in the DevOps track called &lt;a href=&quot;http://www.socallinuxexpo.org/scale9x/presentations/signal-noise&quot;&gt;Getting more Signal from your Noise.&lt;/a&gt;.
You can download the slides  (&lt;a href=&quot;http://serialized.net/images/Signal_Noise_With_Notes.pdf&quot;&gt;with notes&lt;/a&gt;, &lt;a href=&quot;http://serialized.net/images/Signal_Noise_No_Notes.pdf&quot;&gt;without notes&lt;/a&gt;), and this is a companion post which contains links and further information.
I&amp;#8217;d recommend reviewing that before reading more, as I won&amp;#8217;t rehash what I covered there.
Due to the 30 minute timebox, I cut out even discussing a few large areas that I can address (briefly) here.&lt;/p&gt;

&lt;h1&gt;The Point&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Data + Open Source is an explosively growing field.&lt;/li&gt;
&lt;li&gt;The complexity of our software systems &amp;#8211; the way we deliver applications and services &amp;#8211; is exploding.&lt;/li&gt;
&lt;li&gt;The number of people trying/needing to build systems like this is exploding. (Not just Flickr and Facebook anymore.)&lt;/li&gt;
&lt;li&gt;The demands on our time and attention are exploding.&lt;/li&gt;
&lt;li&gt;The data that&amp;#8217;s available to us from our infrastructures AND the &amp;#8220;world around&amp;#8221; (finance, customers, social media, etc) is exploding&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The other thing that&amp;#8217;s exploding are the number of businesses who will provide you some form of &amp;#8220;shrink-wrapped&amp;#8221; delivery of the kinds of tools (or at least results) discussed here. Depending on your business, going DIY and duct-taping together what you need may be the wrong idea. However, there are a few major reasons that DIY &lt;em&gt;can be&lt;/em&gt; a good idea.
* Flexibility: We are learning every day the kinds of things we need our systems to tell us in a hurry. Being able to quickly tune them makes a difference.
* Latency and Connectivity: When you&amp;#8217;re using a system for real-time decisionmaking, at least having it on-premise means you can throw GB/sec at it, and have results in seconds.&lt;/p&gt;

&lt;h1&gt;The Data Stack&lt;/h1&gt;

&lt;p&gt;In the talk, I introduced a model for thinking about what types of functionality the different tools available provide.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Collect&lt;/li&gt;
&lt;li&gt;Transport&lt;/li&gt;
&lt;li&gt;Process&lt;/li&gt;
&lt;li&gt;Store&lt;/li&gt;
&lt;li&gt;Present&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Many tools provide just one part of this stack, but more than that are &amp;#8216;hybrids&amp;#8217;. Getting the data you need often means mixing and matching.&lt;/p&gt;

&lt;p&gt;I called out &lt;a href=&quot;http://graphite.wikidot.com/&quot;&gt;graphite&lt;/a&gt;, &lt;a href=&quot;http://collectd.org/&quot;&gt;collectd&lt;/a&gt;, &lt;a href=&quot;http://opentsdb.net/&quot;&gt;OpenTSDB&lt;/a&gt;, &lt;a href=&quot;https://labs.omniti.com/labs/reconnoiter&quot;&gt;reconnoiter&lt;/a&gt;, &lt;a href=&quot;http://esper.codehaus.org/&quot;&gt;esper&lt;/a&gt;, and &lt;a href=&quot;http://vis.stanford.edu/protovis/&quot;&gt;protovis&lt;/a&gt; as being particularly worth at least knowning about.&lt;/p&gt;

&lt;p&gt;Other projects and ecosystems worth studying:&lt;/p&gt;

&lt;h2&gt;Hadoop&lt;/h2&gt;

&lt;p&gt;The literal elephant in the room that I discussed only tangentially, &lt;a href=&quot;http://hadoop.apache.org/&quot;&gt;Hadoop&lt;/a&gt; (and the huge family of tools around it) can be an incredible asset to learning more about your world via storing/managing/questioning your data. &lt;a href=&quot;http://www.cloudera.com/&quot;&gt;Cloudera&lt;/a&gt; remains a great source of both software and education, and is a good place to start.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s now possible to get real-er time information from a Hadoop system, but historically it&amp;#8217;s been essentially for things that are more time sensitive on the 1-day/1-month time range. (Trends, capacity, etc.)&lt;/p&gt;

&lt;h2&gt;Log Processing and Management&lt;/h2&gt;

&lt;p&gt;The state of the art with log management used to be syslog + logrotate = done. There are a lot more options today.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Many people are using &lt;a href=&quot;http://hadoop.apache.org/hdfs/&quot;&gt;HDFS&lt;/a&gt; (before or after processing) for both it&amp;#8217;s scalability, resilience, and ability to integrate with the larger Hadoop family. Orbitz (awesome at sharing, first graphite, now this) have a great &lt;a href=&quot;http://files.meetup.com/1634302/CHUG_HadoopLogsAtOrbitz.pdf&quot;&gt;presentation about &amp;#8216;Hadoop for Logs&amp;#8217;&lt;/a&gt; which is a good overview of what you&amp;#8217;d be getting into.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://code.google.com/p/logstash/&quot;&gt;Logstash&lt;/a&gt; and &lt;a href=&quot;http://www.graylog2.org/&quot;&gt;graylog2&lt;/a&gt; can bring some of the utility of Splunk without the (ahem) cost structures. While graylog2 stores data in MongoDB, Logstash can optionally use &lt;a href=&quot;http://www.elasticsearch.org/&quot;&gt;ElasticSearch&lt;/a&gt;, which is a nicely packaged &amp;#8220;throw text in and RESTfully search&amp;#8221; engine. (Thanks to the author of Graylog2, &lt;a href=&quot;http://twitter.com/_lennart&quot;&gt;@lennart&lt;/a&gt;, for clarifying that.) &lt;a href=&quot;http://twitter.com/timetabling&quot;&gt;@timetabling&lt;/a&gt; suggests you can &lt;a href=&quot;http://www.elasticsearch.org/blog/2010/02/25/nosql_yessearch.html&quot;&gt;glue ElasticSearch to MongoDB&lt;/a&gt;, so that when the data changes you index it &amp;#8211; but out of the box, that&amp;#8217;s not an option.&lt;/li&gt;
&lt;li&gt;A new entrant, &lt;a href=&quot;https://github.com/basho/luwak&quot;&gt;Luwak&lt;/a&gt; runs on top of Riak, so you get the availability + scalability and a Map/Reduce interface to boot.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cloudera/flume&quot;&gt;Flume&lt;/a&gt; and &lt;a href=&quot;https://github.com/facebook/scribe&quot;&gt;Scribe&lt;/a&gt; (as well as messaging systems like &lt;a href=&quot;http://www.rabbitmq.com/&quot;&gt;RabbitMQ&lt;/a&gt;) can replace syslog as the way to shovel raw logs around.&lt;/li&gt;
&lt;li&gt;Google&amp;#8217;s &lt;a href=&quot;http://code.google.com/p/szl/&quot;&gt;Sawzall&lt;/a&gt; is more on the processing side, but it allows you to describe patterns of information you want from your logs, and then in a map/reduce-like way aggregate them.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Data Analysis&lt;/h2&gt;

&lt;p&gt;A basic-to-advanced knowledge of statistics is becoming essential. There are powerful tools (like &lt;a href=&quot;http://www.r-project.org/&quot;&gt;R&lt;/a&gt;, and many libraries available for different languages like &lt;a href=&quot;http://www.scipy.org/&quot;&gt;SciPy&lt;/a&gt;) &amp;#8211; but if you don&amp;#8217;t know what operation you want them to do, they won&amp;#8217;t help.&lt;/p&gt;

&lt;p&gt;Our tax dollars have actually provided a pretty useful introduction, the &lt;a href=&quot;http://www.itl.nist.gov/div898/handbook/&quot;&gt;NIST Handbook&lt;/a&gt;.
I have been overwhelmingly happy with how useful the book &lt;a href=&quot;http://amzn.to/hFzX8H&quot;&gt;Data Analysis with Open Source Tools&lt;/a&gt; has been &amp;#8211; it takes some decent energy to get through, especially if your background is not so math/dev heavy, but it&amp;#8217;s insanely rewarding.&lt;/p&gt;

&lt;h2&gt;Machine Learning&lt;/h2&gt;

&lt;p&gt;&amp;#8220;Machine Learning&amp;#8221; is still a pretty intimidating thing to Google for unless you&amp;#8217;ve got a C.S. PhD. However, it&amp;#8217;s starting to be packaged and democratized enough that mere mortals can start to play.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://mahout.apache.org/&quot;&gt;Apache Mahout&lt;/a&gt; has a lot of potential to be of tremendous use here. Many people are using it more in text-related spaces, but the ability to find patterns and trends across multiple disparate systems is exactly what we need for things like botnet combat. I&amp;#8217;ve just started looking at this and so far am very inspired to dig further.&lt;/p&gt;

&lt;h1&gt;People to Watch&lt;/h1&gt;

&lt;p&gt;This is a by-no-means-comprehensive list of the people whose tweets, software, and writing I&amp;#8217;ve found useful to keep exploring the possibilities and pitfalls here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.semicomplete.com/&quot;&gt;Jordan Sissel&lt;/a&gt; (author of &lt;a href=&quot;http://code.google.com/p/logstash/&quot;&gt;Logstash&lt;/a&gt;, &lt;a href=&quot;ihttp://code.google.com/p/semicomplete/wiki/Grok&quot;&gt;Grok&lt;/a&gt; and &lt;a href=&quot;http://semicomplete.com/projects/fex/&quot;&gt;Fex&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Strata (The ORA Data Conference) Speakers: &lt;a href=&quot;http://lanyrd.com/2011/strata/speakers/&quot;&gt;Lanyrd List&lt;/a&gt; (and Lanyrd&amp;#8217;s awesome &lt;a href=&quot;http://lanyrd.com/2011/strata/writeups/&quot;&gt;Writeup List&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.perfdynamics.com/Bio/njg.html&quot;&gt;Dr. Neil Gunther&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http:/twitter.com/patrickdebois&quot;&gt;Patrick Debois&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://regis.gaidot.net/&quot;&gt;Regis Giadot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://lethargy.org/~jesus/about.html&quot;&gt;Theo Schlossnagle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.percona.com/&quot;&gt;Percona&lt;/a&gt; (Including the very nice implementation of Dr. Gunther&amp;#8217;s &lt;a href=&quot;http://aspersa.googlecode.com/svn/html/usl.html&quot;&gt;Universal Scalability Law&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;


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

&lt;p&gt;Short of a series of books, updated monthly, all I can really provide is an appetiser. Hopefully you&amp;#8217;ve been inspired to move on to your own data hacking &amp;#8220;main course.&amp;#8221;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Testing Perl code that runs commands</title>
    <link href="http://serialized.net/2010/09/testing-perl-code-that-runs-commands/"/>
    <updated>2010-09-22T00:00:00-07:00</updated>
    <id>http://serialized.net/2010/09/testing-perl-code-that-runs-commands</id>
    <content type="html">&lt;p&gt;At the September &lt;a href=&quot;http://losangeles.pm.org/&quot;&gt;Los Angeles Perl Mongers&lt;/a&gt; meetup, &lt;a href=&quot;http://tommystanton.com/&quot;&gt;Tommy Stanton&lt;/a&gt; presented on an in-progress bit of code he&amp;#8217;s working on, &lt;code&gt;App::Git::HomeSync&lt;/code&gt;. (&lt;a href=&quot;http://tommystanton.com/presentations/20100908-Tommy_Stanton-App-Git-HomeSync/&quot;&gt;Presentation&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;As you&amp;#8217;d hope and expect from something headed CPAN-ward, he&amp;#8217;s got lots of tests. As you might have guessed from the name, this module needs to run &lt;code&gt;git&lt;/code&gt; quite a bit, with different command line arguments. Tommy&amp;#8217;s approach to testing this is good &amp;#8211; ship the module with some &amp;#8220;fixtures&amp;#8221; (a directory in a known state which gets unpacked into a temp directory) and then run the command line app in that directory.&lt;/p&gt;

&lt;p&gt;There is another way to approach this, and I realized I didn&amp;#8217;t have any &amp;#8220;open sourceable&amp;#8221; code which demonstrates this technique.
I got a lot of the way through writing this before realizing I have &lt;a href=&quot;http://serialized.net/2009/10/testing-perl-system-interactions/&quot;&gt;blogged a more basic version of this idea before&lt;/a&gt;, but this is a new-and-improved take on things, with much deeper examples.&lt;/p&gt;

&lt;h2&gt;&lt;code&gt;tl;dr&lt;/code&gt;&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;a href=&quot;http://search.cpan.org/perldoc/IPC::Run&quot;&gt;IPC::Run&lt;/a&gt; to run your command line apps&lt;/li&gt;
&lt;li&gt;In your test code, intercept the calls to &lt;code&gt;IPC::Run::run&lt;/code&gt; and return your own data, based on the command line used&lt;/li&gt;
&lt;li&gt;Store sample command line output inside the test file using &lt;a href=&quot;http://search.cpan.org/perldoc/Data::Section&quot;&gt;Data::Section&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I&amp;#8217;ve stashed a full, functional example of this idea in my &lt;a href=&quot;http://github.com/jbarratt/Acme-System&quot;&gt;Acme::System repository on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Code Walkthrough&lt;/h2&gt;

&lt;h3&gt;Using IPC::Run in your code&lt;/h3&gt;

&lt;p&gt;First, there&amp;#8217;s the module code itself. This module does 2 very stupid things.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It returns the sum of all the PID&amp;#8217;s (Process ID&amp;#8217;s) on the system, and it calls &lt;code&gt;ps&lt;/code&gt; to get this information.&lt;/li&gt;
&lt;li&gt;It returns the value of one of the columns from the &lt;code&gt;vmstat&lt;/code&gt; tool.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The important thing is to use &lt;code&gt;IPC::Run::run&lt;/code&gt; to actually run the code, instead of a blind &lt;code&gt;system()&lt;/code&gt; call. Because it&amp;#8217;s a module call, and has a very simple interface, it&amp;#8217;s much easier to mock it (&amp;#8220;override the functionality with &amp;#8216;fake&amp;#8217; functionality) for testing.&lt;/p&gt;

&lt;p&gt;This is in &lt;a href=&quot;http://github.com/jbarratt/Acme-System/blob/master/lib/Acme/System.pm&quot;&gt;lib/Acme/System.pm&lt;/a&gt;. Here&amp;#8217;s the pidsum method (the &lt;code&gt;vmstat_col&lt;/code&gt; method is basically the same, check out the full code if you&amp;#8217;re curious):&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;6&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;7&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;8&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;9&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;10&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;11&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;12&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;13&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;14&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;perl&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pidsum&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;n&quot;&gt;Return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;all&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PID&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;system&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cut&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;sub &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pidsum&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;@ps_cmd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;ps&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;-Ao&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;pid,cmd&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$stdin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$stderr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;undef&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;undef&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ps_output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;nn&quot;&gt;IPC::Run::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;@ps_cmd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$stdin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ps_output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$stderr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;            &lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^\s*(\d+)/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;            &lt;span class=&quot;nb&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/\n/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ps_output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;So, as I said, stupid code. I only care about getting the output, so I pass in undef for the other values &amp;#8211; &lt;code&gt;IPC::Run::run&lt;/code&gt; wants you to supply them anyway.&lt;/p&gt;

&lt;p&gt;However, that little &lt;code&gt;sum&lt;/code&gt;/&lt;code&gt;map&lt;/code&gt;/&lt;code&gt;split&lt;/code&gt; thing sure looks fancy. How much would be willing to wager that it&amp;#8217;s bug-free? Probably not much. How would you even test code like that?&lt;/p&gt;

&lt;p&gt;So, let&amp;#8217;s cheat &amp;#8211; run &lt;code&gt;ps&lt;/code&gt; just the once, stash the results, and use those for testing from there on out.&lt;/p&gt;

&lt;h3&gt;Storing the command line output results&lt;/h3&gt;

&lt;p&gt;Check out the the &lt;a href=&quot;http://github.com/jbarratt/Acme-System/blob/master/t/00-fakerun.t&quot;&gt;whole test file&lt;/a&gt; to see what&amp;#8217;s going on overall.&lt;/p&gt;

&lt;p&gt;There&amp;#8217;s a few bits of weirdness, for sure. Down the end you&amp;#8217;ll see:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;6&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;7&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;8&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;9&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;10&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;11&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;12&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;text&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;    __DATA__
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    __[ ps -Ao pid,cmd ]__
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    PID CMD
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        1 init [2]
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        7 [khelper]
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &#8230;.
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    1887 /usr/sbin/acpid
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    __[ vmstat -n 1 1 ]__
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    procs &#8212;&#8212;&#8212;&#8211;memory&#8212;&#8212;&#8212;- &#8212;swap&#8211; &#8212;&#8211;io&#8212;- -system&#8211; &#8212;-cpu&#8212;-
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    0  0    648  85932 194240 119124    0    0     0     5    2   51  0  0 100  0
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    __END__
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This is the format that &lt;code&gt;Data::Section&lt;/code&gt; wants. You just need to stash each command you run between the underscored square brackets, and follow it with some sample command line data.&lt;/p&gt;

&lt;p&gt;The tricky thing is this &amp;#8211; &lt;code&gt;Data::Section&lt;/code&gt; was built to be used with Modules, not &amp;#8220;plain jane &lt;code&gt;.t&lt;/code&gt; files.&amp;#8221;
So to make that work, you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give your test a package name. I chose to just stick a &lt;code&gt;Test::&lt;/code&gt; in front of the module name.&lt;/li&gt;
&lt;li&gt;Give &lt;code&gt;Data::Section&lt;/code&gt; an instance of that object to stick it&amp;#8217;s methods into.&lt;/li&gt;
&lt;/ul&gt;


&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;perl&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;c1&quot;&gt;# magic; Data::Section wants this to be a module, not a test file.&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;c1&quot;&gt;# trick into thinking this hashref is a member of Test::Acme::System&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bless&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This is the only part of this whole technique that feels truly hacky. If anyone has suggestions for better ways to manage this, let me know.&lt;/p&gt;

&lt;h3&gt;Overriding &lt;code&gt;IPC::Run::run&lt;/code&gt; in a test&lt;/h3&gt;

&lt;p&gt;There are lots of ways to override a module&amp;#8217;s methods; I have had good experiences with &lt;a href=&quot;http://search.cpan.org/perldoc/Test::MockModule&quot;&gt;Test::MockModule&lt;/a&gt;. It&amp;#8217;s pretty easy.&lt;/p&gt;

&lt;h4&gt;Write a callback that emulates &lt;code&gt;IPC::Run::run&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;Here&amp;#8217;s the code that makes that evil hack above worthwhile. Here&amp;#8217;s all you have to do to recover those canned program execution results, using the &lt;code&gt;section_data&lt;/code&gt; method provided by &lt;code&gt;Data::Section&lt;/code&gt; (and that hacky &lt;code&gt;$data&lt;/code&gt; reference):&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;perl&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;sub &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;mock_ipc_run&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$cmd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$stdin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$stderr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;@_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;nv&quot;&gt;$$stdout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;section_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;@$cmd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))};&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h4&gt;&amp;#8220;Mock&amp;#8221; that in place&lt;/h4&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;perl&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;c1&quot;&gt;# override the real run object with one that will use the __DATA__ block&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$module&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Test::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MockModule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;IPC::Run&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;nv&quot;&gt;$module&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;run&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;\&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mock_ipc_run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Actually doing the testing&lt;/h3&gt;

&lt;p&gt;At this point, test away!&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;6&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;7&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;8&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;9&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;perl&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;c1&quot;&gt;# Actually &amp;quot;run the tests&amp;quot;, using the canned results from the __DATA__ block&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;n&quot;&gt;cmp_ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Acme::System::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pidsum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;==&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8278&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;n&quot;&gt;cmp_ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Acme::System::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vmstat_col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;buff&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;==&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;194240&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;n&quot;&gt;cmp_ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Acme::System::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vmstat_col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;si&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;==&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;n&quot;&gt;cmp_ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Acme::System::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vmstat_col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;cs&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;==&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;51&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;n&quot;&gt;cmp_ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Acme::System::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vmstat_col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;swpd&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;==&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;648&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;n&quot;&gt;done_testing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;So I can (independently) calculate what the results should have been, given the arbitrary data I&amp;#8217;ve saved in the &lt;code&gt;__DATA__&lt;/code&gt; block, and test based on those values. Awesome.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;perl&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;n&quot;&gt;jbarratt&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;@dev:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/work/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Acme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;prove&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fakerun&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fakerun&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;n&quot;&gt;All&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tests&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;successful&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;n&quot;&gt;Files&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Tests&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wallclock&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;secs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.01&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;usr&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.03&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.00&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cusr&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.10&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;csys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;mf&quot;&gt;0.14&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CPU&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;n&quot;&gt;Result:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PASS&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Trust me, the normal code will still actually call the system&lt;/h3&gt;

&lt;p&gt;Just for fun, I threw in a &lt;a href=&quot;http://github.com/jbarratt/Acme-System/blob/master/bin/live&quot;&gt;script that actually uses this module to get live data&lt;/a&gt;:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;perl&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Acme::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Sum of all system PID&amp;#39;s: &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Acme::System::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pidsum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Current CPU user time: &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Acme::System::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vmstat_col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;us&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Current Free Mem: &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Acme::System::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vmstat_col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;free&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;And sure enough, if you run it, the data is getting updated live. &lt;code&gt;IPC::Run&lt;/code&gt; really is working on the live system.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;6&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;7&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;8&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;jbarratt@dev:~/work/Acme-System/lib$&lt;/span&gt; ../bin/live
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;Sum of all system PID&amp;#39;s: 367273&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;Current CPU user time: 0&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;Current Free Mem: 70448&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;jbarratt@dev:~/work/Acme-System/lib$&lt;/span&gt; ../bin/live
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;Sum of all system PID&amp;#39;s: 367291&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;Current CPU user time: 0&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;Current Free Mem: 70556&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Wrapping it all up&lt;/h2&gt;

&lt;p&gt;Other than the hackish trick to get &lt;code&gt;Data::Section&lt;/code&gt; working in what&amp;#8217;s not really a module, this code is really clean, readable, and easy to maintain. It works well for pretty much any module you might care to use instead of &lt;code&gt;IPC::Run&lt;/code&gt; &amp;#8211; there are lots of options, but as long as you use one of the module-ized ones, you can hook the module name and go from there.&lt;/p&gt;

&lt;p&gt;Especially if you write lots of sysadmin tools, and especially if they have costs or risks associated with running them (&lt;code&gt;fsck&lt;/code&gt;? &lt;code&gt;rm -rf&lt;/code&gt;?) this technique can be a lifesaver. It&amp;#8217;s only as good as the inputs you give it, though. I made a mistake the first time I figured this workflow out of grabbing an output which, in real life, ended up with more whitespace than I&amp;#8217;d accounted for, because the counters had gotten bigger between when I snagged my &amp;#8220;output to test with&amp;#8221; and when it was running on &amp;#8220;live output.&amp;#8221;&lt;/p&gt;

&lt;p&gt;I hope it helps, and if you have any suggestions about how to improve the technique, let me know (or send a pull request!)&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Up-Up-Updated &#8216;Inbox Zero with Mail.app&#8217; Technique</title>
    <link href="http://serialized.net/2010/09/up-up-updated-inbox-zero-with-mail-app-technique/"/>
    <updated>2010-09-06T00:00:00-07:00</updated>
    <id>http://serialized.net/2010/09/up-up-updated-inbox-zero-with-mail-app-technique</id>
    <content type="html">&lt;p&gt;In &lt;a href=&quot;http://serialized.net/2009/03/my-approach-to-inbox-zero-with-mailapp/&quot;&gt;March&lt;/a&gt; and &lt;a href=&quot;http://serialized.net/2009/12/updated-inbox-zero-with-mail-app-technique/&quot;&gt;December&lt;/a&gt; of 2009 I described how to do the &lt;a href=&quot;http://inboxzero.com/&quot;&gt;Inbox Zero&lt;/a&gt; method with Mac Mail, often known as &lt;code&gt;Mail.app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since publishing those articles I&amp;#8217;d been fed up with the performance of all the methods I&amp;#8217;d been using, and finally switched over to a true beast of a mail processing machine, &lt;a href=&quot;http://www.indev.ca/MailActOn.html&quot;&gt;Mail Act-On&lt;/a&gt;. The native plugin performance was great, and I was pretty happy with this solution.&lt;/p&gt;

&lt;p&gt;The only thing I wasn&amp;#8217;t happy with was that I was still only using the single feature &amp;#8211; the ability to, with a hotkey, move mail into an archive folder. And for this, I&amp;#8217;d happily paid.&lt;/p&gt;

&lt;p&gt;However, I was recently contacted by the developer of the perfect plugin for me &amp;#8211; &lt;a href=&quot;http://stl.techinno.nl/archive/&quot;&gt;Archive, a button for Apple Mail.&lt;/a&gt;. It does Archive and nothing else. It&amp;#8217;s a native plugin so it&amp;#8217;s fast, fast, fast. You don&amp;#8217;t have to jump through any of the hoops of Applescripting and Service menus and Quicksilver.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve been using it for a few weeks now and it&amp;#8217;s been perfect &amp;#8211; clean, simple, and exactly what I wanted all along.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://serialized.net/images/archive/screen.png&quot; alt=&quot;The new &#8216;Archive&#8217; feature&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s free, and you can download it from &lt;a href=&quot;http://stl.techinno.nl/archive/&quot;&gt;the author&amp;#8217;s site&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Why using packages makes sense in a configuration management world</title>
    <link href="http://serialized.net/2010/09/why-using-packages-makes-sense-in-a-configuration-management-world/"/>
    <updated>2010-09-01T00:00:00-07:00</updated>
    <id>http://serialized.net/2010/09/why-using-packages-makes-sense-in-a-configuration-management-world</id>
    <content type="html">&lt;p&gt;I woke up this morning to a discussion on twitter between two of my favorite internet people, &lt;a href=&quot;http://twitter.com/littleidea&quot;&gt;Andrew Shafer&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/ripienaar&quot;&gt;R.I. Pienaar&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Andrew I know from his previous job with Reductive (now &lt;a href=&quot;http://puppetlabs.com&quot;&gt;Puppet Labs&lt;/a&gt;) and I love what he has to say. (I really liked his &lt;a href=&quot;http://devopscafe.org/show/2010/7/19/episode-8.html&quot;&gt;DevOps Cafe episode&lt;/a&gt; &amp;#8211; in particular making me change my opinion about &amp;#8220;commitments&amp;#8221; in Agile contexts.)&lt;/p&gt;

&lt;p&gt;R.I. is a force of nature &amp;#8211; &lt;a href=&quot;http://www.devco.net/&quot;&gt;his blog&lt;/a&gt; is great, and full of years of hard-earned wisdom, and &lt;a href=&quot;http://marionette-collective.org/&quot;&gt;mcollective&lt;/a&gt; project is something I can&amp;#8217;t wait to roll out.&lt;/p&gt;

&lt;p&gt;The discussion centered around the question that I&amp;#8217;ll paraphrase:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;In the era of configuration management tools like Chef and Puppet, what value do packages provide? What are the pros and cons of packaging?&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&quot;http://twitter.com/ripienaar/status/22684759326&quot;&gt;&lt;img src=&quot;http://serialized.net/images/packages/ri_tweet.jpg&quot; alt=&quot;RI&#8217;s question&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://twitter.com/littleidea/status/22688039535&quot;&gt;&lt;img src=&quot;http://serialized.net/images/packages/littleidea_tweet.jpg&quot; alt=&quot;littleidea question&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It was clear that both of them were feeling the pinch of expressing themselves in 140 characters. It&amp;#8217;s a topic I&amp;#8217;m pretty passionate about, after 15+ years fighting to keep systems under control, so I figured I&amp;#8217;d write up my take on it.&lt;/p&gt;

&lt;h1&gt;Packages vs &lt;code&gt;wget &amp;amp;&amp;amp; tar&lt;/code&gt;&lt;/h1&gt;

&lt;p&gt;What are the pros and cons at the utility level?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(As dogma-free and objective as I can be, of course&amp;#8230;)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;The cost of building packages&lt;/h2&gt;

&lt;p&gt;Let&amp;#8217;s start with the only downside I can think of to having to build packages &amp;#8211; it&amp;#8217;s an extra step, and takes some time.&lt;/p&gt;

&lt;p&gt;Packaging your own code is easy &amp;#8211; you solve it once, and then have something like &lt;a href=&quot;http://hudson-ci.org/&quot;&gt;Hudson&lt;/a&gt; or &lt;a href=&quot;http://buildbot.net/trac&quot;&gt;BuildBot&lt;/a&gt; take it from there. However, packaging upstream code that&amp;#8217;s not in your distro is a pain in the butt. That&amp;#8217;s a given.&lt;/p&gt;

&lt;p&gt;Both of these get worse if (like me) you&amp;#8217;re stuck running multiple distributions. Right now we have to build &lt;code&gt;.rpm&lt;/code&gt;, &lt;code&gt;.deb&lt;/code&gt; and Solaris packages.&lt;/p&gt;

&lt;p&gt;Depending on what language you&amp;#8217;re using, there might be some tools that help package things the right way. For Debian+Perl, for example, &lt;a href=&quot;http://packages.debian.org/lenny/dh-make-perl&quot;&gt;dh-make-perl&lt;/a&gt; is getting to the point of being awesome and very usable.&lt;/p&gt;

&lt;p&gt;One way to get packages for upstream stuff that&amp;#8217;s not very painful is with a tool like &lt;a href=&quot;http://www.asic-linux.com.mx/~izto/checkinstall/&quot;&gt;CheckInstall&lt;/a&gt; &amp;#8211; you do the equivalent of a &lt;code&gt;make install&lt;/code&gt; one time in a sandbox, and that gives you a package you can install at will and get all the benefits I&amp;#8217;ll elaborate below.&lt;/p&gt;

&lt;p&gt;No matter what, it&amp;#8217;s an extra step.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://twitter.com/AshBerlin/status/22743329014&quot;&gt;@AshBerlin&lt;/a&gt; points out that, in the case that you&amp;#8217;re managing some upstream software, that this is a cost you have to take on for every version they release, not just a 1 time cost.&lt;/p&gt;

&lt;p&gt;There is no question that it&amp;#8217;s &amp;#8216;easier&amp;#8217; to do a &lt;code&gt;make install&lt;/code&gt; than to build a package (every time the software is updated) and get that installed.&lt;/p&gt;

&lt;p&gt;So here&amp;#8217;s why that&amp;#8217;s worth putting up with.&lt;/p&gt;

&lt;h2&gt;The value of building packages&lt;/h2&gt;

&lt;h3&gt;Redundant, Version-aware Repositories&lt;/h3&gt;

&lt;p&gt;What&amp;#8217;s can go wrong with code that looks like this? (Arbitrary link I happened to have in my &lt;code&gt;.bash_history&lt;/code&gt;)&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; wget http://yuilibrary.com/downloads/yuicompressor/yuicompressor-2.4.2.zip
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;ol&gt;
&lt;li&gt;What happens when the version changes? You have to update your configuration. This can be a good or bad thing, but in some cases you really want &lt;code&gt;$latest&lt;/code&gt; to be installed, rather than the hard-coded version someone supplied the last time they edited the configuration manifest.&lt;/li&gt;
&lt;li&gt;What happens when the yuilibrary folks change their (arbitrary) download URI&amp;#8217;s?&lt;/li&gt;
&lt;li&gt;What happens if &lt;a href=&quot;http://yuilibrary.com&quot;&gt;http://yuilibrary.com&lt;/a&gt; is down the next time you want to do a build?&lt;/li&gt;
&lt;li&gt;What if you want to be shipping &lt;code&gt;yuicompressor-2.4.1.zip&lt;/code&gt;? Is that still available for download?&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;When you want to install a package, the more reliable you can make the process, the better. Upgrading all the servers in a cluster? You want &lt;strong&gt;all&lt;/strong&gt; the servers to be upgraded. Trying to bring a new server online? You want to be able to do that with a very low probability of anything going wrong. (The more you can trust your deploys, especially in the age of automated infrastructure, it saves you money to be able to bring servers up as &amp;#8220;Just in Time&amp;#8221; as possible.)&lt;/p&gt;

&lt;p&gt;The &amp;#8220;repo&amp;#8221; model provided in at least the Red Hat and Debian packaging system handles all of these cases really, really well.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can provide a list of repositories that an attempt to install a package will try from until they find one working&lt;/li&gt;
&lt;li&gt;It&amp;#8217;s a trivial sysadmin task to have several repos with the same content available. Each one doesn&amp;#8217;t even have to be fancy and &amp;#8220;HA&amp;#8221;.&lt;/li&gt;
&lt;li&gt;It&amp;#8217;s 100% predictable (and an implementation detail you don&amp;#8217;t have to worry about) what will happen when you say you either want a specific version of a package, or the latest version.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Built-in &amp;#8220;tripwire&amp;#8221;-like functionality&lt;/h3&gt;

&lt;p&gt;Apt and Yum both keep checksums of all the files on the system installed by packages. So at any time you can ask &amp;#8220;have any files supposed to be managed by packages been modified&amp;#8221;?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://packages.debian.org/lenny/debsums&quot;&gt;debsums&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rpm -V -a&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pkgchk&lt;/code&gt; on Solaris (/via &lt;a href=&quot;http://twitter.com/builddoctor/status/22738104589&quot;&gt;@builddoctor&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;This is a useful thing to know for security reasons, of course. However, it&amp;#8217;s even more important for helping people adapt their behaviors.&lt;/p&gt;

&lt;p&gt;In an environment that&amp;#8217;s moving from &amp;#8220;not configuration managed&amp;#8221; to &amp;#8220;configuration managed&amp;#8221;, and the status quo has been &amp;#8220;modify the files on production servers&amp;#8221;, it&amp;#8217;s great to be able to get a nagios alert that one of the servers is now out of configuration, check the sums, and find out exactly what file(s) and when were modified.&lt;/p&gt;

&lt;p&gt;(If you couple that with a nice &amp;#8216;everyone logs in as their user and sudo&amp;#8217;s when needed&amp;#8217; policy, you can find out exactly who and when, as well.)&lt;/p&gt;

&lt;h3&gt;The package manager knows how files got on your system&lt;/h3&gt;

&lt;p&gt;Knowing what files got spewed into your system from your average &lt;code&gt;make install&lt;/code&gt; is pretty predictable, but certainly not always.&lt;/p&gt;

&lt;p&gt;This is useful for 2 cases:&lt;/p&gt;

&lt;h4&gt;Troubleshooting, and knowing where to make changes when you find the problem&lt;/h4&gt;

&lt;p&gt;The server keeps throwing 500 errors. Why? Ah, an untrapped exception in &lt;code&gt;/some/file/deep/on/the/system&lt;/code&gt;. Ok, I can fix that. Where do I need to go fix that? &lt;code&gt;dpkg -S &amp;lt;filename&amp;gt;&lt;/code&gt; tells me the exact package responsible for that file.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; dpkg -S /usr/bin/factor
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;    coreutils: /usr/bin/factor&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; dpkg -S /usr/bin/facter
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;    facter: /usr/bin/facter&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;That&amp;#8217;s one area in particular where configuration management systems can add an extra layer of value. R.I. actually wrote a tool that helps you discover which puppet module is responsible for configuring a given resource on the server. (&lt;a href=&quot;http://www.devco.net/code/parselocalconfig.rb&quot;&gt;localconfig.yaml parser&lt;/a&gt;) So if the answer is, rather than &amp;#8220;it&amp;#8217;s something shipped with a package&amp;#8221;, &amp;#8220;it&amp;#8217;s a config file that puppet wrote with your module called &lt;code&gt;my_module&lt;/code&gt;&amp;#8221;, you can easily find and fix it.&lt;/p&gt;

&lt;h4&gt;Uninstalling&lt;/h4&gt;

&lt;p&gt;I&amp;#8217;ve had some concrete problems from this, where I did an upgrade, and cruft left over from the previous version interfered with the new versions. For dynamic languages which build up large library trees, this can be particularly nasty, since default search paths might end up including remnants of an old version.&lt;/p&gt;

&lt;p&gt;When the package manager knows the location of every file, it can rip them out as happily as it put them in.&lt;/p&gt;

&lt;h3&gt;Dependencies are built in&lt;/h3&gt;

&lt;p&gt;At the level of configuration management, I really care about the application I&amp;#8217;m configuring.&lt;/p&gt;

&lt;p&gt;I want to run &lt;code&gt;lighttpd&lt;/code&gt;. I tell the configuration manager to install it. I don&amp;#8217;t want to have to do a research project to find all the supporting libraries required for it. Also, I really don&amp;#8217;t want to track down the &lt;code&gt;-dev&lt;/code&gt; versions of all of those libraries by hand.&lt;/p&gt;

&lt;p&gt;This is especially important for upgrades &amp;#8211; if an application starts using a new library after an upgrade (or depends on a newer version of a library when upgrading) that&amp;#8217;s all handled (and expressible) at the package layer.&lt;/p&gt;

&lt;h3&gt;Discovery of available updates are built in&lt;/h3&gt;

&lt;p&gt;This is one of the most compelling reasons.&lt;/p&gt;

&lt;p&gt;If you&amp;#8217;ve got a system with 9 tarball&amp;#8217;d packages,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What versions are currently installed?&lt;/li&gt;
&lt;li&gt;What software has updates available?&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;It&amp;#8217;s bad enough if you&amp;#8217;re installing software you know about, but I assume we&amp;#8217;re going to be using a distribution at some point.
You also REALLY want to know about updates your distribution is providing, right? Especially when it&amp;#8217;s things like critical kernel issues, openssl problems &amp;#8211; anything that can be remotely triggered, at the very least.&lt;/p&gt;

&lt;p&gt;Knowing what versions are available can be easily automated. You can use things like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.builderau.com.au/program/linux/soa/Automatically-update-your-Ubuntu-system-with-cron-apt/0,339028299,339279542,00.htm&quot;&gt;cron-apt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.cyberciti.biz/faq/fedora-automatic-update-retrieval-installation-with-cron/&quot;&gt;yumupdate&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;to handle this, and even do things like automatically install security patches if you&amp;#8217;d like.&lt;/p&gt;

&lt;p&gt;Since you need to solve this &amp;#8216;sysadmin problem&amp;#8217; at large anyway, why not leverage the tools and practices you build around this to learn about your own software, as well? It&amp;#8217;s just as valuable to know that there&amp;#8217;s a new build of &lt;code&gt;apache2&lt;/code&gt; available from the core Debian repo as it is to know that &lt;code&gt;our_custom_app&lt;/code&gt;, which we expected to be at version &lt;code&gt;2.6&lt;/code&gt; everywhere, is pinging because &lt;code&gt;host25&lt;/code&gt; is still running &lt;code&gt;2.5&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Cryptographic signatures are built in&lt;/h3&gt;

&lt;p&gt;Packages give you a way to trust that the bits you&amp;#8217;re about to install are the ones you should be installing.&lt;/p&gt;

&lt;p&gt;In this time of huge malware infestations, attempts to trojan even things like the linux kernel, and a large black market for &amp;#8220;owned boxes&amp;#8221;, you have every reason not to trust that the software you download isn&amp;#8217;t compromised in some way.&lt;/p&gt;

&lt;p&gt;Most places you can download tarballs also post checksums of what those files should be. There&amp;#8217;s two problems with this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you can&amp;#8217;t trust the place the download is hosted, why would you trust the sum?&lt;/li&gt;
&lt;li&gt;That adds a lot of complexity to the automated installer.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;You go from&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download the package&lt;/li&gt;
&lt;li&gt;Decompress, configure, make&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;To&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download the package&lt;/li&gt;
&lt;li&gt;Scrape for the latest checksums&lt;/li&gt;
&lt;li&gt;Verify the checksums&lt;/li&gt;
&lt;li&gt;THEN install the packages&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Packages solve both problems.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;They distribute a public key asynchronously from the hosting of the packages. Unless you are owned already, you can verify that a package was signed by the person who holds the matching private key.&lt;/li&gt;
&lt;li&gt;Checking signatures is built in. Your package install will fail if something goes wrong.&lt;/li&gt;
&lt;/ol&gt;


&lt;h3&gt;Binary-identical code on every server&lt;/h3&gt;

&lt;p&gt;There are lots of things that can go wrong when you try and build a package from source.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You may not have some development libraries you need. Great, now you&amp;#8217;re stuck managing those explicitly in configuration management as well. This also means that&lt;/li&gt;
&lt;li&gt;Every server has to have the full stack of software needed to be &lt;strong&gt;able&lt;/strong&gt; to build your software&lt;/li&gt;
&lt;li&gt;Compilation may fail, especially if the package was updated from the last time you tried to build it.&lt;/li&gt;
&lt;li&gt;Things that varied from build-to-build need to be accounted for when troubleshooting. &amp;#8220;Huh, &lt;code&gt;redis&lt;/code&gt; on &lt;code&gt;host25&lt;/code&gt; keeps crashing. Do we need to rebuild it?&amp;#8221;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;In general, it&amp;#8217;s very nice to be able to completely decouple the tasks of&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Creating&lt;/strong&gt; a &amp;#8216;build&amp;#8217; of your software and stack&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploying&lt;/strong&gt; a &amp;#8216;build&amp;#8217; of your software and stack&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Environment Support&lt;/h3&gt;

&lt;p&gt;One reason we like packages and repos is that it lets us define a configuration as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A set of &lt;strong&gt;which&lt;/strong&gt; packages&lt;/li&gt;
&lt;li&gt;A set of configurations of those packages&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Then when we&amp;#8217;re working in a topic or feature branch, we can create a repository just for that branch (this is also automated), and the repo configuration is the only thing that needs to be modified in the configuration management code.&lt;/p&gt;

&lt;p&gt;Also, because you only need a subset of all the packages you need in a repo, this lets us &amp;#8220;stack&amp;#8221; them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prefer my project repo (which only has my project-sensitive packages getting built into it, the stuff I&amp;#8217;m modifying)&lt;/li&gt;
&lt;li&gt;Fall back to the production repo for anything else you need&lt;/li&gt;
&lt;/ul&gt;


&lt;h1&gt;The End&lt;/h1&gt;

&lt;p&gt;Packages may add some pain and complexity up front to the install process, but they add a tremendous amount of value to the &amp;#8220;lifecycle management&amp;#8221; of your applications. Most of the hell we go through as people running servers doesn&amp;#8217;t happen the first month we set them up, it&amp;#8217;s month 6, 18, and 24 that are the real problem. And those problems (&amp;#8220;servers are graveyards of state&amp;#8221;, etc) that make Configuration Management the right thing to do in the first place.&lt;/p&gt;

&lt;p&gt;Use them. Love them.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Deploying self-contained Perl Dancer applications</title>
    <link href="http://serialized.net/2010/08/deploying-self-contained-perl-dancer-applications/"/>
    <updated>2010-08-30T00:00:00-07:00</updated>
    <id>http://serialized.net/2010/08/deploying-self-contained-perl-dancer-applications</id>
    <content type="html">&lt;p&gt;I&amp;#8217;m really enjoying using Perl&amp;#8217;s &lt;a href=&quot;http://perldancer.org&quot;&gt;Dancer&lt;/a&gt; for building lightweight web applications. It&amp;#8217;s heavily inspired by Ruby&amp;#8217;s &lt;a href=&quot;http://sinatrarb.com&quot;&gt;Sinatra&lt;/a&gt; framework, but clearly Perlish.&lt;/p&gt;

&lt;p&gt;The only thing I&amp;#8217;ve been bothered by so far is getting my applications from my development environment out to production. It&amp;#8217;s pretty easy to actually &lt;a href=&quot;http://search.cpan.org/dist/Dancer/lib/Dancer/Deployment.pod&quot;&gt;do deployments&lt;/a&gt; in terms of actually getting your app up and handling web requests, but shipping the software to the remote system has always bothered me.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: I wanted to clarify that Dancer itself is very lightweight and has as close to zero dependencies as is reasonable to have.&lt;/p&gt;

&lt;p&gt;However, the Dancer apps that I&amp;#8217;ve been building tend to require a lot of pretty fresh CPAN goodness. (&lt;a href=&quot;http://search.cpan.org/dist/Task::Plack/&quot;&gt;Task::Plack&lt;/a&gt;, &lt;a href=&quot;http://search.cpan.org/dist/Moose/&quot;&gt;Moose&lt;/a&gt;, &lt;a href=&quot;http://search.cpan.org/dist/DBIx::Class/&quot;&gt;DBIx::Class&lt;/a&gt;, &lt;a href=&quot;http://search.cpan.org/dist/AnyEvent/&quot;&gt;AnyEvent&lt;/a&gt;, and more.) This is a problem if you&amp;#8217;re trying to avoid using CPAN as root to just install system packages, which I like to avoid &amp;#8211; it makes systems harder to define with something like &lt;a href=&quot;http://puppetlabs.com/&quot;&gt;Puppet&lt;/a&gt;, and can cause weird interaction problems between multiple applications running on the same machine when they use the same modules.&lt;/p&gt;

&lt;p&gt;Dancer builds you a nice starter application container when you run &lt;code&gt;dancer -a&lt;/code&gt; &amp;#8211; it&amp;#8217;s made to look like a Perl module, with a &lt;code&gt;Makefile.PL&lt;/code&gt; and everything. This initially excited me, because I could just turn it into a debian package it with something like &lt;code&gt;dh-make-perl&lt;/code&gt;. Here&amp;#8217;s the problem &amp;#8211; when you &lt;code&gt;perl Makefile.PL &amp;amp;&amp;amp; make dist&lt;/code&gt; none of your non-perl-module assets make the trip. I&amp;#8217;m not really interested in deploying applications that don&amp;#8217;t have templates, CSS, Javascript, or images.&lt;/p&gt;

&lt;p&gt;From what I can tell in the docs and on IRC, most people solve this by just checking out their application from their version control system on the production box.&lt;/p&gt;

&lt;p&gt;This is more or less this idea:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://serialized.net/images/shipwright/cpan_to_build.png&quot; alt=&quot;installing an app&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you&amp;#8217;re like me, and living life with hundreds or thousands of servers, that approach doesn&amp;#8217;t really work. It also doesn&amp;#8217;t solve the first problem above of how to handle all the dependencies (or dependency clashes on a single machine.)&lt;/p&gt;

&lt;p&gt;If you&amp;#8217;re running lots of servers, you&amp;#8217;ll end up with this problem. You install your first app on a single box or two, and it&amp;#8217;s running along fine. Then the people come, and you need more horsepower. Time to build a new box.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://serialized.net/images/shipwright/new_server.png&quot; alt=&quot;adding a new server&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Oops! &lt;code&gt;DBIx::Class&lt;/code&gt; isn&amp;#8217;t passing tests right now. I guess we can&amp;#8217;t deploy a new server. Or, more subtly, everything installs, but when you add your app to the load balancer, something is &amp;#8220;wacky&amp;#8221; one 1/2 of the web requests. Pleh.&lt;/p&gt;

&lt;p&gt;You &lt;strong&gt;really&lt;/strong&gt; don&amp;#8217;t want to be in that trap if you&amp;#8217;re trying to auto-scale your app on, say, EC2.&lt;/p&gt;

&lt;p&gt;Ok, so we don&amp;#8217;t want to install from CPAN on the fly.&lt;/p&gt;

&lt;p&gt;I really like &lt;a href=&quot;http://blogs.perl.org/users/brian_d_foy/&quot;&gt;brian d foy&lt;/a&gt;, and he&amp;#8217;s got a strategy to handle this problem: &lt;a href=&quot;http://search.cpan.org/~rjbs/CPAN-Mini-1.100630/bin/minicpan&quot;&gt;run your own CPAN!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is actually a pretty good idea, and in some environments, I&amp;#8217;d be using it right now.&lt;/p&gt;

&lt;p&gt;That turns the model to this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://serialized.net/images/shipwright/build_from_minicpan.png&quot; alt=&quot;building from minicpan&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We have our own &lt;code&gt;minicpan&lt;/code&gt; to use to buffer the volatility of the &lt;code&gt;CPAN&lt;/code&gt;. Upgrades can happen to &lt;code&gt;minicpan&lt;/code&gt; when we want and need them to. If the &lt;code&gt;minicpan&lt;/code&gt; didn&amp;#8217;t change, we can install our application on as many servers as we want, and trust they&amp;#8217;ll be getting the same code.&lt;/p&gt;

&lt;p&gt;There&amp;#8217;s still a big problem with this: what if you have multiple apps that have different dependencies?
You can&amp;#8217;t use CPAN&amp;#8217;s &amp;#8220;new hotness&amp;#8221; for one simple app that could really use from it, without worrying about if all your other applications will be able to work with all that new code. So we&amp;#8217;ve given ourselves the ability to add a &amp;#8216;buffer&amp;#8217; between our usage and CPAN&amp;#8217;s potential volatility, but we haven&amp;#8217;t bought much independence for our applications.&lt;/p&gt;

&lt;p&gt;Brian&amp;#8217;s started &lt;a href=&quot;http://blogs.perl.org/users/brian_d_foy/2010/03/manage-multiple-minicpans-and-version-them.html&quot;&gt;working on extending minicpan&lt;/a&gt; to handle multiple minicpan&amp;#8217;s.&lt;/p&gt;

&lt;p&gt;However, there is another approach, which brings some other nice features as well.&lt;/p&gt;

&lt;p&gt;Enter &lt;a href=&quot;http://search.cpan.org/searchcpanmodule=Shipwright&quot;&gt;Shipwright&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Shipwright lets you keep a local, version-controlled copy of all the source (from CPAN or otherwise) that your application needs. It keeps the information about where all that source &amp;#8220;came from&amp;#8221;, be it CPAN or a local file, so you can keep it as up to date as you want to, and when you want to. It nicely decouples the &amp;#8220;application building and packaging&amp;#8221; problem (&amp;#8220;make me a new package&amp;#8221;) from the &amp;#8220;application maintenance&amp;#8221; problem (&amp;#8220;update some components.&amp;#8221;)&lt;/p&gt;

&lt;p&gt;So now we&amp;#8217;ve got a version controlled &amp;#8220;CPAN Cache&amp;#8221; per application we&amp;#8217;re managing.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://serialized.net/images/shipwright/build_with_shipwright.png&quot; alt=&quot;building with shipwright&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The other things I really like about Shipwright are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It doesn&amp;#8217;t just handle the CPAN problem &amp;#8211; it also makes your code into a little self-contained unit which can be dropped into any directory on the target system.&lt;/li&gt;
&lt;li&gt;You can tweak any module&amp;#8217;s &amp;#8220;build process&amp;#8221;. (As I take advantage of below.) If the CPAN installer doesn&amp;#8217;t work the way you want or need, you can do some pre/post-install hacking. Again &amp;#8211; in a nice, version controlled and repeatable way.&lt;/li&gt;
&lt;li&gt;You can ship &lt;code&gt;autoconf&lt;/code&gt; style applications along with it. Want to also deploy a patched version of &lt;code&gt;nginx&lt;/code&gt;, or a &lt;code&gt;redis&lt;/code&gt; server? You can do that here. (I wouldn&amp;#8217;t, but you can.)&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;Essentially, all I&amp;#8217;m saying is &amp;#8220;use shipwright&amp;#8221; &amp;#8211; but there are a few tricks to make it work for Dancer applications.&lt;/p&gt;

&lt;h3&gt;MANIFEST&lt;/h3&gt;

&lt;p&gt;First, you&amp;#8217;ll need to make sure all the files you care about in your Dancer app are going to be included at all. This means getting them in the MANIFEST file. I just did a simple &lt;code&gt;find . -type f &amp;gt; MANIFEST&lt;/code&gt; and cleaned out the entries I didn&amp;#8217;t need or already had. If you&amp;#8217;re doing this a lot, or modifying the file contents of your applications a lot, I&amp;#8217;m sure there&amp;#8217;s a more elegant approach.&lt;/p&gt;

&lt;h3&gt;shipwright &lt;code&gt;build&lt;/code&gt; file&lt;/h3&gt;

&lt;p&gt;One of the nice things about shipwright is that it allows you to tune up a build script for everything you&amp;#8217;re installing.&lt;/p&gt;

&lt;p&gt;Even though the Dancer packages now contain all your files, they still don&amp;#8217;t know where to get installed.&lt;/p&gt;

&lt;p&gt;Normally the &lt;code&gt;scripts/MyApp/build&lt;/code&gt; contents look like this:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;basemake&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nf&quot;&gt;install&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;%%MAKE%% install&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;If we add a simple extra step, that gives us a copy of all the module&amp;#8217;s assets rooted off our package&amp;#8217;s &amp;#8216;/www&amp;#8217; path.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;basemake&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nf&quot;&gt;install&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;%%MAKE%% install ; cp -av . %%INSTALL_BASE%%/www&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h1&gt;Walkthrough&lt;/h1&gt;

&lt;p&gt;First, you&amp;#8217;ll need to install Shipwright. I am in love with the mighty combination of &lt;a href=&quot;http://search.cpan.org/search?query=local::lib&quot;&gt;local::lib&lt;/a&gt; and &lt;a href=&quot;http://github.com/miyagawa/cpanminus&quot;&gt;cpanm&lt;/a&gt;, so I&amp;#8217;d recommend starting there.&lt;/p&gt;

&lt;h2&gt;Build your Dancer app&lt;/h2&gt;

&lt;p&gt;Once you&amp;#8217;ve fixed the MANIFEST file as described above, you need to build a distribution of your Dancer app.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ../MyApp
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; perl Makefile.PL
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; make dist
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Prepare the &amp;#8216;vessel&amp;#8217;&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;m going to be doing all the work in a directory called &lt;code&gt;~/home/work/shipwright&lt;/code&gt;.
I&amp;#8217;m also using the &lt;code&gt;git&lt;/code&gt; shipwright backend here &amp;#8211; it works with svn, plain filesystem, and other options as well.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; you might need to mkdir -p &lt;span class=&quot;s2&quot;&gt;&amp;quot;$HOME/work/shipwright/&amp;quot;&lt;/span&gt; first.
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;APPNAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;MyApp&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SHIPWRIGHT_SHIPYARD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;git:file:///$HOME/work/shipwright/$APPNAME-vessel.git&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; shipwright create
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Ok, now you&amp;#8217;ve got the vessel. It&amp;#8217;s time to load it full of CPAN&amp;#8217;y goodness.
Since this is a tutorial for Dancer, I&amp;#8217;ll include some of the basics I like to have when deploying Dancer apps.&lt;/p&gt;

&lt;h2&gt;Fill the vessel with software&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;m using &lt;code&gt;&#8211;no-follow&lt;/code&gt; here because I had some errors trying to follow dependencies on my internal applications that I also install via distribution file. If you&amp;#8217;re only loading CPAN modules from your Dancer app, you can take this off.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;6&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;7&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;8&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;9&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;10&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;11&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;12&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;13&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;14&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;15&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; shipwright import cpan:Template cpan:Dancer cpan:YAML::XS cpan:Task::Plack
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; put the full path, and right version number of, the file here
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; shipwright import file:~/work/&lt;span class=&quot;nv&quot;&gt;$APPNAME&lt;/span&gt;/&lt;span class=&quot;nv&quot;&gt;$APPNAME&lt;/span&gt;-0.004.tar.gz &#8211;no-follow
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; REPEAT importing &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;any of your other in-house modules/code
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~/work/shipwright
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; git clone &lt;span class=&quot;nv&quot;&gt;$APPNAME&lt;/span&gt;-vessel.git
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$APPNAME&lt;/span&gt;-vessel
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; vi scripts/&lt;span class=&quot;nv&quot;&gt;$APPNAME&lt;/span&gt;/build
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; change the install line from:
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt;       install: %%MAKE%% install
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; to
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt;       install: %%MAKE%% install ; cp -av . %%INSTALL_BASE%%/www
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; git add scripts/&lt;span class=&quot;nv&quot;&gt;$APPNAME&lt;/span&gt;/build
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; git commit -m &lt;span class=&quot;s2&quot;&gt;&amp;quot;tweaked build script for $APPNAME&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; git push origin master
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Build the vessel&lt;/h2&gt;

&lt;p&gt;Cool. Now we&amp;#8217;ve got a self-contained, versioned repository. Time to build it.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./bin/shipwright-builder &#8211;install-base ~/work/shipwright/&lt;span class=&quot;nv&quot;&gt;$APPNAME&lt;/span&gt; &#8211;force
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;The &lt;code&gt;&#8211;force&lt;/code&gt; is because some modules don&amp;#8217;t pass tests. Shipwright does have a ways to go with dependency management (or I&amp;#8217;m doing something wrong) &amp;#8211; if I&amp;#8217;ve install a module into the &amp;#8216;vessel&amp;#8217;, sometimes other modules that depend on it can&amp;#8217;t use it at build/test time.&lt;/p&gt;

&lt;p&gt;Now you&amp;#8217;ve got a directory (&lt;code&gt;~/work/shipwright/$APPNAME&lt;/code&gt;) which can be deployed repeatably on your servers. You can wrap it up in a Debian or Red Hat package if you&amp;#8217;d like, tar it, rsync it, BitTorrent it &amp;#8211; up to you.&lt;/p&gt;

&lt;h2&gt;Maintaining the Vessel&lt;/h2&gt;

&lt;p&gt;When you build a new version of your Dancer app, all you have to do is update the vessel, then build.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; shipwright relocate &lt;span class=&quot;nv&quot;&gt;$APPNAME&lt;/span&gt; file:~/&#8230;.new.tar.gz
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; shipwright update &lt;span class=&quot;nv&quot;&gt;$APPNAME&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$APPNAME&lt;/span&gt;-vessel
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; git pull
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; rm -rf ~/work/shipwright/&lt;span class=&quot;nv&quot;&gt;$APPNAME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./bin/shipwright-builder &#8211;install-base ~/work/shipwright/&lt;span class=&quot;nv&quot;&gt;$APPNAME&lt;/span&gt; &#8211;force
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Using the Vessel&lt;/h2&gt;

&lt;p&gt;Shipwright has some nice features to set up all the environment variables needed so you can use your app. All you have to do is source the appropriate script, like so:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;up your environment so the &lt;span class=&quot;s1&quot;&gt;&amp;#39;$APPNAME&amp;#39;&lt;/span&gt; libraries and binaries are in your path
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; . /opt/yourstuff/&lt;span class=&quot;nv&quot;&gt;$APPNAME&lt;/span&gt;/tools/shipwright-source-bash /opt/yourstuff/&lt;span class=&quot;nv&quot;&gt;$APPNAME&lt;/span&gt;/
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;What&amp;#8217;s cool is you can do the same thing from SYSV-style &lt;code&gt;init&lt;/code&gt; scripts. Let&amp;#8217;s say you&amp;#8217;re launching this as a &lt;code&gt;fastcgi&lt;/code&gt; application.
Your startup script can look like this example. The magic line is &lt;code&gt;source $APP_BASE&#8230;&lt;/code&gt; which uses the shipwright shell config to set the variables used by the rest of the script.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;6&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;7&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;8&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;9&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;10&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;11&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;12&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;13&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;14&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;15&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;16&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;17&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;18&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;19&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;20&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;21&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;22&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;23&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;24&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;25&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;26&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;27&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;28&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;29&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;30&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;31&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;32&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;33&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;34&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;35&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;36&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;37&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;38&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;39&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;40&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;41&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;42&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;43&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;44&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;45&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;46&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;47&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;48&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;49&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;50&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;51&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;52&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;53&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;54&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;55&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;56&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;57&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;58&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;59&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;60&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;61&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;62&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;63&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;64&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;65&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;66&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;67&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;68&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;69&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;70&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;71&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;72&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;73&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;74&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;75&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;76&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;77&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;78&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;79&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;80&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;81&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;82&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;83&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;84&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;85&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;86&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;87&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;88&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;89&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;90&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;91&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;92&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;93&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;94&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;95&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;96&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;97&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;98&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;99&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;100&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;101&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;102&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;103&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;sh&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nv&quot;&gt;NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$APPNAME&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nv&quot;&gt;APP_BASE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/opt/mt/$NAME&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nb&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$APP_BASE&lt;/span&gt;/tools/shipwright-source-bash &lt;span class=&quot;nv&quot;&gt;$APP_BASE&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nv&quot;&gt;APP_BIN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$APP_BASE/bin&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nv&quot;&gt;APP_WWW&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$APP_BASE/www&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nv&quot;&gt;APP_PSGI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$APP_WWW/app.psgi&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nv&quot;&gt;FCGI_LISTEN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;127.0.0.1:55900
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nv&quot;&gt;DAEMON&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$APP_BIN/plackup&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;c&quot;&gt;# Defaults&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;c&quot;&gt;#RUN=&amp;quot;no&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nv&quot;&gt;OPTIONS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;-s FCGI &#8211;listen $FCGI_LISTEN -E production &#8211;app $APP_PSGI&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nv&quot;&gt;PIDFILE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$NAME.pid&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; -f /lib/lsb/init-functions &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; . /lib/lsb/init-functions
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;start&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    log_daemon_msg &lt;span class=&quot;s2&quot;&gt;&amp;quot;Starting plack server&amp;quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$NAME&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    start-stop-daemon -b -m &#8211;start &#8211;quiet &#8211;pidfile &lt;span class=&quot;s2&quot;&gt;&amp;quot;$PIDFILE&amp;quot;&lt;/span&gt; &#8211;exec &lt;span class=&quot;nv&quot;&gt;$DAEMON&lt;/span&gt; &#8211; &lt;span class=&quot;nv&quot;&gt;$OPTIONS&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt; !&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;        &lt;/span&gt;log_end_msg 1
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;        &lt;/span&gt;log_end_msg 0
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;signal&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$1&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;stop&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SIGNAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;TERM&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        log_daemon_msg &lt;span class=&quot;s2&quot;&gt;&amp;quot;Stopping plack server&amp;quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$NAME&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;    if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$1&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;reload&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SIGNAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;HUP&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;            log_daemon_msg &lt;span class=&quot;s2&quot;&gt;&amp;quot;Reloading plack server&amp;quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$NAME&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;ERR: wrong parameter given to signal()&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;    fi&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;    if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; -f &lt;span class=&quot;s2&quot;&gt;&amp;quot;$PIDFILE&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;        &lt;/span&gt;start-stop-daemon &#8211;stop &#8211;signal &lt;span class=&quot;nv&quot;&gt;$SIGNAL&lt;/span&gt; &#8211;quiet &#8211;pidfile &lt;span class=&quot;s2&quot;&gt;&amp;quot;$PIDFILE&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;     &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;            &lt;/span&gt;log_end_msg 0
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SIGNAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;KILL&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        start-stop-daemon &#8211;stop &#8211;signal &lt;span class=&quot;nv&quot;&gt;$SIGNAL&lt;/span&gt; &#8211;quiet &#8211;pidfile &lt;span class=&quot;s2&quot;&gt;&amp;quot;$PIDFILE&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt; !&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;                &lt;/span&gt;log_end_msg 1
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;                &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$2&lt;/span&gt; !&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;0
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;            &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;            &lt;/span&gt;rm &lt;span class=&quot;s2&quot;&gt;&amp;quot;$PIDFILE&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;                log_end_msg 0
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;            &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;        fi&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;    if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$SIGNAL&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;KILL&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;        &lt;/span&gt;rm -f &lt;span class=&quot;s2&quot;&gt;&amp;quot;$PIDFILE&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;    else&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;        &lt;/span&gt;log_end_msg 0
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$1&amp;quot;&lt;/span&gt; in
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    start&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    start
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    ;;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    force-start&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    start
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    ;;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    stop&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        signal stop 0
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    ;;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    force-stop&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    signal stop 0
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    ;;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    reload&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    signal reload 0
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    ;;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    force-reload|restart&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    signal stop 1
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    sleep 2
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    start
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    ;;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    *&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Usage: /etc/init.d/$NAME {start|force-start|stop|force-stop|reload|restart|force-reload}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    ;;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;esac&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Dancer is great. Shipwright is great. CPAN is great, but I want a buffer from all that awesomeness.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Relaunched blog, sorry for any dust.</title>
    <link href="http://serialized.net/2010/08/relaunched-blog-sorry-for-any-dust/"/>
    <updated>2010-08-29T00:00:00-07:00</updated>
    <id>http://serialized.net/2010/08/relaunched-blog-sorry-for-any-dust</id>
    <content type="html">&lt;p&gt;I&amp;#8217;ve migrated my site from &lt;a href=&quot;http://wordpress.org&quot;&gt;WordPress&lt;/a&gt; to &lt;a href=&quot;http://wiki.github.com/mojombo/jekyll/&quot;&gt;Jekyll&lt;/a&gt;.
You can see where the donuts are made in the &lt;a href=&quot;http://github.com/jbarratt/serialized.net&quot;&gt;source&lt;/a&gt;.
This is a much more programmer-y way to blog, including very nice baked in server-side syntax highlighting.&lt;/p&gt;

&lt;p&gt;I apologize if your feed reader gets my entire posting history back, I&amp;#8217;ve got a few nice articles in draft that I hope to get up soon so it should be worth staying subscribed.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Notes from my Jekyll Migration</title>
    <link href="http://serialized.net/2010/08/notes-from-my-jekyll-migration/"/>
    <updated>2010-08-29T00:00:00-07:00</updated>
    <id>http://serialized.net/2010/08/notes-from-my-jekyll-migration</id>
    <content type="html">&lt;p&gt;I had a few snags moving to Jekyll that I thought worth sharing.&lt;/p&gt;

&lt;h3&gt;Lenny Support Packages&lt;/h3&gt;

&lt;p&gt;If you&amp;#8217;re using Debian Lenny, you won&amp;#8217;t complain about having these packages installed:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;  sudo apt-get install ruby-dev  libyaml-ruby libzlib-ruby python-pygments libgsl-ruby1.8 sun-java6-jre
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Local install of Gems&lt;/h3&gt;

&lt;p&gt;I didn&amp;#8217;t want to mess with my system gems, and wanted to have the gems installed in my local directory like I&amp;#8217;m used to with Perl&amp;#8217;s &lt;a href=&quot;search.cpan.org/perldoc?local::lib&quot;&gt;local::lib&lt;/a&gt;.
This turned out to be harder than you may think. Here&amp;#8217;s the environment incantation that did the trick:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;bash&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;RUBY_PREFIX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$HOME/.ruby&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$RUBY_PREFIX/bin/:$RUBY_PREFIX/lib/ruby/gems/1.8/bin/:$PATH&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;GEM_HOME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$RUBY_PREFIX/lib/ruby/gems/1.8&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;GEM_PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$GEM_HOME&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;RUBYLIB&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$RUBY_PREFIX/lib/ruby:$RUBY_PREFIX/lib:$RUBY_PREFIX/lib/site_ruby/1.8&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;And then I grabbed &lt;a href=&quot;http://rubyforge.org/frs/?group_id=126&quot;&gt;RubyGems&lt;/a&gt; and just&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ruby setup.rb all &#8211;prefix&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$RUBY_PREFIX&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Importing Wordpress&lt;/h3&gt;

&lt;p&gt;I also wanted to use a remote database that I didn&amp;#8217;t have direct network access to.
Step 1, use &lt;code&gt;ssh&lt;/code&gt; to create a nice tunnel (to the arbitrary local port 11122):&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ssh -L 11122:host.of.database.com:3306 user@domain.com
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;I needed to tweak the importer tool that ships with Jekyll to support using a host and port:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;ruby&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dbname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;127.0.0.1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;11122&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Sequel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mysql&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dbname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:password&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:port&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;There was a whole lot of hideous perl going on to slap around my posts once they were imported since the post bodies were in a strange combination of raw HTML, textile, and other legacy markup fragments. Things seem fairly solid at this point.&lt;/p&gt;

&lt;h3&gt;Optimizing CSS&lt;/h3&gt;

&lt;p&gt;I&amp;#8217;m using some CSS magic from the inspirational &lt;a href=&quot;http://oocss.org/&quot;&gt;OOCSS project&lt;/a&gt;, and that style leaves you with lots of individual files. My &lt;a href=&quot;http://github.com/jbarratt/serialized.net/blob/master/Rakefile&quot;&gt;Rakefile&lt;/a&gt; is mostly snaked from people like &lt;a href=&quot;http://github.com/avdgaag/arjanvandergaag.nl/blob/master/Rakefile&quot;&gt;avdgaag&lt;/a&gt;, but I added in a useful CSS optimization section.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;ruby&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;style/merged.css&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;style/syntax.css&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;style/template.css&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;style/libraries.css&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;style/grids.css&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;style/content.css&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;style/mod.css&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;n&quot;&gt;sh&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;cat &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prerequisites&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &amp;gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.devel&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;n&quot;&gt;sh&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;java -jar ~/.java/yuicompressor-2.4.2.jar &#8211;type css -o style/merged.css &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.devel&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;I&amp;#8217;ve had to elaborate files by name so they end up in the correct order (one of the least fun things about CSS, aside from &amp;#8216;everything else&amp;#8217;, is that order matters). So you do have to update the list by hand when adding files, but most of the time I&amp;#8217;m sure you&amp;#8217;ll tend to tweak them instead. I&amp;#8217;m using Yahoo&amp;#8217;s &lt;a href=&quot;http://developer.yahoo.com/yui/compressor/&quot;&gt;YUI Compressor&lt;/a&gt; which is nice, since if my Javascript gets more complex I can use it for that as well.&lt;/p&gt;

&lt;p&gt;For now it shrinks the payload from 14k to 8k, not worth doing super backflips over &amp;#8211; the majority of the gain is in the simple concatenation, turning 6+ HTTP GET&amp;#8217;s into a single one.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Capturing short-lived programs on Linux</title>
    <link href="http://serialized.net/2010/06/capturing-short-lived-programs-on-linux/"/>
    <updated>2010-06-14T00:00:00-07:00</updated>
    <id>http://serialized.net/2010/06/capturing-short-lived-programs-on-linux</id>
    <content type="html">&lt;p&gt;One of the things I love most about DTrace is your &lt;a href=&quot;http://www.brendangregg.com/DTrace/shortlived.d&quot;&gt;ability to do things like this.&lt;/a&gt; Because you can ask the kernel to let you start tracking when something cool happens (like forking a new program), you can instrument it.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;text&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;// Measure parent fork time
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;syscall::*fork*:entry { /* save start of fork */
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;  self-&amp;gt;fork = vtimestamp;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Sadly, those tools aren&amp;#8217;t available on a standard issue Linux machine. (You can do it with &lt;a href=&quot;http://sourceware.org/systemtap/wiki/systemtapstarters&quot;&gt;SystemTap&lt;/a&gt;, but it&amp;#8217;s not on every server I end up looking at.) Today I was trying to track down some processes that were making very odd DNS lookups. I isolated the user ID making these calls via iptables logging:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;text&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;iptables -I OUTPUT 1 -m string &#8211;string &amp;quot;BADZONE&amp;quot; -d 127.0.0.1 -p udp &#8211;destination-port 53 &#8211;algo bm -j LOG &#8211;log-uid &#8211;log-prefix &amp;quot;BADZONE: &amp;quot;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;But this user&amp;#8217;s PHP scripts were getting launched and dying again quickly. How to find out what was going on inside them? This hacky little trick actually worked really well. You can download it from &lt;a href=&quot;http://axis.serialized.net/gitweb/?p=utilities.git;a=blob_plain;f=auto_stracer;hb=HEAD&quot;&gt;my git utilities directory.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Basically, we check the process list as fast as we can for any owned by that user; If you find one, stick an strace on it. The script will &amp;#8216;hang around&amp;#8217; until all the strace processes have finished. You end up with a directory full of trace files which you can then post-grep through to get what you need.&lt;/p&gt;

&lt;p&gt;The short version is I was able to catch one of that user&amp;#8217;s programs doing the odd behaviour within about 30 seconds of running this tool, which was great!&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;6&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;7&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;8&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;9&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;10&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;11&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;12&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;13&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;14&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;15&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;16&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;17&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;18&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;19&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;20&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;21&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;22&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;23&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;24&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;25&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;26&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;27&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;28&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;29&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;30&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;31&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;32&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;33&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;34&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;35&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;36&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;37&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;38&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;39&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;40&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;41&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;42&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;43&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;44&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;45&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;46&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;47&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;48&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;49&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;50&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;51&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;52&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;53&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;54&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;55&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;56&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;57&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;perl&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;c1&quot;&gt;#!/usr/bin/perl&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;warnings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Getopt::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$opt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;n&quot;&gt;GetOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$opt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;uid=i&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;number=i&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;help&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;man&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$opt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;help&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$opt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;man&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;defined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$opt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Usage: auto_stracer &#8211;number &amp;lt;processes to capture&amp;gt; &#8211;uid &amp;lt;numeric uid&amp;gt;\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nv&quot;&gt;$opt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$traced&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%seen&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;@pids&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%ourpid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nv&quot;&gt;$ourpid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;vg&quot;&gt;$$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nv&quot;&gt;$SIG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sub &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;kill&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;@pids&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Interrupt: Killed all running strace processes and quitting.\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;};&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$traced&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$opt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/\n/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`ps -Ao &amp;#39;uid,pid&amp;#39;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;s/^\s+//g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# eat leading spaces&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$uid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/\s+/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;k&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ourpid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# don&amp;#39;t run on something we are tracking&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$pid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$uid&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$opt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$seen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;            &lt;span class=&quot;nv&quot;&gt;$seen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;            &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$st_pid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;do_strace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;            &lt;span class=&quot;nv&quot;&gt;$ourpid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$st_pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;            &lt;span class=&quot;nb&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;@pids&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$st_pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;            &lt;span class=&quot;nv&quot;&gt;$traced&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;            &lt;span class=&quot;k&quot;&gt;last&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$traced&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$opt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Traced $opt-&amp;gt;{number}, waiting for all to finish\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$kid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;      &lt;span class=&quot;nv&quot;&gt;$kid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;waitpid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$kid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;All processes completed, exiting.\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;sub &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;do_strace&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;@_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ourpid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;fork&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ourpid&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ourpid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$cmd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;strace -p $pid -f -s 65535 -o trace.$pid.$$ -v&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;\tcmd: $cmd\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;nb&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$cmd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;So, very brute force compared to the elegance of systemtap or DTrace, but when you need it, it&amp;#8217;s still handy.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Instantly share local directories with 2 command lines</title>
    <link href="http://serialized.net/2010/06/instantly-share-local-directories-with-2-command-lines/"/>
    <updated>2010-06-11T00:00:00-07:00</updated>
    <id>http://serialized.net/2010/06/instantly-share-local-directories-with-2-command-lines</id>
    <content type="html">&lt;p&gt;Just came across this useful trick to let anyone browse/download directories you want to share in seconds.&lt;/p&gt;

&lt;p&gt;All you need is a Mac or Linux machine you are logged into, and ssh access to a server on the internet. It uses &lt;a href=&quot;http://www.lylebackenroth.com/blog/2009/05/03/serve-your-current-directory-using-a-simple-webserver-python/&quot;&gt;this trick&lt;/a&gt; I just saw the other day.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python -m SimpleHTTPServer &amp;amp;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ssh -R 8080:localhost:8000 my.remote.host
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Now someone can go to http://my.remote.host:8080/ and be browsing your local directory. Rad. And you see the access that&amp;#8217;s happening come up in your screen &amp;#8211; SimpleHTTPServer spits it out to you.&lt;/p&gt;

&lt;p&gt;When they&amp;#8217;ve got what they need, just&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;my.remote.host$ exit&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;fg&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;# Brings python back, CTRL-C to exit&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Sharing over, nice and securely back to normal.&lt;/p&gt;

&lt;p&gt;If this isn&amp;#8217;t working, the most common reason is that on the remote server, you do need the &amp;#8216;GatewayPorts&amp;#8217; set to &amp;#8216;yes&amp;#8217;  in your server&amp;#8217;s /etc/ssh/sshd_config for this to work. (And you&amp;#8217;ll need to restart sshd after you make that change.)&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Optimal web-sized identifiers</title>
    <link href="http://serialized.net/2010/05/optimal-web-sized-identifiers/"/>
    <updated>2010-05-14T00:00:00-07:00</updated>
    <id>http://serialized.net/2010/05/optimal-web-sized-identifiers</id>
    <content type="html">&lt;p&gt;As part of a project I&amp;#8217;m working on for fun (shhhh) I&amp;#8217;ve been trying to solve an interesting problem &amp;#8211; what is the most compact way I can uniquely refer to something in a URI?&lt;/p&gt;

&lt;p&gt;This one&amp;#8217;s going to get complicated, so here&amp;#8217;s the tl;dr version. To get the shortest possible, web-safe identifiers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;encode identifiers with base62 or a customized version of base64 that uses valid characters.&lt;/li&gt;
&lt;li&gt;Use a big enough hash space to get an acceptable level of collisions.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Ok. Here&amp;#8217;s the long-winded version.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s a little like the &amp;#8220;URL Shortener&amp;#8221; use case, where you want to take a big fat link and describe it in a tiny link. In this case, I&amp;#8217;m converting individual sentences into a tiny, linkable representation.&lt;/p&gt;

&lt;p&gt;So, I need a very short identifier that obeys certain (conflicting) properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As much as possible, the identifier should be the same regardless of the order that I create the sentences in&lt;/li&gt;
&lt;li&gt;It should be as short as possible, because I may need to refer to a lot of these in a single URI&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;In the URL shortener mode, they tend to solve this by just keeping a global &amp;#8220;ID&amp;#8221; counter and incrementing it every time someone creates a new link. I need to use something a lot more like a hash. (MD5 or SHA1 are typical choices here.)&lt;/p&gt;

&lt;p&gt;So what are the constraints?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How long can a URI be?&lt;/li&gt;
&lt;li&gt;What characters are we allowed to use?&lt;/li&gt;
&lt;li&gt;How much unique data is going to be represented?&lt;/li&gt;
&lt;li&gt;How tolerant can we be of collisions? (When 2 &amp;#8220;objects&amp;#8221; might map to the same shortened identifier?)&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;URI constraints&lt;/h3&gt;

&lt;p&gt;The first 2 are simple and global. There&amp;#8217;s no real standard on URI length, but &lt;a href=&quot;http://www.boutell.com/newfaq/misc/urllength.html&quot;&gt;smart people have done the legwork for us&lt;/a&gt; so we&amp;#8217;ll steal their conclusions, and say &amp;#8220;keep URI&amp;#8217;s shorter than 2,000 characters.&amp;#8221;&lt;/p&gt;

&lt;p&gt;As far as the characters that can be used, we can consult &lt;a href=&quot;http://tools.ietf.org/html/rfc3986&quot;&gt;RFC 3986&lt;/a&gt; in the &amp;#8220;Unreserved Characters&amp;#8221; section and find we&amp;#8217;re allowed 0-9, a-z, A-Z, and &amp;#8220;- _ . ~&amp;#8221; (dash, underscore, dot, tilde.) I&amp;#8217;m going to avoid using those because I&amp;#8217;d like to keep them for separating my identifiers. So, if we just go with the &amp;#8220;normal characters&amp;#8221;, there&amp;#8217;s 62 of them.&lt;/p&gt;

&lt;h3&gt;Collision Constraints&lt;/h3&gt;

&lt;p&gt;If you assume a hashing function generates numbers pretty randomly spread throughout the number space available to it (which I will for this) there&amp;#8217;s actually some pretty good math we can use to figure out how likely a collision will be. If you&amp;#8217;re interested in where this comes from, check out the &lt;a href=&quot;http://en.wikipedia.org/wiki/Birthday_paradox&quot;&gt;Birthday Paradox&lt;/a&gt;, which is nicely written up at Wikipedia. Using the formulas there you can calculate the probability of having 2 keys that collide, as a function of how many things you&amp;#8217;re trying to insert, and the size of the overall hash space.&lt;/p&gt;

&lt;h3&gt;Putting it all together&lt;/h3&gt;

&lt;p&gt;First, figure out how many items you want to be able to store. (for me, 20,000 is a high estimate).
Second, figure out how comfortable you are with having some keys collide. 50/50 odds? (0.5) 1/1000 chance? (0.001)
I&amp;#8217;m actually pretty ok having a very small number of collisions &amp;#8211; I&amp;#8217;m going to use 0.99, a 99% chance that SOMETHING will collide. (That&amp;#8217;s still going to be a small number, less than a 100% chance that anything at all will collide, let alone more than one.)&lt;/p&gt;

&lt;p&gt;I sketched up a little script for this article (which you can &lt;a href=&quot;http://axis.serialized.net/gitweb/?p=utilities.git;a=blob;f=hashspace_model;hb=HEAD&quot;&gt;grab from my git repo&lt;/a&gt;. It&amp;#8217;s pretty self-documenting, so I&amp;#8217;ll let it speak for itself.&lt;/p&gt;

&lt;p&gt;The goal is, given our constraints, and the fact that we need to use only the characters 0 .. 9, a .. z, A .. Z, (a) how many of those characters do we need, and (b) given that it probably won&amp;#8217;t be an exact fit, what will our collision probability end up being?&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;6&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;7&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;8&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;9&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;10&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;11&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;12&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;13&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;14&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;15&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;16&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;17&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;18&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;19&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;20&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;21&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;22&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;23&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;24&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;25&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;26&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;27&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;28&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;29&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;30&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;31&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;32&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;33&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;34&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;35&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;36&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;37&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;38&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;39&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;40&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;41&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;42&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;43&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;44&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;45&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;perl&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$probability&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;n&quot;&gt;GetOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;items=i&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;probability=f&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$probability&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Trying to store %d items with a %0.5f chance of collision\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$probability&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;c1&quot;&gt;# solve the birthday paradox in terms of &amp;#39;how big the range should be&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;c1&quot;&gt;# http://en.wikipedia.org/wiki/Birthday_paradox#Calculating_the_probability =&amp;gt; wolfram alpha, &amp;#39;solve for d&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$items&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$probability&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;To do that, we&amp;#39;d need to be working in the range 1:$max\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;c1&quot;&gt;# compare that back to the original formula from Wikipedia and make sure that worked&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$calculated_prob&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_probability&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;probability %0.10f should match your requested probability of %0.10f, or something went wrong.\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$calculated_prob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$probability&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;c1&quot;&gt;# so it does, cool&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;c1&quot;&gt;# how many bits would it take to represent $max?&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$frac_bits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$real_bits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$frac_bits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;This can be represented by %0.2f bits (%d)\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$frac_bits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$real_bits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;c1&quot;&gt;# ok, so how about encoding those into URI&amp;#39;s? We can use 0-9, a-z and A-Z, which gives 62 &amp;quot;digits&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;c1&quot;&gt;# aka base62. $max in base62 can be calculated like we did &amp;quot;how many base2 digits were needed&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$base62_digits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;62&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Using 0..9, a..z and A..Z we can represent each object with $base62_digits digits\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;c1&quot;&gt;# ok, if we&amp;#39;re using 5 digits, what&amp;#39;s our actual &amp;quot;space&amp;quot; and what&amp;#39;s the probability of a collision?&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$newmax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;62&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$base62_digits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;c1&quot;&gt;# which is actually how many bits?&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$newbits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$newmax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Given that we&amp;#39;ll have to use %d digits, (%d bits), the real probability of a collision is %0.10f\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$base62_digits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$newbits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_probability&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$newmax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;sub &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get_probability&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;@_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/$max)**(($items*($items-1))/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;The most mysterious parts of this are probably the formulas. The one in the get_probability subroutine is transcribed right &lt;a href=&quot;http://en.wikipedia.org/wiki/Birthday_paradox#Calculating_the_probability&quot;&gt;from the Wikipedia page&lt;/a&gt;, but the other one is the same formula, solved for a different value. In general, if you need to do this, &lt;a href=&quot;http://wolframalpha.com&quot;&gt;WolframAlpha&lt;/a&gt; is a math nerd&amp;#8217;s dream come true. I just asked it to &amp;#8220;solve (the equation) for d&amp;#8221; and got the new formula I needed.
&lt;img src=&quot;http://serialized.net/images/solve_equation.jpg&quot; title=&quot;Solve Equation&quot; alt=&quot;solve equation&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The solution actually comes from &amp;#8220;show your steps&amp;#8221; &amp;#8211; I can find an intermediate form that&amp;#8217;s easier to represent in a non-math-centric programming language. (I&amp;#8217;m sure you can do imaginary numbers in perl, but it was kind of outside the scope of my plans for this evening.)&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s the formula I ended up using:
&lt;img src=&quot;http://serialized.net/images/solution.jpg&quot; title=&quot;solution&quot; alt=&quot;Solved for D&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s a few sample runs of the script:&lt;/p&gt;

&lt;p&gt;First, using my personal constraints for this project:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;6&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;7&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./hashspace_model -i 20000 -p 0.99
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;Trying to store 20000 items with a 0.99000 chance of collision&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;To do that, we&amp;#39;d need to be working in the range 1:43427276.7179157&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;probability 0.9900000006 should match your requested probability of 0.9900000000, or something went wrong.&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;This can be represented by 25.37 bits (26)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;Using 0..9, a..z and A..Z we can represent each object with 5 digits&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;Given that we&amp;#39;ll have to use 5 digits, (29 bits), the real probability of a collision is 0.1961141788&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Cool! So I said I&amp;#8217;m ok with a 99% chance of a collision, and the algorithm figured out that in order to do that, I&amp;#8217;d need to be using 5 digits of base62. And if I&amp;#8217;m using 5 digits of base62, I get 3 more bits than I strictly &amp;#8220;need&amp;#8221;, which means I end up with only about a 1/5 chance of EVER getting a collision.&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s say I wanted to be more strict, and go &amp;#8220;one in a million&amp;#8221;.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;6&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;7&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./hashspace_model -i 20000 -p 0.000001
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;Trying to store 20000 items with a 0.000001 chance of collision&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;To do that, we&amp;#39;d need to be working in the range 1:199989899999232&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;probability 0.0000009992 should match your requested probability of 0.0000010000, or something went wrong.&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;This can be represented by 47.51 bits (48)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;Using 0..9, a..z and A..Z we can represent each object with 8 digits&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;Given that we&amp;#39;ll have to use 8 digits, (47 bits), the real probability of a collision is 0.0000009103&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;In this case base62 comes pretty close to exactly the dimensions that we want, so we more or less get 1/1,000,000 on the nose with 8 digits.&lt;/p&gt;

&lt;p&gt;If you grab the script to play with, you may need to tweak the printf&amp;#8217;s and make sure they have enough resolution for the data you&amp;#8217;re trying to examine.&lt;/p&gt;

&lt;p&gt;Ok, so that tells us how bit our bitspace needs to be, but not how to get a hash, or how to do base62.&lt;/p&gt;

&lt;h3&gt;Hashing Function&lt;/h3&gt;

&lt;p&gt;I chose md5 because&amp;#8230;. it seems to work fine. I&amp;#8217;m sure there&amp;#8217;s a better option, but this is working for now. However, md5 has a lot more bits available than I need. How to just steal a few of them?&lt;/p&gt;

&lt;p&gt;First, you need to know how many bits you want. Thankfully, I know I want 29 bits (thanks, helper script!). I can extract 29 bits of information from it by making a &amp;#8220;mask&amp;#8221; of 29 1&amp;#8217;s, which can be done easily like so:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;perl&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$mask&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;29&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;So, now I just need a raw integer slice of an md5, and do a &amp;#8220;logical and&amp;#8221; of that:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;perl&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Digest::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MD5&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;qw(md5)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;c1&quot;&gt;# unpack makes this back into an integer for us&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;c1&quot;&gt;# L == interpret the data as a 32 bit unsigned long. &lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;c1&quot;&gt;# See &amp;#39;perldoc -f pack&amp;#39; for a ton of other options&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;unpack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;L&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;md5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;the string we want&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nv&quot;&gt;$value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$mask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Groovy. Now we know what number we want to represent, we need to actually represent that in this weird &amp;#8220;base62&amp;#8221; format.&lt;/p&gt;

&lt;p&gt;The algorithm for converting to base(anything) is actually pretty easy.
We&amp;#8217;re used to thinking in base10, so I&amp;#8217;ll show an example of running the algorithm to from and to base10, just so the flow is clear.&lt;/p&gt;

&lt;table&gt;
&lt;tr&gt;&lt;td&gt;125&lt;/td&gt;&lt;td&gt;Starting Value&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;125 % 10 = 5&lt;/td&gt;&lt;td&gt;Find the remainder when dividing by the &amp;#8220;destination base.&amp;#8221; Keep &amp;#8220;5&amp;#8221; as the &amp;#8220;new number&amp;#8221;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;125 / 10 = 12&lt;/td&gt;&lt;td&gt;Divide by the &amp;#8220;destination base&amp;#8221;. This chops the number off the end that we just snagged as a remainder&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;12 % 10 = 2&lt;/td&gt;&lt;td&gt;Do it again with the result of the division. Stick the result to the front of number we&amp;#8217;re keeping track of (now 25)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;12 / 10 = 1&lt;/td&gt;&lt;td&gt;And do the division again&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;1 % 10 = 1&lt;/td&gt;&lt;td&gt;Last remainder, glue to the front again, and we have the answer &amp;#8220;125&amp;#8221;. (Back where we started.)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;1 / 10 = 0&lt;/td&gt;&lt;td&gt;As soon as we get 0 from the division, our work here is done.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;


&lt;p&gt;Simple enough to understand in base10, but the exact same technique works when going from base10 to any other base (2 would work to convert to binary, we&amp;#8217;re using 62, and if you could find enough characters, you could go to something crazy like base300 using the same idea.)&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s the source for it:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;6&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;7&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;8&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;9&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;10&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;11&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;12&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;13&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;14&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;15&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;16&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;17&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;18&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;19&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;20&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;21&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;22&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;23&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;24&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;25&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;26&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;27&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;28&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;29&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;30&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;perl&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;c1&quot;&gt;# even though they are letters we are using them here in the role of &amp;quot;digits&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;@digits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;a&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;z&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;A&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Z&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%digits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$digits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$#digits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;sub &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_base&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;@_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;nb&quot;&gt;die&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;base $base out of range 1-62&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;62&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$digits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$rep&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;c1&quot;&gt;# prepend the &amp;quot;digit&amp;quot; we get when dividing by the base        &lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;nv&quot;&gt;$rep&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$digits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$value&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$rep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;c1&quot;&gt;# then &amp;quot;shift right&amp;quot; the working value&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;nv&quot;&gt;$value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$base&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$rep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;k&quot;&gt;sub &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_base&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$rep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;@_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;nb&quot;&gt;die&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;base $base out of range 1-62&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;62&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;c1&quot;&gt;# this pattern grabs a character at a time, left to right&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$rep&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; /./g&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;nv&quot;&gt;$value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;nv&quot;&gt;$value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$digits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;So there you have it. Provably optimal URI-compatible identifiers with 3 easy steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Figure out what the constraints for your problem space are&lt;/li&gt;
&lt;li&gt;Grab enough bits from md5&lt;/li&gt;
&lt;li&gt;Convert to (and from) base62&lt;/li&gt;
&lt;/ol&gt;

</content>
  </entry>
  
  <entry>
    <title>Quickie: Keeping my OSX downloads folder clean</title>
    <link href="http://serialized.net/2010/05/quickie-keeping-my-osx-downloads-folder-clean/"/>
    <updated>2010-05-04T00:00:00-07:00</updated>
    <id>http://serialized.net/2010/05/quickie-keeping-my-osx-downloads-folder-clean</id>
    <content type="html">&lt;p&gt;My Downloads folder consistently gets large and cluttered. I considered an app like &lt;a href=&quot;http://www.noodlesoft.com/hazel&quot;&gt;Hazel&lt;/a&gt; but it seemed like overkill.&lt;/p&gt;

&lt;p&gt;I added the following alias to my .bashrc file:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;bash&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;clean_downloads&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;find ~/Downloads -mtime +30 -maxdepth 1 -print -exec rmtrash &amp;#39;{}&amp;#39; &amp;#39;;&amp;#39;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;which depends on the free tool &amp;#8217;&lt;a href=&quot;http://www.nightproductions.net/cli.htm&quot;&gt;rmtrash&lt;/a&gt;&amp;#8217; being installed &amp;#8211; a command line way to elegantly move files to the OSX-standard trash can.&lt;/p&gt;

&lt;p&gt;The nice thing is when I think &amp;#8216;that looks messy&amp;#8217;, I just run clean_downloads, and get a nice list of all the things that it just &amp;#8220;trashed&amp;#8221; &amp;#8211; so, worst case, I can go and fish it out right then and there. Actually a bit nicer than things magically getting trashed while I&amp;#8217;m not looking.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Getting around tmpfs &#8216;noexec&#8217; problems</title>
    <link href="http://serialized.net/2010/03/getting-around-tmpfs-noexec-problems/"/>
    <updated>2010-03-16T00:00:00-07:00</updated>
    <id>http://serialized.net/2010/03/getting-around-tmpfs-noexec-problems</id>
    <content type="html">&lt;p&gt;In general, running your /tmp (or /var/tmp) without the execute bit set is a good idea. And sometimes, you don&amp;#8217;t have a choice &amp;#8211; for example, when running in a hosting environment running Virtuozzo.&lt;/p&gt;

&lt;p&gt;You&amp;#8217;re liable to see a mount that looks like this:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; mount | grep noexec
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;/dev/simfs on /tmp type simfs (rw,noexec)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;/dev/simfs on /var/tmp type simfs (rw,noexec)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;devpts on /dev/pts type devpts (rw,nosuid,noexec)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;However, sometimes that&amp;#8217;s a problem, for example if you run the fantastic &lt;a href=&quot;http://www.asic-linux.com.mx/~izto/checkinstall/&quot;&gt;checkinstall&lt;/a&gt; tool to package software. You might see an error message like this:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;text&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;/usr/bin/installwatch: /var/tmp/tmp.SuogJyYftZ/installscript.sh: /bin/sh: bad interpreter: Permission denied
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;The noexec permission has gotten us. How to work around it?
Here&amp;#8217;s a quick, easy to roll back method:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;6&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;7&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;8&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; make a new temporary directory &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;this use
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;go&quot;&gt;mkdir ~/tmptmp&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; use mount &#8211;bind to overlay this on our &lt;span class=&quot;s1&quot;&gt;&amp;#39;real&amp;#39;&lt;/span&gt; /var/tmp &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;now
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; sudo mount &#8211;bind ~/tmptmp /var/tmp
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do &lt;/span&gt;your work
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; sudo checkinstall make install
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; restore the natural order to the universe
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; sudo umount /var/tmp
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;You could also (potentially) remount /tmp without that option temporarily, but that isn&amp;#8217;t always possible. (See &amp;#8216;virtuozzo&amp;#8217; above.)&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Adding iSCSI exports to OpenSolaris for remote Time Machine</title>
    <link href="http://serialized.net/2010/03/adding-iscsi-exports-to-opensolaris-for-remote-time-machine/"/>
    <updated>2010-03-15T00:00:00-07:00</updated>
    <id>http://serialized.net/2010/03/adding-iscsi-exports-to-opensolaris-for-remote-time-machine</id>
    <content type="html">&lt;p&gt;There are 3 ways to Time Machine over the network (that I know of)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use a Time Capsule&lt;/li&gt;
&lt;li&gt;Run Snow Leopard Server, which allows you to set remote drives as Time Machine volumes&lt;/li&gt;
&lt;li&gt;Mount the iSCSI share via an &amp;#8220;initiator&amp;#8221;, and use it like it was a normal hard drive.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;I&amp;#8217;m not sure I&amp;#8217;d want to use the iSCSI option with a laptop, so I use a hybrid of the second and third options.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m running Snow Leopard Server on a Mac Mini with limited disk space. I&amp;#8217;ve got a large server running OpenSolaris about which I &lt;a href=&quot;http://serialized.net/2009/02/the-littlest-thumper-opensolaris-nas-on-an-msi-wind-pc/&quot;&gt;blogged previously.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are the brief steps you need to take to get it working.&lt;/p&gt;

&lt;p&gt;On the Snow Leopard Server, install the &lt;a href=&quot;http://www.studionetworksolutions.com/products/product_detail.php?t=more&amp;amp;pi=11&quot;&gt;ISCSI initiator from GlobalSan.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On your OpenSolaris server, make sure you&amp;#8217;ve installed the support packages needed.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; pkg install SUNWiscsi SUNWiscsitgt
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Now, from one of your available disk pools, create the virtual hard drives for your servers to mount, (making sure you make them about 1.5x larger than the disks you&amp;#8217;re trying to back up, so you can get historical information from them.&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; zfs create -o &lt;span class=&quot;nv&quot;&gt;shareiscsi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;on -s -V 160GB mypool/laptop_tm
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; zfs create -o &lt;span class=&quot;nv&quot;&gt;shareiscsi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;on -s -V 140GB mypool/server_tm
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;To find out what the &amp;#8220;target ID&amp;#8217;s&amp;#8221; are, run this:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;console&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; iscsitadm list target
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;shows the target names to paste into the initiator.&lt;/p&gt;

&lt;p&gt;You can follow the instruction at this &lt;a href=&quot;http://blogs.sun.com/constantin/entry/zfs_and_mac_os_x&quot;&gt;blog on sun.com&lt;/a&gt; which has screenshots of the rest of the process.&lt;/p&gt;

&lt;p&gt;At this point the drives are just like regular disks, from the perspective of your Mac (desktop or server) &amp;#8211; and can be formatted and used for Time Machine. Very convenient and the data that you&amp;#8217;re backing up will be in the safe, safe hands of ZFS in the event of a disk failure.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Using custom functions in Puppet templates</title>
    <link href="http://serialized.net/2010/01/using-custom-functions-in-puppet-templates/"/>
    <updated>2010-01-01T00:00:00-08:00</updated>
    <id>http://serialized.net/2010/01/using-custom-functions-in-puppet-templates</id>
    <content type="html">&lt;p&gt;This eventually required a support ticket to figure out, so I&amp;#8217;m documenting it here in case it&amp;#8217;s useful to others.&lt;/p&gt;

&lt;p&gt;The problem: You have a puppet function you find useful. At this point custom functions are &lt;a href=&quot;http://reductivelabs.com/trac/puppet/wiki/PluginsInModules&quot;&gt;really easy to create and distribute via modules&lt;/a&gt; so there&amp;#8217;s really no reason not to be using them. However, you want to use the result of a function in your templates.&lt;/p&gt;

&lt;p&gt;A real-world example of this is sharing authentication information. (For example, crypted password hashes. Plain text, as always, would be evil no matter where it was living.)
You really have 3 choices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Coding it right into your puppet code and checking that into your version control system&lt;/li&gt;
&lt;li&gt;Not distributing that information with puppet&lt;/li&gt;
&lt;li&gt;Using puppet to distribute the information, but store it outside of your puppet modules somehow.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;We chose the third way, and store this kind of information in YAML files outside the puppet modules tree.
Anyway. So we want to access this info inside a template.&lt;/p&gt;

&lt;p&gt;Assume you have a function called &amp;#8216;get_extdata&amp;#8217;.
You normally call from your &amp;#8216;.pp&amp;#8217; manifests with something like&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;ruby&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;vg&quot;&gt;$data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_extdata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;mymodule&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;path:to:data&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;You can make a call like that from your template by doing this wonderful fragment of magic-wand-waving to get this function accessible:&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;mytemplate.erb&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;erb&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;x&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Puppet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Parser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Functions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;autoloader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loadall&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;x&quot;&gt;    Now you can use the &amp;#39;scope&amp;#39; variable to get at your function.&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;x&quot;&gt;    This is the equivalent of the call get_extdata(&amp;#39;mymodule&amp;#39;,  &amp;#39;path:to:data&amp;#39;):&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;x&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;function_get_extdata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;mymodule&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s1&quot;&gt;&amp;#39;path:to:data&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This works like a charm, and means you don&amp;#8217;t have to create a bunch of variables that you don&amp;#8217;t really need before you load the template.&lt;/p&gt;

&lt;p&gt;So if you were creating an .htpasswd style file with puppet, you could do&lt;/p&gt;

&lt;p&gt;In your &lt;code&gt;init.pp&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;ruby&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;vg&quot;&gt;$users&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;steve&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;paul&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;stu&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;code&gt;htpasswd.erb&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;erb&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;x&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Puppet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Parser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Functions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;autoloader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loadall&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;x&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;-%&amp;gt;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;x&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;function_get_extdata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;authmodule&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;&lt;span class=&quot;x&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;-%&amp;gt;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;



</content>
  </entry>
  
  <entry>
    <title>Updated &#8220;Inbox Zero with Mail.app&#8221; technique</title>
    <link href="http://serialized.net/2009/12/updated-inbox-zero-with-mail-app-technique/"/>
    <updated>2009-12-02T00:00:00-08:00</updated>
    <id>http://serialized.net/2009/12/updated-inbox-zero-with-mail-app-technique</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: I have updated to a new method since writing this &amp;#8211; I now use a &lt;a href=&quot;http://stl.techinno.nl/archive/&quot;&gt;free native Archiving plugin&lt;/a&gt;. More information in my &lt;a href=&quot;http://serialized.net/2010/09/up-up-updated-inbox-zero-with-mail-app-technique/&quot;&gt;most recent article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Back in March, I wrote about my &lt;a href=&quot;http://serialized.net/2009/03/my-approach-to-inbox-zero-with-mailapp/&quot;&gt;technique for implementing Inbox Zero with Mail.app&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since then, the world has changed. I&amp;#8217;ve upgraded to Snow Leopard, and Quicksilver has essentially stopped working out for me. (I&amp;#8217;ve been trying to keep it up to date, and sometimes it kind of works, but my confidence levels are really low.) On the other hand, I&amp;#8217;m loving me some &lt;a href=&quot;http://code.google.com/p/qsb-mac/&quot;&gt;Google Quick Search Box&lt;/a&gt; (a new project from the &lt;a href=&quot;http://www.cultofmac.com/quicksilver-is-sort-of-dead-long-live-google-quick-search-box/6986&quot;&gt;original creator of Quicksilver&lt;/a&gt;). The only feature that I still wanted Quicksilver for was triggers. And until today, I was still running it for trigger support to implement my Inbox Zero trick.&lt;/p&gt;

&lt;p&gt;And then triggers broke when I upgraded it. And I&amp;#8217;m out.&lt;/p&gt;

&lt;p&gt;So here&amp;#8217;s how to get Inbox Zero magic in Mail.app using only tools native to Snow Leopard.&lt;/p&gt;

&lt;p&gt;First, launch Automator and create a new Service workflow.
&lt;img src=&quot;http://serialized.net/images/Automator_select_service.jpg&quot; title=&quot;Automator Create a new Service Workflow&quot; alt=&quot;Automator Create a new Service Workflow&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Select &amp;#8220;Utilities&amp;#8221; and then drag in &amp;#8220;Run Applescript&amp;#8221; to the window on the right.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://serialized.net/images/automator-drag-run-applescript.jpg&quot; title=&quot;Automator: Run Applescript&quot; alt=&quot;Automator: Run Applescript&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Fill in your applescript, replacing only the center &amp;#8220;comment&amp;#8221; block &amp;#8211; leave the other autogenerated lines there.&lt;/p&gt;

&lt;p&gt;The core code again, (tweak to fit your accounts and archive mailbox names)&lt;/p&gt;

&lt;figure class=&#8217;code&#8217;&gt; &lt;div class=&quot;highlight&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre class=&quot;line-numbers&quot;&gt;&lt;span class=&#8217;line-number&#8217;&gt;1&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;2&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;3&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;4&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;5&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;6&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;7&lt;/span&gt;
&lt;span class=&#8217;line-number&#8217;&gt;8&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&#8217;code&#8217;&gt;&lt;pre&gt;&lt;code class=&#8217;applescript&#8217;&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;tell&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;application&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Mail&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;theSelectedMessages&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;selection&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;myAccount&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;zimbra&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;myMailbox&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Archive&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;k&quot;&gt;repeat&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;theMessage&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;theSelectedMessages&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;            &lt;span class=&quot;nv&quot;&gt;move&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;theMessage&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;mailbox&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;myMailbox&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;account&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;myAccount&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;repeat&lt;/span&gt;
&lt;/span&gt;&lt;span class=&#8217;line&#8217;&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;tell&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;It should look something like this:
&lt;img src=&quot;http://serialized.net/images/automator_archive.jpg&quot; title=&quot;Automator: Archive Applescript&quot; alt=&quot;Automator: Archive Applescript&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And that&amp;#8217;s it! Save it, and give it a name you&amp;#8217;ll remember. (I chose &amp;#8220;Archive Selected Mail.&amp;#8221;)&lt;/p&gt;

&lt;p&gt;Now it&amp;#8217;s actually in Mail&amp;#8217;s Menu (under &amp;#8216;Services&amp;#8217;) and we can use the built in OSX hotkey support to launch it.&lt;/p&gt;

&lt;p&gt;Go to the System Preferences Menu, click &amp;#8220;Keyboard Shortcuts&amp;#8221;, and add one for the menu item you created. (It needs to be the same exact name you saved your service as.)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://serialized.net/images/Keyboard-Shortcuts-Archive-Mail.jpg&quot; title=&quot;Keyboard Shortcuts: Archive Mail&quot; alt=&quot;Keyboard Shortcuts: Archive Mail&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Badda bing. Feature complete, and I can (sadly) retire Quicksilver forever. This technique should be extensible to all kinds of other cases when you want to add new features to applications, for access either through the menus or with hot keys.&lt;/p&gt;
</content>
  </entry>
  
</feed>

