<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Drew Stephens</title>
    <link rel="alternate" type="text/html" href="http://dinomite.net/" />
    <link rel="self" type="application/atom+xml" href="http://dinomite.net/atom.xml" />
    <id>tag:dinomite.net,2010-07-14://2</id>
    <updated>2012-01-17T06:15:16Z</updated>
    
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 5.1</generator>

<entry>
    <title>Perl and Dubstep</title>
    <link rel="alternate" type="text/html" href="http://dinomite.net/2011/perl-and-dubstep/" />
    <id>tag:dinomite.net,2011://2.277</id>

    <published>2011-10-26T12:30:00Z</published>
    <updated>2012-01-17T06:15:16Z</updated>

    <summary><![CDATA[In the past year, I have come to quite like dubstep, a burgeoning electronic music genre. Perhaps this is a more interesting introduction than an article. Dubstep's current phase reminds me of generalized techno (mostly house &amp; dance) during the...]]></summary>
    <author>
        <name>Drew Stephens</name>
        <uri>http://dinomite.net/about-me.html</uri>
    </author>
    
        <category term="Computers" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Programming" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="programming" label="Programming" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://dinomite.net/">
        <![CDATA[<p>In the past year, I have come to quite like <a href="http://en.wikipedia.org/wiki/Dubstep">dubstep</a>, a burgeoning electronic music genre.  Perhaps <a href="http://www.youtube.com/watch?v=LXO-jKksQkM">this</a> is a more interesting introduction than an article.  Dubstep's current phase reminds me of generalized techno (mostly house &amp; dance) during the mid-90's--a huge variety of styles, many small artists, much of it distributed through non-traditional channels.  In the late 90's the distribution was via early filesharing networks, most notably Napster.  For Dubstep, <a href="http://www.youtube.com/results?search_type=&amp;search_query=dubstep%20remix&amp;aq=f">YouTube</a>, <a href="http://www.mixcloud.com/dubstep/">Mixcloud</a>, and <a href="http://www.mixcloud.com/dubstep/">Soundcloud</a> seem to be the preferred ways of getting new tracks out.</p>

<p>To chronicle and share this growth of a genre, I started <a href="https://twitter.com/dailywub">@DailyWub</a>, a Twitter account that posts a new dubstep track every day.  Being an engineer, I found the idea of manually keeping a queue and posting a track every day to be a dreadful task.  For some time, the account has been powered by <a href="www.bufferapp.com">Buffer</a>, a simple webapp that allows you to create a queue of tweets that are metered out at a schedule of your choosing.  Buffer is ok, but they limit the queue to 10 tweets, and at some point started shortening URLs even when not needed, which breaks the YouTube thumbnails in many Twitter clients.  Having a queue that is regularly plucked from and emitted to Twitter is a fairly simple operation, so I wrote my own program to do it--<a href="https://metacpan.org/module/Net::Twitter::Queue">Net::Twitter::Queue</a>.</p>

<p>Net::Twitter::Queue is a simple Perl module that employs <a href="https://metacpan.org/module/Net::Twitter">Net::Twitter</a> to do the heavy lifting.  To use it, I have a queue of tweets in a file, <code>tweets.yaml</code>:</p>

<pre class="brush: bash">
- Caspa - Where's My Money? http://www.youtube.com/watch?v=myZU2DZoD9w
- Skrillex - First Of The Year http://www.youtube.com/watch?v=2cXDgFwE13g
- Rusko - Everyday http://www.youtube.com/watch?v=xDAX2aVWAag
</pre>

<p>When run, Net::Twitter::Queue will remove the top item from that YAML file and post it to Twitter using the account information specified in <code>config.yaml</code>:</p>

<pre class="brush: bash">
consumer_key: [consumer_key]
consumer_secret: [consumer_secret]
access_token: [access_token]
access_token_secret: [access_token_secret]
</pre>

<p>Where do those values come from?  Two places: the consumer information is on the page for your application at <a href="https://dev.twitter.com">dev.twitter.com</a> (go ahead, make one!) and the access tokens are specific to the account you want to post as.  To generate them, I used <a href="https://github.com/marcel/twurl">Twurl</a>.  With the consumer key &amp; secret in hand, simply run Twurl:</p>

<pre class="brush: bash">
Titus:~/$ twurl authorize --consumer-key [consumer_key] \
--consumer-secret [consumer_secret]
</pre>

<p>Twurl will respond with a URL that you can visit in a web browser, login to Twitter with the account you want to post as, and get a PIN back.  Give the PIN to Twurl and it will complete the authentication process, saving the access token &amp; associated secret in your <code>~/.twurlrc</code>.  Grab those two, toss them into <code>config.yaml</code> and run Net::Twitter::Queue from the directory that has <code>config.yaml</code> &amp; <code>tweets.yaml</code> in it:</p>

<pre class="brush: bash">
caligula:~/twitter/dailywub$ ls
config.yaml  tweets.yaml
caligula:~/twitter/dailywub$ perl -MNet::Twitter::Queue -e \
'$q=Net::Twitter::Queue->new->tweet'
</pre>

<p>Easy as that--the top entry in <code>tweets.yaml</code> has been popped and posted to Twitter.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Creating a Perl Module in Modern Style</title>
    <link rel="alternate" type="text/html" href="http://dinomite.net/2011/creating-a-perl-module-in-modern-style/" />
    <id>tag:dinomite.net,2011://2.276</id>

    <published>2011-10-22T13:00:00Z</published>
    <updated>2012-01-13T10:29:13Z</updated>

    <summary><![CDATA[One of the very best things about Perl is CPAN, a repository of modules to do everything from browse the web to manipulating image files. CPAN provides a consistent method for installing modules (install cpanminus and then cpanm &lt;Module::Name&gt;) and...]]></summary>
    <author>
        <name>Drew Stephens</name>
        <uri>http://dinomite.net/about-me.html</uri>
    </author>
    
        <category term="Computers" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Programming" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en-us" xml:base="http://dinomite.net/">
        <![CDATA[<p>One of the very best things about Perl is <a href="https://metacpan.org/">CPAN</a>, a repository of modules to do everything from <a href="https://metacpan.org/module/WWW::Mechanize">browse the web</a> to <a href="https://metacpan.org/module/Image::Magick">manipulating image files</a>.  CPAN provides a consistent method for installing modules (<a href="https://metacpan.org/module/App::cpanminus#Installing-to-system-perl">install cpanminus</a> and then <code>cpanm &lt;Module::Name&gt;</code>) and the largest number of modules of all the scripting languages.  More often than not, what you are trying to do has already been done and exists as a CPAN module.  In the event you are doing something new, the best way to give back to the community and get free help is to encapsulate your work and distribute it as a module on CPAN.</p>

<p>Historically, creating a module suitable for general consumption was a confusing.  Tutorials <a href="http://world.std.com/~swmcd/steven/perl/module_mechanics.html">from years past</a> abound, <a href="http://www.perlmonks.org/?node_id=431702">each one longer</a> <a href="http://members.pcug.org.au/~rcook/PerlModule_HOWTO.html">than the previous</a>, and <a href="http://mathforum.org/~ken/perl_modules.html">always employing a different toolchain</a>, making synthesis of common concepts impossible.  These days, however, things are much easier.  In the past 6 years or so the Perl community has tried on a <a href="https://metacpan.org/module/ExtUtils::MakeMaker">number</a> of <a href="https://metacpan.org/module/Module::Build">methods</a> for <a href="https://metacpan.org/module/Module::Install">building</a> modules.  The focus of this article will be a recent (circa late 2009...the Perl ecosystem takes a measured pace) build system, <a href="https://metacpan.org/module/Dist::Zilla">Dist::Zilla</a>.</p>

<p>Whereas <a href="https://metacpan.org/module/ExtUtils::MakeMaker">ExtUtils::MakeMaker</a> and <a href="https://metacpan.org/module/Module::Build">Module::Build</a> are systems for building, testing, and installing a release, Dist::Zilla sits at a higher level.  With Dist::Zilla, you create a single file that controls the build &amp; test flow (using <a href="https://metacpan.org/module/Dist::Zilla::Plugin::MakeMaker">ExtUtils::MakeMaker</a> under the hood) but also provide functionality for generating semi-boilerplate files (LICENSE, MANIFEST, META.yml) and releasing the code via CPAN.  The configuration file, <code>dist.ini</code>, is easy-to-read and short in contrast to prior build systems.</p>

<p>To start using Dist::Zilla, install it using the standard CPAN shell command (<code>cpan -i Dist::Zilla</code>) or with cpanminus (<code>cpanm Dist::Zilla</code>).  You utilize Dist::Zilla through the command <code>dzil</code>; if that's not in your path (<code>which dzil</code>), then you'll want to find it and symlink it somewhere useful or add it to your path.  Global setup of dzil is done by invoking <code>dzil setup</code> and answering the questions it poses.  With that done you can very easily mint a new distribution:</p>

<pre class="brush: perl">
Titus:~/sandbox$ dzil new Number::Cruncher
[DZ] making target dir /Users/dinomite/Dropbox/sandbox/Number-Cruncher
[DZ] writing files to /Users/dinomite/Dropbox/sandbox/Number-Cruncher
[DZ] dist minted in ./Number-Cruncher
</pre>

<p>In the newly created Number-Cruncher directory you'll find a <code>lib</code> directory containing <code>Number/Cruncher.pm</code> and a <code>dist.ini</code>
:</p>

<pre class="brush: perl">
name    = Number-Cruncher
author  = Drew Stephens [drew@dinomite.net]
license = Perl_5
copyright_holder = Drew Stephens
copyright_year   = 2011

version = 0.001

[@Basic]
</pre>

<p>At this point, code and tests are the only things needed to have a Perl module.  Here's some simple code for <code>lib/Number/Cruncher.pm</code>:</p>

<pre class="brush: perl">
use strict;
use warnings;
package Number::Cruncher;

=head1 NAME

Number::Cruncher - crunch numbers

=cut

sub new {
    my $class = shift;
    my $self = {
        first => shift,
        second => shift,
    };
    bless $self, $class;
    return $self;
}

sub crunch {
    my $self = shift;
    return $self->{first} + $self->{second};
}

1;
</pre>

<p>And the associated test file that I created, <code>t/number-cruncher.t</code>:</p>

<pre class="brush: perl">
#!/usr/bin/env perl
use strict;
use warnings;

use Test::More tests => 2;

BEGIN { use_ok 'Number::Cruncher'; }

my $first = 1;
my $second = 7;
my $cruncher = Number::Cruncher->new($first, $second);
ok (($first + $second) == $cruncher->crunch());
</pre>

<p>In three files--<code>dist.ini</code>, <code>lib/Number/Cruncher.pm</code>, and <code>t/number-cruncher.t</code>--we have a module.  Run the test with <code>dzil test</code> and you'll see Dist::Zilla build your module into a temporary directory and run the test suite from there:</p>

<pre class="brush: shell">
Titus:~/sandbox/Number-Cruncher$ dzil test
[DZ] building test distribution under .build/mgJsQhkFi6
[DZ] beginning to build Number-Cruncher
[DZ] guessing dist's main_module is lib/Number/Cruncher.pm
[DZ] extracting distribution abstract from lib/Number/Cruncher.pm
[DZ] writing Number-Cruncher in .build/mgJsQhkFi6
Checking if your kit is complete...
Looks good
Writing Makefile for Number::Cruncher
cp lib/Number/Cruncher.pm blib/lib/Number/Cruncher.pm
Manifying blib/man3/Number::Cruncher.3
PERL_DL_NONLAZY=1 /usr/local/Cellar/perl/5.12.3/bin/perl "-MExtUtils::Command::MM" "-e" "test_harness(0, 'blib/lib', 'blib/arch')" t/*.t
t/number-cruncher.t .. ok   
All tests successful.
Files=1, Tests=2,  0 wallclock secs ( 0.02 usr  0.01 sys +  0.02 cusr  0.00 csys =  0.05 CPU)
Result: PASS
[DZ] all's well; removing .build/mgJsQhkFi6
</pre>

<p>To build a distributable tarball, just run <code>dzil build</code>:</p>

<pre class="brush: shell">
Titus:~/sandbox/Number-Cruncher$ dzil build
[DZ] beginning to build Number-Cruncher
[DZ] guessing dist's main_module is lib/Number/Cruncher.pm
[DZ] extracting distribution abstract from lib/Number/Cruncher.pm
[DZ] writing Number-Cruncher in Number-Cruncher-0.001
[DZ] building archive with Archive::Tar::Wrapper
[DZ] writing archive to Number-Cruncher-0.001.tar.gz
Titus:~/sandbox/Number-Cruncher$ ls Number-Cruncher-0.001*
Number-Cruncher-0.001.tar.gz

Number-Cruncher-0.001:
LICENSE     META.yml    README      lib
MANIFEST    Makefile.PL dist.ini    t
</pre>

<p>If you already have a PAUSE account, you can use <code>dzil release</code> to upload that tarball to PAUSE for inclusion in CPAN.  If you haven't authored a Perl module before, <a href="http://pause.perl.org/pause/query?ACTION=request_id">request an account</a> for uploading modules to CPAN.  With PAUSE and Dist::Zilla, creating widely-available Perl modules is easy.</p>

<h2>See Also</h2>

<ul>
<li><a href="http://dzil.org">dzil.org</a></li>
<li><a href="https://metacpan.org/module/Dist::Zilla::Tutorial">Dist::Zilla::Tutorial</a></li>
<li><a href="https://metacpan.org/release/Shell-Verbose">Shell::Verbose</a>, my first Dist::Zilla-powered module</li>
</ul>
]]>
        <![CDATA[<p><br /> </p>
]]>
    </content>
</entry>

<entry>
    <title>Rafter Pull-Up Bar</title>
    <link rel="alternate" type="text/html" href="http://dinomite.net/2011/rafter-pull-up-bar/" />
    <id>tag:dinomite.net,2011://2.275</id>

    <published>2011-05-23T01:57:52Z</published>
    <updated>2012-01-07T12:27:23Z</updated>

    <summary>I quite enjoy exercising and, ever since I did parkour, I&apos;ve really liked body weight movements. I don&apos;t do much in the way of parkour any more, but I do CrossFit religiously, which features a lot of pull-ups. I&apos;ve got...</summary>
    <author>
        <name>Drew Stephens</name>
        <uri>http://dinomite.net/about-me.html</uri>
    </author>
    
        <category term="CrossFit" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Fitness" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="crossfit" label="CrossFit" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="exercise" label="exercise" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="fitness" label="Fitness" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://dinomite.net/">
        <![CDATA[<p>I quite enjoy exercising and, ever since I did parkour, I've really liked body weight movements. I don't do much in the way of parkour any more, but I do CrossFit <a href="http://www.flickr.com/photos/dinomite/5722067913/in/photostream">religiously</a>, which features a <em>lot</em> of pull-ups.  I've got a <a href="http://www.amazon.com/Iron-Total-Upper-Body-Workout/dp/B001EJMS6K/ref=sr_1_7">doorway pull-up bar</a> which is superb for just getting going in the morning; since they're only $25, I think everyone should have (and use) one.  While having a pull-up bar inside the house is great, I do most of my real workouts in my garage--with easy access to running (the street), box jumps (wall in my back yard), and a barbell, I can do many different <a href="http://www.crossfit.com/cf-info/faq.html#General0">WODs</a>.  For WODs that involve pull-ups, I've been doing them on the rafters in the garage.  While this works, the rafters are a bit too high to get to easily and they <em>really</em> strain my grip.  I'm all for the workout being difficult, but I don't always want it to be training for climbing.  To that end, I built a pull-up bar this weekend.
<a href="http://www.flickr.com/photos/dinomite/5749073468/in/photostream"><img alt="pull-up bar" src="http://farm3.static.flickr.com/2702/5749073468_34876074a9.jpg" width="500" height="164" class="mt-image-center" /></a></p>

<p><a href="http://www.flickr.com/photos/dinomite/5748521987/in/set-72157626658390219/"><img alt="bolt detail" src="http://farm3.static.flickr.com/2160/5748521987_81c1001769_m.jpg" width="240" height="240" class="mt-image-right" /></a>
It's a pretty simple affair, largely based upon <a href="http://www.youtube.com/watch?v=S4vk4M-Vr5o">this instructional video</a>.  The pull-up bar runs perpendicular to a pair of rafters that are 4 feet apart, hanging a few inches below the bottom of the rafters.  In my garage, the rafters are 2x6, which seem to be plenty sturdy enough even when I kip &amp; do muscle-ups over the bar.</p>

<p>The materials I used for the bar:</p>

<ul>
<li>A 48" long, 1" diameter pipe</li>
<li>Two 12" long 2x6s</li>
<li>Two 6" long 2x6s</li>
<li>Six 4" long 3/8" bolts</li>
<li>Six 3/8" nuts</li>
<li>Twelve flat washers</li>
<li>Eight 2.5" long wood screws</li>
<li>Construction adhesive</li>
</ul>

<p><a href="http://www.flickr.com/photos/dinomite/5748523795/in/set-72157626658390219"><img alt="bolt detail" src="http://farm4.static.flickr.com/3430/5748523795_25a4de0930_m.jpg" width="210" height="240" class="mt-image-right" /></a>
The only prep beyond cutting the wood is drilling the holes for the bar in the larger 2x6 pieces.  Note that a 1" diameter bar has a 1" <em>interior</em> diameter, so you need a larger drill bit than 1"; I used a 1¼" bit which was still slightly small, but worked with a bit of extra drill action.  Once the bar holes are drilled, I made the holes for the 3/8" bolts on the opposite half of the 2x6, and corresponding holes in the rafters where the bar was to be mounted.  My standard procedure for woodworking is to supplement my lackluster skill with adhesive, so I applied some construction adhesive with my caulk gun between the 2x6 and the rafter and then bolted it in place.</p>

<p>With the supports bolted in place, I slipped the bar itself through the holes and quickly discovered the need for something more.  The bar itself is 48 inches long, and the space between my rafters is also 48 inches.  Since I put the supports inside a pair of rafters, the bar was nicely flush with the outside of the supports, but this also meant it would only take a couple of inches of lateral movement for it to fall out.  The solution is to cap fashion caps using some more 2x6 and secure it with wood screws.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Parallel Processing in PHP</title>
    <link rel="alternate" type="text/html" href="http://dinomite.net/2011/parallel-processing-in-php/" />
    <id>tag:dinomite.net,2011://2.267</id>

    <published>2011-05-17T12:30:00Z</published>
    <updated>2012-01-16T09:23:25Z</updated>

    <summary>Though not a first choice for long-running processes, many web shops end up writing daemons or batch processing scripts in PHP. As business grows, the need to process records more quickly to deal with traffic becomes an issue. Often times,...</summary>
    <author>
        <name>Drew Stephens</name>
        <uri>http://dinomite.net/about-me.html</uri>
    </author>
    
        <category term="Computers" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Programming" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="computers" label="Computers" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="php" label="php" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="programming" label="Programming" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://dinomite.net/">
        <![CDATA[<p>Though not a first choice for long-running processes, many web shops end up writing daemons or batch processing scripts in PHP.  As business grows, the need to process records more quickly to deal with traffic becomes an issue.  Often times, the processing is limited by something other than raw processing power--network latency and database query times being the usual slowdowns.  When this is the case, the easiest way to increase throughput is with multiprocessing: multiple children that spread the time waiting so as the fully utilize the processing power available.</p>

<p>To this end, I have created a simple framework for managing child/worker multiprocessing in PHP.  Like other high-level interpreted languages, the most straightforward way to spin things up is using <code>fork(2)</code> to create new processes.  While not as Hardcore and Awesome as the lightweight threads that other languages provide, OS-level process creation isn't a huge hindrance if you code for it: make the child processes long running so as to mitigate the startup cost.  </p>

<p>The framework is part of the <a href="https://launchpad.net/genius">Team Lazer Beez Open Source</a> project--you can find it in the <a href="http://bazaar.launchpad.net/~genius.com/genius/trunk/view/head:/php/Utility/">utility</a> package.  The entire thing is simple enough to fit in a single class, <a href="http://bazaar.launchpad.net/~genius.com/genius/trunk/view/head:/php/Utility/lib/gosUtility/Parallel.cls.php">gosUtility_Parallel</a>, the basics of which can be credited to <a href="http://stackoverflow.com/users/47529/chaos">chaos'</a> <a href="http://stackoverflow.com/questions/752214/php-daemon-worker-environment/752255#752255">post on Stack Overflow</a>.</p>

<p>Using the library is simple--extend gosUtility_Parallel and override the <code>doWorkChildImpl()</code> method:</p>

<pre class="brush: php">
// Include the Genius config file
require_once dirname(dirname(__FILE__)) .'/Core/testConfig.inc.php';

class Minimal extends gosUtility_Parallel {
    protected function doWorkChildImpl() {
        gosUtility_Parallel::$logger->debug($this->workerID . " started");
        usleep(2000000);

        gosUtility_Parallel::$logger->debug($this->workerID . " doing work");
        usleep(2000000);

        gosUtility_Parallel::$logger->info($this->workerID . " finishing");
        exit(1);
        return;
    }
}
</pre>

<p>This class creates simple workers that print a couple of debug messages with some sleeping in between, and then announce that they are done working.  Now you can instantiate the class with a single argument: the number of children to run.  gosUtility_Parallel will take care of all the details.</p>

<pre class="bursh: php">
// Make with the go
$minimal = new Minimal(2);
$minimal->go();
</pre>

<p>If children <code>exit</code> with a non-zero status, the parent will spin up a replacement.  The parent will continue to run until all children have exited normally, or it gets <code>INT</code> (say, ctrl+c) or <code>TERM</code> (the default signal sent by kill(1)), in which case it will pass that signal on to the children, ensure they shut down, and then end itself.  gosUtility_Parallel provides ample logging information; running the above produces the following output:</p>

<pre>
INFO - Started worker 0 (pid 42093)
DEBUG - 0 started
INFO - Started worker 1 (pid 42094)
DEBUG - 1 started
DEBUG - 0 doing work
DEBUG - Checking worker 0 (pid 42093)
DEBUG - Checking worker 1 (pid 42094)
DEBUG - 1 doing work
INFO - 0 finishing
INFO - 1 finishing
DEBUG - Checking worker 0 (pid 42093)
INFO - Worker 0 (pid 42093) exited normally
DEBUG - Checking worker 1 (pid 42094)
INFO - Worker 1 (pid 42094) exited normally
</pre>

<p>gosUtility_Parallel provides a number of overrideable methods whose names explain their purpose: <code>parentSetup()</code>, <code>parentCleanup()</code>, and <code>childCleanup()</code>.  Children can also get their <code>$workerID</code> and the <code>$maxWorkers</code> number making processing based upon modular division trivial.  The <a href="http://bazaar.launchpad.net/~genius.com/genius/trunk/view/head:/php/Utility/parallel.php">example parallel class</a> in the distribution demonstrates some of these features:</p>

<pre class="brush: php">
// Include the Genius config file
require_once dirname(dirname(__FILE__)) .'/Core/testConfig.inc.php';

class Par extends gosUtility_Parallel {
    public function __construct($maxWorkers) {
        parent::__construct($maxWorkers);

        // Redefine the logger
        gosUtility_Parallel::$logger = Log5PHP_Manager::getLogger('gosParallel.Par');
    }

    protected function doWorkChildImpl() {
        gosUtility_Parallel::$logger->debug($this->workerID . " started");

        // Run until told not to
        global $run;
        while ($run) {
            gosUtility_Parallel::$logger->debug($this->workerID . " doing work.");
            usleep(2000000);
            if ($this->workerID == 0 && rand(0,10) == 7) {
                gosUtility_Parallel::$logger->info($this->workerID . " returning");
                return;
            }
        }
    }

    protected function parentCleanup() {
        gosUtility_Parallel::$logger->debug("Parent cleaning up");
    }

    protected function childCleanup() {
        gosUtility_Parallel::$logger->debug($this->workerID . " cleaning up");
    }
}
</pre>

<p>The example above runs out-of-the-box (provided your PHP was built with <a href="http://us.php.net/pcntl"><code>--enable-pcntl</code></a>, so I encourage you to <a href="https://launchpad.net/genius">download the source</a> and take it for a test drive.</p>

<p>Incidently, if you're in the Perl world you can just use <a href="http://search.cpan.org/dist/Parallel-ForkManager/lib/Parallel/ForkManager.pm">Parallel::ForkManager</a> and be on your way.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Learning About Nutrition</title>
    <link rel="alternate" type="text/html" href="http://dinomite.net/2011/learning-about-nutrition/" />
    <id>tag:dinomite.net,2011://2.273</id>

    <published>2011-05-02T11:30:25Z</published>
    <updated>2012-01-12T09:27:42Z</updated>

    <summary> I have learned a lot about nutrition in the past few years, mainly fueled by my interest in fitness. Once I got beyond run-of-the-mill Globo Gym workouts by delving into truly challenging fitness like parkour and CrossFit, it became...</summary>
    <author>
        <name>Drew Stephens</name>
        <uri>http://dinomite.net/about-me.html</uri>
    </author>
    
        <category term="CrossFit" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Fitness" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="crossfit" label="CrossFit" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="exercise" label="exercise" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="fitness" label="Fitness" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="nutrition" label="nutrition" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://dinomite.net/">
        <![CDATA[<p><a href="http://www.fitbomb.com/p/why-i-eat-paleo.html"><img alt="Go Paleo" src="http://dinomite.net/assets_c/2011/05/Go%20Paleo-thumb-500x500-2.jpg" width="400" height="400" class="mt-image-right" style="float: right; margin: 0 0 20px 20px;" /></a>
I have learned a <em>lot</em> about nutrition in the past few years, mainly fueled by my interest in fitness.  Once I got beyond run-of-the-mill <a href="http://rehobothcrossfit.com/2010/08/19/globo-gym-vs-crossfit-gym/">Globo Gym</a> workouts by delving into truly challenging fitness like <a href="http://www.americanparkour.com">parkour</a> and <a href="http://crossfit.com">CrossFit</a>, it became apparent that I would need to match exercise with proper nutrition in order to excel.  Note: if you don't give a shit about what I've done and just want to learn about nutrition, <a href="#information">head to the bottom</a>.</p>

<h1>In The Beginning, There Was Parkour</h1>

<p>Training at <a href="http://www.primal-fitness.com/">Primal Fitness</a> was the first time I came across folks who offered dietary advice that wasn't focused on weight loss--something I haven't ever been interested in or needed.  Right in line with the nature of the parkour community at the time, the focus of nutrition was pretty loose: eat more protein and less sugar.  Like any athlete trying to build muscle, eating more protein than that on a <a href="http://en.wikipedia.org/wiki/Western_pattern_diet">standard American diet (SAD)</a> is mostly a no brainer.  Weight lifting folks long ago figured out that protein was essential to building muscle, and in recent years it's common knowledge since we all see <a href="http://www.urbandictionary.com/define.php?term=bro">Bros</a> downing their <a href="http://www.youtube.com/watch?v=4JMOh-cul6M#t=1m40s">protein powder</a>.  Less sugar has <a href="http://www.westonaprice.org/abcs-of-nutrition/475-principles-of-healthy-diets">almost always been</a> generally accepted as good nutrition advice...at least until it was pushed out by the blind fear of fat...but I'm getting ahead of myself.</p>

<h1>The Next Level: CrossFit</h1>

<p>I picked up CrossFit from hanging out at Primal Fitness, and largely as a way to get better at parkour.  Parkour involves lots of short distance sprinting with long distance running and a large amount of gymnastic strength &amp; jumping.  What better to train such a diverse set of skills than the <a href="http://www.crossfit.com/cf-info/what-crossfit.html">general purpose fitness focus</a> of CrossFit?  Indeed, Primal is also a CrossFit box in addition to being the first facility in the US with such a focus on Parkour.  What does CrossFit have to say about nutrition?  Quite a bit, and it's a significant part of the famous World-Class Fitness in 100 Words:</p>

<blockquote>
  <p>Eat meat and vegetables, nuts and seeds, some fruit, little starch and no sugar. Keep intake to levels that will support exercise but not body fat. Practice and train major lifts: Deadlift, clean, squat, presses, C&amp;J, and snatch. Similarly, master the basics of gymnastics: pull-ups, dips, rope climb, push-ups, sit-ups, presses to handstand, pirouettes, flips, splits, and holds. Bike, run, swim, row, etc, hard and fast. Five or six days per week mix these elements in as many combinations and patterns as creativity will allow. Routine is the enemy. Keep workouts short and intense. Regularly learn and play new sports.</p>
</blockquote>

<h1>Enter The Zone</h1>

<p>The main <a href="http://www.crossfit.com/cf-info/start-diet.html">dietary message from CrossFit HQ</a> is that <a href="http://zoneperfect.com/nutrition-program">The Zone Diet</a> is the best set of guiding principals for optimum nutrition.  As much as it may seem on the face of it, this isn't just some marketing cross-promotion crap--much like CrossFit you don't need to buy anything to eat Zone.  The basic tenet is that your meals should all be made up of 40% energy (calories) provided by carbohydrates, 30% by protein, and 30% by fat (<a href="http://www.iom.edu/Reports/2002/Dietary-Reference-Intakes-for-Energy-Carbohydrate-Fiber-Fat-Fatty-Acids-Cholesterol-Protein-and-Amino-Acids.aspx">the food pyramid advises</a> about 55:20:25).  Zone prescribes that the carbohydrates you eat be of the low-glycemic index variety: vegetables, whole grains, whole fruit, though <a href="http://robbwolf.com/2009/11/24/the-black-box-summit-or-how-i-got-fired-from-the-crossfit-nutrition-certification/">some argue</a> that this is offered as secondary to the macronutrient ratio that is the center of Zone.</p>

<p>I gave Zone a solid try while doing CrossFit on my own in 2009 and really liked it--when I managed to stick to the relatively low carbohydrate formula for even a few days I had much more stable energy throughout the day and felt ready to tackle the workout of the day whether I decided to do it first thing in the morning or late in the evening.  For a couple of years, I more-or-less followed the Zone and was pretty happy.  When I moved back to DC, I started CrossFitting at <a href="http://www.potomaccrossfit.com">Potomac CrossFit</a> right around the time they were starting a Paleo Challenge, which encourages people to give a strict paleo diet a try for 30 days.  While I didn't participate in the challenge, I figured it was worth reading up on paleo and giving it a try since I had heard so much about it in the CrossFit community.</p>

<h1>Where I End Up: Paleo</h1>

<p>I picked up <a href="http://robbwolf.com/">Robb Wolf</a>'s book, <a href="http://www.kk.org/cooltools/archives/005236.php">The Paleo Solution</a> and, after initially being off-put by the self-help, anecdotal nature at the beginning of the book, I was impressed with the scientific information and references provided later.  Over the week I read the book I quickly moved from "I'll give this paleo thing a bit of a try" to "I will only eat grass-fed beef and organic broccoli cooked in coconut oil".  I found it so convincing in part because of the science, but also the back-to-basics origin for the ideas on nutrition.  As anyone who has read widely on <a href="http://www.goodhealth.com/articles/2008/04/07/the_age_of_nutritionism_and_pitfalls_of_the_western_diet">modern nutritionism</a> knows, the dietary advice offerings in the past 50 years have done nothing to make Americans or Westerners in general any healthier.  Things like margarine are pushed as healthier replacements only to later find that partially hydrogenated fats are supremely deadly.</p>

<p>Paleo starts by saying, "Nutrition is so complex we haven't come close to understanding it enough scientifically to offer complete dietary advice."  Instead, paleo nutrition bases the nutrition guidelines on what we evolved to eat, that is the foods that sustained humans for the hundreds of thousands of years prior to the rise of agriculture.  Since we have arguably evolved very little since the products of agriculture (grains, legumes) became the central part of our diet, about 10,000 years ago, looking back to what our evolution had us eating seems a very good start.  We need not attempt to reenact the caveman lifestyle, but we can use the diets of our evolutionary ancestors as a logical framework for making nutrition choices in the modern world.</p>

<p>In so many words, that is my nutritional journey--I am now a complete paleo convert.  After trying it for a month, I was absolutely hooked and, a lot like CrossFit, I now try to tell everyone I meet about how awesome this paleo thing is.  In addition to never suffering from <a href="http://www.youtube.com/watch?v=XO_uJVL8KkA">blood sugar fluctuation induced unhappiness</a> I am also not only ready to tackle workouts whenever, but reading to absolutely own them.  Beyond that, the dietary guidelines of paleo fall in line with a <a href="http://www.dovepress.com/the-western-diet-and-lifestyle-and-diseases-of-civilization-peer-reviewed-article-RRCC">wide set of evidence</a> showing that modern diets are wrong in so many ways I really believe that eating this way makes me greatly healthier overall.</p>

<h1><a name="information">Information on Nutrition</a></h1>

<p>The original point of this post was not to just tell my story of nutritional discovery, but to let others know what they should read to understand nutrition.  I never like to just tell people what they should eat, because that makes me just another guy hocking advice that Really Will Make Everything Better!  Instead, I want to give folks the information to make their own decision--and I think the evidence points so strongly in one direction that anyone who does read up on it will be in the same camp that I'm in.</p>

<p>If you're just getting interested in nutrition, then these are the articles you should read.  If you don't care about nutrition, I would encourage you to at least read those by Michael Pollan: they paint a pretty grim picture of the food supply in the United States</p>

<ul>
<li><a href="http://www.nytimes.com/2007/01/28/magazine/28nutritionism.t.html?_r=1&amp;ref=magazine&amp;oref=slogin">Unhappy Meals</a> - Michael Pollan</li>
<li><a href="http://www.nytimes.com/2002/03/31/magazine/power-steer.html?pagewanted=all&amp;src=pm">Power Steer</a> - Michael Pollan</li>
<li><a href="http://www.nytimes.com/2002/07/07/magazine/what-if-it-s-all-been-a-big-fat-lie.html?pagewanted=all">What if It's All Been a Big Fat Lie</a> - Gary Taubes</li>
<li><a href="http://www.westonaprice.org/abcs-of-nutrition/475-principles-of-healthy-diets">Principles of Healthy Diets</a> - Weston A Price Foundation</li>
</ul>

<p>For those who want to know more, a good next step is to check out some documentaries:</p>

<ul>
<li><a href="http://en.wikipedia.org/wiki/Fat_Head_%28documentary%29">Fathead (2009)</a> - A response to <a href="http://en.wikipedia.org/wiki/SuperSize_Me">Super Size Me</a> that effectively presents the flaws of the <a href="http://en.wikipedia.org/wiki/Lipid_hypothesis">lipid hypothesis</a></li>
<li><a href="http://en.wikipedia.org/wiki/King_Corn_%28film%29">King Corn (2007)</a> - On the American industrialized food system</li>
</ul>

<p>To really understand what nutrition is about, book reading is in order:</p>

<ul>
<li><a href="http://www.amazon.com/Why-We-Get-Fat-About/dp/0307272702">Why We Get Fat</a> - A much longer version of the Gary Taubes article above explaining the history &amp; details of modern nutrition advice</li>
<li><a href="http://www.amazon.com/Omnivores-Dilemma-Natural-History-Meals/dp/0143038583/ref=sr_1_1?ie=UTF8&amp;qid=1304302727&amp;sr=8-1">The Omnivore's Dilemma</a> - Michael Pollan's book that introduced nutritionism and its failings, and describes the industrial food system in detail, contrasting it with local agriculture</li>
<li><a href="http://www.amazon.com/Defense-Food-Eaters-Manifesto/dp/0143114964/ref=sr_1_1?ie=UTF8&amp;qid=1304302881&amp;sr=8-1">In Defense of Food</a> - More on food &amp; nutritionism. This is where "Eat food.  Not too much.  Mostly plants" comes from</li>
<li><a href="http://www.marksdailyapple.com/vegetarian-myth-review/">The Vegetarian Myth</a> - A very striking and thorough tearing apart of every angle of vegetarianism written by a former long-time vegan</li>
</ul>

<p>If you really want to have a thorough understanding of the lipid hypothesis, Gary Taubes wrote another book that is basically Why We Get Fat with even more scientific evidence and why the calories in-calories out model for obesity doesn't work entitled <a href="http://www.amazon.com/Good-Calories-Bad-Controversial-Science/dp/1400033462/ref=sr_1_1?ie=UTF8&amp;qid=1304302628&amp;sr=8-1">Good Calories, Bad Calories</a>.</p>

<p>To get an idea of this whole Paleo thing that I have fallen in love with check out these things, in order of brevity (read: depth):</p>

<ul>
<li><a href="http://whole9life.com/2010/05/the-paleo-pitch/">Whole 9's The Paleo Pitch</a></li>
<li><a href="http://robbwolf.com/faq/#overview">Robb Wolf's Paleo Overview</a></li>
<li><a href="http://www.fitbomb.com/p/why-i-eat-paleo.html">Fit Bomb's What Is Paleo?</a></li>
<li><a href="http://www.kk.org/cooltools/archives/005236.php">The Paleo Solution</a> - Robb Wolf's book on the paleo diet (which I reviewed on <a href="http://www.kk.org/cooltools">Cool Tools</a>)</li>
<li><a href="http://www.amazon.com/Paleo-Diet-Weight-Healthy-Designed/dp/0470913029/ref=sr_1_3?ie=UTF8&amp;qid=1304303375&amp;sr=8-3">The Paleo Diet</a> - Dr. Loren Cordain, another big name in the paleo community</li>
<li><a href="http://www.amazon.com/Primal-Blueprint-Reprogram-effortless-boundless/dp/0982207700/ref=sr_1_8?ie=UTF8&amp;qid=1304303375&amp;sr=8-8">The Primal Blueprint</a> - I haven't read Mark Sisson's book, but I do read his <a href="http://www.marksdailyapple.com/">very good blog</a></li>
</ul>
]]>
        

    </content>
</entry>

<entry>
    <title>Building an Olympic Lifting Platform</title>
    <link rel="alternate" type="text/html" href="http://dinomite.net/2011/building-an-olympic-lifting-platform/" />
    <id>tag:dinomite.net,2011://2.270</id>

    <published>2011-04-22T01:29:48Z</published>
    <updated>2012-01-22T01:54:27Z</updated>

    <summary> CrossFit got me started on Olympic lifting and it is now one of my favorite things that I do in the exercise realm. The tools needed for CrossFit are few and generally inexpensive, but Oly lifting does require some...</summary>
    <author>
        <name>Drew Stephens</name>
        <uri>http://dinomite.net/about-me.html</uri>
    </author>
    
        <category term="CrossFit" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="crossfit" label="CrossFit" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="exercise" label="exercise" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://dinomite.net/">
        <![CDATA[<p><a href="http://www.flickr.com/photos/dinomite/5510688763/in/set-72157626102609509/"><img alt="Finished platform" src="http://farm6.static.flickr.com/5174/5510688763_2a99df1c6d.jpg" width="500" height="333" class="mt-image-right" /></a>
CrossFit got me started on Olympic lifting and it is now one of my favorite things that I do in the exercise realm.  The tools needed for CrossFit are few and generally inexpensive, but Oly lifting does require some significant outlay if you plan on doing it at home.  One of the things you need is a platform upon which to perform lifts--it's important to have a stable, flat surface to stand on, and have the ability to drop weights.  Before going through with building a platform I dumped a light bar on my brick patio and the back yard, both of which left marks.  It was time for me to build a platform.</p>

<p>The basic arrangement of a platform is simple: a sufficiently wide patch of wood to stand on flanked by rubber to absorb dropped weights.  There are a <a href="http://straighttothebar.com/articles/2009/03/diy_how_to_build_an_olympic_we/index.html">handful</a> of <a href="http://board.crossfit.com/showthread.php?t=20752">notes</a> on building platforms online, most of which suggest two base layers made from full sheets of 3/4" plywood topped with a third half-sheet of 3/4" plywood with horestall mats on either side.  Simple enough, but these instructions also usually state that the resulting device cannot be lifted by on person alone.  I wanted to have the ability to at least flip my platform on end by myself to get it out of the way, so I took a different route.  To keep the weight more reasonable, I used 3/8" (11/32" at your local lumber yard) plywood and reduced the fore to aft dimension from 8 feet to 6, making for an 8 foot wide by 6 foot long platform.  In practice, this is plenty of space to perform lifts, even if you're doing some real speed as part of a <a href="http://crossfit.com">CrossFit</a> workout.</p>

<p>Materials:</p>

<ul>
<li>Two 6x8 foot sheets of cheap 11/32 plywood</li>
<li>Two 4x6 foot sheets of cheap 11/32 plywood</li>
<li>One 4x6 foot sheet of nice 11/32 plywood</li>
<li>Construction adhesive</li>
<li>150 3/4 inch wood screws</li>
</ul>

<p>Assembly is a very simple affair:</p>

<ol>
<li>Lay the 6x8 sheets with their long edges side by side (<a href="http://www.flickr.com/photos/dinomite/5510660609/in/set-72157626102609509/">photo</a>)</li>
<li>Apply construction adhesive to half of 6x8 sheet pair and top with one of the 4x6 sheets</li>
<li>Drill &amp; screw edges every 6 to 10 inches, and put screws all over the interior as well--it's OK to put screws anywhere, as you won't be standing on this portion</li>
<li>Top with weights to ensure layers bond evenly  (<a href="http://www.flickr.com/photos/dinomite/5510661483/in/set-72157626102609509/">photo</a>)</li>
<li>Apply adhesive to <a href="http://www.flickr.com/photos/dinomite/5511260930/in/set-72157626102609509/">other half</a>, top with remaining 4x6 sheet, and repeat screwing process</li>
<li>Test fit 4x6 piece of nice plywood in the center of the previously assembled parts and mark edges</li>
<li>Apply adhesive to the platform between marks, lay nice plywood down and secure with screws along front &amp; back (4 foot) edges only</li>
<li>Put a <a href="http://www.flickr.com/photos/dinomite/5510663107/in/set-72157626102609509/">crapton of weights</a> on top to ensure your platform comes out flat</li>
<li>Once everything is dry, give it a coat of deck sealant to make it waterproof</li>
</ol>

<p>The end result is a platform that can (just barely) be dragged by one person.  If I were doing this whole thing again, I'd take one more foot off of each dimension, making for a 5 by 7 foot platform and saving significant weight in the process.  I think this would sill leave enough room for any sort of lifting.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Watching iPad Applications</title>
    <link rel="alternate" type="text/html" href="http://dinomite.net/2011/watching-ipad-applications/" />
    <id>tag:dinomite.net,2011://2.271</id>

    <published>2011-04-09T13:00:00Z</published>
    <updated>2012-01-24T00:47:19Z</updated>

    <summary>Shortly after the release of The Daily, Andy Baio created The Daily: Indexed and, more importantly, described how he created that index in a blog post. The crux of his reverse engineering of The Daily app was Charles, which he...</summary>
    <author>
        <name>Drew Stephens</name>
        <uri>http://dinomite.net/about-me.html</uri>
    </author>
    
        <category term="Computers" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Networking" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="ipad" label="ipad" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="networking" label="Networking" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://dinomite.net/">
        <![CDATA[<p>Shortly after the release of <a href="http://www.thedaily.com">The Daily</a>, <a href="http://waxy.org">Andy Baio</a> created <a href="http://thedailyindexed.tumblr.com">The Daily: Indexed</a> and, more importantly, described how he created that index in <a href="http://waxy.org/2011/02/how_i_indexed_the_daily/">a blog post</a>.  The crux of his reverse engineering of The Daily app was <a href="http://www.charlesproxy.com">Charles</a>, which he describes how to use in the aforementioned blog post.  Since reading that post, I've wanted to explore a number of applications on my iPad and iPhone to see what they're really doing when they cause the network indicator to spin.</p>

<p>First things first, I setup Charles and started up <a href="http://reederapp.com/">Reeder</a>, an RSS feed reader that integrates tightly with Google Reader.  My main interest was to see when it actually marked posts as read--I often read in short spurts on my iPhone, which results in pulling up a post only to switch out of Reeder or lock my phone seconds later.  Sometimes the posts would be marked read if I pulled up Google Reader, but sometimes they were still marked unread.  Was this a network latency problem when the phone was using 3G/Edge internet, or was it Reeder doing some fanciness with when it marked posts read?</p>

<p>I didn't get to my goal right away because the first thing I noticed upon starting up Reeder is that it hits the original blog for every single one of the feeds that I subscribed to in Google Reader.  As someone who hasn't cleaned up a number of blogs that don't post anymore, this was a few hundred feeds.  I shouldn't have been surprised by this, as it doesn't really make sense for Google to pull all of the content for all of those blogs and package it up for my convenience.</p>

<p>Getting back to my initial focus, Reeder attempts to mark a post read as soon as you open a post--any failure of a post being marked read is because the network was slow or inoperative at the time you were reading.  Reeder periodically refreshes all of your feeds, as indicated by the spinning icon on the iPad or the replaced battery display on the iPhone, but it actually spends much longer doing this than the icon's state would lead you to believe.  From day-to-day usage the update to the feeds I care about (read: those that actually have updates) is done in short order, but Charles reveals that Reeder is still pulling data from individual websites.  My guess is that Reeder pulls the feed list from Google, gets the new posts mentioned therein, and then proceeds to do its own checking of feeds.</p>

<p>Reeder was the only app that had really crossed my mind after Andy Baio's post, and it fulfilled my desire to experiment with Charles, which is a very good tool that I'll turn to if I have future questions that need answering.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Paleo Egg Muffins</title>
    <link rel="alternate" type="text/html" href="http://dinomite.net/2011/paleo-egg-muffins/" />
    <id>tag:dinomite.net,2011://2.269</id>

    <published>2011-03-07T22:18:45Z</published>
    <updated>2012-01-21T17:52:44Z</updated>

    <summary>There are a number of recipes for paleo muffins, which are a great way to get fast paleo food in the morning. As I usually do with cooking, I created my own recipe from the ones I found online. For...</summary>
    <author>
        <name>Drew Stephens</name>
        <uri>http://dinomite.net/about-me.html</uri>
    </author>
    
        <category term="Cooking" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="cooking" label="cooking" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="nutrition" label="nutrition" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://dinomite.net/">
        <![CDATA[<p>There are a <a href="http://nomnompaleo.com/post/3397688384/curried-beef-broccoli-slaw-mushroom-frittata">number</a> of <a href="http://www.norcalsc.com/index.php/post/egg_cupcakes_to_go/">recipes</a> for <a href="http://everydaypaleo.com/2010/03/24/egg-cupcakes/">paleo</a> <a href="http://paleoblocks.blogspot.com/2010/08/breakfast-muffins.html">muffins</a>, which are a great way to get fast <a href="http://en.wikipedia.org/wiki/Paleolithic_diet">paleo</a> food in the morning.  As I usually do with cooking, I created my own recipe from the ones I found online.  For 24 muffins, I assembled:</p>

<ul>
<li>18 eggs</li>
<li>5 small sausages (breakfast size)</li>
<li>2 large sausages</li>
<li>1 red pepper</li>
<li>1 large onion</li>
<li>1/2 cup strained yogurt (Greek style)</li>
</ul>

<p>The odd sausage arrangement is simply because that is what I had on hand--once cooked and crumbled it was about 2 &frac12; cups worth of sausage.</p>

<p>I began by cooking the sausage, followed by sautéing the diced onion &amp; pepper in the fat that rendered out of the sausage.  After cracking all of the eggs into a a large bowl, I whisked them together with the yogurt.  With all of that assembled, I combined the sausage with the pepper &amp; onion and portioned it into a pair of muffin pans.  The eggs are the last thing before the oven, filling each cup &#8532;rds full.  Into the oven for 15 minutes, rotate top/bottom pan, and give them another 7-10.  The bottoms of mine were a bit under cooked, so I might try putting the lower rack all the way down, rather than the standard in-the-middle.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Altering many directories at once with CmdDirs</title>
    <link rel="alternate" type="text/html" href="http://dinomite.net/2011/altering-many-directories-at-once-with-cmddirs/" />
    <id>tag:dinomite.net,2011://2.268</id>

    <published>2011-02-20T19:34:25Z</published>
    <updated>2012-01-13T13:24:33Z</updated>

    <summary>On any machine I use I create a directory, sandbox, at the root of my home directory to hold checkouts of source code I&apos;m working on. This directory often contains code from many different repositories, dozens of projects that I...</summary>
    <author>
        <name>Drew Stephens</name>
        <uri>http://dinomite.net/about-me.html</uri>
    </author>
    
        <category term="Computers" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Programming" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="computers" label="computers" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="programming" label="Programming" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://dinomite.net/">
        <![CDATA[<p>On any machine I use I create a directory, sandbox, at the root of my home directory to hold checkouts of source code I'm working on.  This directory often contains code from many different repositories, dozens of projects that I intermittently work on.  Many of these repositories depend on others, in particular Java submodules for <a href="http://clearspring.com/">Clearspring</a>, and I want to be able to easily update all of them at once.  With Subversion this is easy: the <code>svn</code> command allows you to act upon a checkout without being in the directory that contains it.  Simply issuing <code>svn up *</code> from <code>~/sandbox</code> ensures that I have the latest code revision in each of my checkouts and <code>svn st *</code> allows me to see if I have any uncommited changes.</p>

<p>While I love Git, it does not make such actions this simple.  Git requires you to be in the repository directory (or set a number of environment variables) to work wit that repo.  While the <a href="http://superuser.com/questions/235455/bash-script-to-perform-an-action-on-each-subdirectory-in-a-directory"><code>-exec</code> option of <code>find(1)</code></a> allows me to descend into each directory and perform an action, I wanted to make this easy, because such all-checkout-actions are something that I want to do a number of times each day.  Like most problems, this one is (best?) solved with Perl.  Enter <a href="https://github.com/dinomite/CmdDirs">App::CmdDirs</a>.</p>

<p><a href="https://github.com/dinomite/CmdDirs/raw/master/bin/cmddirs">CmdDirs</a> is a fairly simple Perl app that I have written to do what I describe above--descend into any number of directories and perform a command in each one.</p>

<pre>titus:~/sandbox$ ls
CmdAll                 mac-itunes             genius-os
scoreboard             GAE                    hf
uaParser               WebService-LOC-CongRec iTunes-Sync
titus:~/sandbox$ cmddirs "git st"
Performing `git st` in &lt;cmdall&gt;
## master
?? App-CmdDirs-1.00.tar.gz

Performing `git st` in &lt;itunes-sync&gt;
## master

Performing `git st` in &lt;uaparser&gt;
## master
 M uaParser/test/test_user_agent.py

Performing `git st` in &lt;webservice-loc-congrec&gt;
## master
</pre>

<p>See the numerous directories? Note that there are 9 directories in my <code>sandbox</code> but <code>git st</code> was only performed in a few of them, those which are Git repositories.  CmdDirs has a modicum of intelligence: if it knows what your command is, the command will only be performed in applicable directories.  This can be overridden with <code>-all</code>, <code>-git</code>, or <code>-svn</code> doing what you expect.  Git and Subversion are the only two things supported right now, because that's all I have a need for. Writing new <a href="https://github.com/dinomite/CmdDirs/tree/master/lib/App/CmdDirs/Traverser">Traversers</a> is simple--just copy the form of git.pm or svn.pm.  You can probably Achieve at this endeavor even without knowing Perl.</p>

<p>Here's a one-liner for installing <code>cmddirs</code>:</p>

<pre>
curl https://github.com/dinomite/CmdDirs/raw/master/bin/cmddirs > ~/bin/cmddirs && chmod a+x ~/bin/cmddirs
</pre>
]]>
        

    </content>
</entry>

<entry>
    <title>Crapcan Racing Tips</title>
    <link rel="alternate" type="text/html" href="http://dinomite.net/2010/crapcan-racing-tips/" />
    <id>tag:dinomite.net,2010://2.265</id>

    <published>2010-12-16T08:48:44Z</published>
    <updated>2012-01-11T09:16:52Z</updated>

    <summary> Drivers&apos; schools are incredibly fun and the best way to improve your driving prowess. Track days can be incredibly useful for honing your skill once you have been on track enough to catch your own mistakes. While incredibly useful...</summary>
    <author>
        <name>Drew Stephens</name>
        <uri>http://dinomite.net/about-me.html</uri>
    </author>
    
        <category term="Cars" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="cars" label="cars" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="lemons" label="LeMons" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://dinomite.net/">
        <![CDATA[<p><a href="http://mpierce.org/gallery/v/motorsport/2010-12-lemons/2010-12-lemons-00012.jpg.html"><img alt="The Jaywatch car" src="http://mpierce.org/gallery/d/4339-2/2010-12-lemons-00012.jpg" width="400" height="267" class="mt-image-left" /></a>
<a href="http://www.nccbmwcca.org/content.php?120-driving-school">Drivers' schools</a> are incredibly fun and the best way to improve your driving prowess.  <a href="http://www.nasaproracing.com/hpde/">Track days</a> can be incredibly useful for honing your skill once you have been on track enough to catch your own mistakes.  While incredibly useful tools for learning to drive fast, neither can touch the <a href="http://www.24hoursoflemons.com/">24 Hours of LeMons</a> for having fun with motorsports.  I have previously written about <a href="http://dinomite.net/2010/how-bvd-skidmark-got-to-goin-for-broken/">the basics of getting to a LeMons race</a>, and what happened at <a href="http://dinomite.net/2010/bvd-skidmarks-first-24-hours-of-lemons/">our first race</a>.  The team just finished another race, the 2010 Arse-Freeze-Apalooza at Buttonwillow this past weekend, where we finished 68th of 173.  Better than half made us happy, because the head gasket blew with an hour and a half left in the race.</p>

<p>Track driving is certainly a specialized skill and racing is a step beyond that--in addition to driving a car at the limit, you have to deal with numerous other cars on track who may decide to pass you at any time.  In crapcan racing things are even crazier because most folks don't care much if the car gets hit and many of them have little to no experience driving on a racetrack, much less in anger.</p>

<h1>Track Experience</h1>

<p>The biggest piece of advice I can give is to get some track experience before heading out on track in your first LeMons race.  Street driving, or even autocross shares very little with driving on a racetrack, and there is no adequate preparation aside from sufficient time on a track.  Even if you have done a lemons race, going to a much less crowded HPDE or other track even twill be very information--rare are the times you get to take an unmolested line, much less lap, at a race.</p>

<h1>Many Races</h1>

<p><a href="http://mpierce.org/gallery/v/motorsport/2010-12-lemons/2010-12-lemons-00097.jpg.html"><img alt="F'ed Up Racing" src="http://mpierce.org/gallery/d/4509-2/2010-12-lemons-00097.jpg" width="400" height="267" class="mt-image-right" /></a>
The first time you go to a 24 Hours of LeMons event, you'll find at least three different types of race teams: those who built something that doesn't belong on a racetrack; the teams there to win; and the teams that are just there to have fun in any way possible.  Don't get me wrong, everyone is there to have fun, but the former two have very specific goals in mind.  The folks who bring a <a href="http://www.thetruthaboutcars.com/2010/12/and-the-real-winner-is-2/">Fiat 600</a> or a <a href="http://www.flickr.com/photos/43812942@N06/5233878618/in/set-72157625406524427/">limousine</a> aren't interested in winning the race outright--they're looking for the <a href="http://jalopnik.com/5068138/index-of-effluency-bar-set-unreasonably-high-for-thunderhill-peugeot-505-turbo-or-chevy-corvair">Index of Effluency</a>, or simply testing their own mechanical mettle.</p>

<p>By the same token, some teams come with the intent to win the speed race--they have a reliable, quick car, know how to do fast pit stops, and don't intend to spend time in the penalty box.  If it's not obvious who these teams are, check the time sheets after a couple hours of racing; they are the ones on the lead lap or just behind.  Figure out which cars belong in this group, do your best to stay out of their way, and certainly don't hit them.</p>

<h1>Caution Wave</h1>

<p>If you've done other racing or track days, one of the first things you'll notice about crapcan racing is the number of yellow flags thrown.  When you have hundreds of $500 cars on a racetrack with inexperienced drivers, problems happen often.  At the Arse-Freeze-Apalooza, Jay said that the recovery crew did 75 tows on Saturday alone.  Oftentimes, cautions will be thrown well ahead of what you can see if you're closely following a pack of cars.  For this reason, you'll see folks who have been racing a while throw up their hand by the rear-view mirror and wave when they see a yellow flag.  This way, everyone behind knows that they are going to slow for caution, and you should too.</p>

<p>Photos by <a href="http://mpierce.org/gallery/v/motorsport/2010-12-lemons/">Marshall Pierce</a>.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>E36 M3 Fuel Mileage</title>
    <link rel="alternate" type="text/html" href="http://dinomite.net/2010/e36-m3-fuel-mileage/" />
    <id>tag:dinomite.net,2010://2.266</id>

    <published>2010-12-10T13:33:26Z</published>
    <updated>2011-09-23T09:01:55Z</updated>

    <summary>Since I have access to a Closed Course and a Professional Driver, I recently did a study of my M3&apos;s gas mileage at different speeds. Since all cars are geared differently and exhibit vastly different aerodynamics, this won&apos;t hold much...</summary>
    <author>
        <name>Drew Stephens</name>
        <uri>http://dinomite.net/about-me.html</uri>
    </author>
    
        <category term="Cars" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="cars" label="Cars" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="m3" label="M3" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://dinomite.net/">
        <![CDATA[<p>Since I have access to a Closed Course and a Professional Driver, I recently did a study of my M3's gas mileage at different speeds.  Since all cars are geared differently and exhibit vastly different aerodynamics, this won't hold much water (gas?) for any other vehicle.</p>

<table>
    <tr>
        <td> Average speed </td>
        <td> Miles per Gallon </td>
    </tr>
    <tr>
        <td>&gt;city&lt;</td>
        <td>22</td>
    </tr>
    <tr>
        <td>55 MPH</td>
        <td>32</td>
    </tr>
    <tr>
        <td>75 MPH</td>
        <td>26</td>
    </tr>
    <tr>
        <td>90 MPH</td>
        <td>24</td>
    </tr>
    <tr>
        <td>105 MPH</td>
        <td>22</td>
    </tr>
</table>
]]>
        

    </content>
</entry>

<entry>
    <title>Creating an OpenVPN Server on Ubuntu</title>
    <link rel="alternate" type="text/html" href="http://dinomite.net/2010/creating-an-openvpn-server-on-ubuntu/" />
    <id>tag:dinomite.net,2010://2.264</id>

    <published>2010-12-01T22:16:01Z</published>
    <updated>2010-12-02T12:47:10Z</updated>

    <summary>I have long used an SSH tunnel (put simply: ssh -D 8000 server + FoxyProxy) to browse the web securely from unencrypted wireless access points and other potentially hostile networks. While this is secure, it isn&apos;t all that convenient and...</summary>
    <author>
        <name>Drew Stephens</name>
        <uri>http://dinomite.net/about-me.html</uri>
    </author>
    
        <category term="Computers" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Linux" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Sysadmin" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="internet" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="linuxsysadmintutorial" label="Linux sysadmin tutorial" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://dinomite.net/">
        <![CDATA[<p>I have long used an <a href="http://embraceubuntu.com/2006/12/08/ssh-tunnel-socks-proxy-forwarding-secure-browsing/">SSH tunnel</a> (put simply: <code>ssh -D 8000 server</code> + <a href="http://getfoxyproxy.org/">FoxyProxy</a>) to browse the web <a href="http://codebutler.com/firesheep">securely</a> from unencrypted wireless access points and other <a href="http://www.wallofsheep.com/">potentially hostile networks</a>.  While this is secure, it isn't all that convenient and <a href="http://sites.inka.de/bigred/devel/tcp-tcp.html">has inherent problems</a>.  What I really want is a proper VPN, that will seamlessly encapsulate <strong>all</strong> traffic from my local machine and pass it through the tunnel to be emitted by the server.  <a href="http://openvpn.net/">OpenVPN</a> is one of <a href="http://www.postfix.org/">those things</a> that has a reputation for being difficult to setup,so I long avoided it.  Once I decided to actually make with the go, it turned out to not be terribly difficult, though I did have to do a bit of searching to get exactly what I wanted.</p>

<p>There are a number of <a href="http://www.linux.com/learn/tutorials/304510:weekend-project-setting-up-a-vpn-on-your-linux-router-or-gateway">good</a> <a href="http://www.itsatechworld.com/2006/01/29/how-to-configure-openvpn/">tutorials</a> for setting up OpenVPN, and the following instructions will mostly mirror those.  First, install the requisite packages:</p>

<pre class="brush: bash">
caligula:~$ sudo aptitude install openvpn
</pre>

<p>Then, setup a place to generate the requisite keys:</p>

<pre class="brush: bash">
    caligula:~$ mkdir tmp/vpn && cd vpn
    caligula:~/tmp/vpn$ cp -r /usr/share/doc/openvpn/examples/easy-rsa/2.0/* .
</pre>

<p>At this point, many tutorials (the above mentioned ones included) say that you should run <code>./init-config</code>, which doesn't exist in recent version OpenVPN.  With the scripts for generating keys in place, open up <code>vars</code> and edit the stuff at the bottom, which should be pretty straightforward:</p>

<pre class="brush: bash">
    export KEY_COUNTRY="US"
    export KEY_PROVINCE="NY"
    export KEY_CITY="Rochester"
    export KEY_ORG="Dinomite-Net"
    export KEY_EMAIL="drew@dinomite.net"
</pre>

<p>The <code>vars</code> file just sets up a bunch of environment variables, so you'll want to source it and then build the certificate authority:</p>

<pre class="brush: bash">
    caligula:~/tmp/vpn$ source vars
    caligula:~/tmp/vpn$ ./clean-all
    caligula:~/tmp/vpn$ ./build-ca
</pre>

<p>Building the certificate authority involves a few questions, for most of which the defaults defined from <code>vars</code> are all you need.  Next, build the keys for the server and client (I name my computers <a href="http://dinomite.net/2009/caligulas-giant-ship/">after Roman emperors</a>):</p>

<pre class="brush: bash">
    caligula:~/tmp/vpn$ ./build-key-server caligula
    caligula:~/tmp/vpn$ ./build-key vespasian
    caligula:~/tmp/vpn$ ./build-dh
</pre>

<p>With all that done, you can copy the appropriate key files over to the client, in my case <code>vespasian</code>.  Since I already had <a href="http://code.google.com/p/tunnelblick/">tunnelblick</a> on that machine, I put the files directly where they needed to go:</p>

<pre class="brush: bash">
caligula:~/tmp/vpn$ cd keys
caligula:~/tmp/vpn/keys$ scp vespasian.crt vespasian.key \
    ca.crt vespasian:~/Library/Application Support/Tunnelblick/Configurations/
</pre>

<p>Two steps left.  First, make the client configuration file.  For tunnelblick, this goes in the same directory as above, and you can name it whatever you want:</p>

<pre class="brush: bash">
    vespasian:~$ cat Library/Application Support/Tunnelblick/Configurations/client.conf
    client
    dev tun
    proto udp
    remote caligula.dinomite.net 1194
    resolv-retry infinite
    nobind
    persist-key
    persist-tun
    ca ca.crt
    cert vespasian.crt
    key vespasian.key
    comp-lzo
    verb 3
</pre>

<p>There are plenty of other sites that will explain what all of those options mean, so I won't go over it here.  The important things to change from above are the <code>remote</code> and the names for the <code>cert</code> and <code>key</code>.  Now on to the server config and the files that it needs:</p>

<pre class="brush: bash">
    caligula:~/tmp/vpn/keys$ cp dh1024.pem caligula.key caligula.crt /etc/openvpn/
    caligula:~/tmp/vpn/keys$ cat /etc/openvpn/server.conf
    server 10.7.7.0 255.255.255.0
    push "redirect-gateway"

    dev tun0
    proto udp
    keepalive 10 120
    comp-lzo
    dh /etc/openvpn/dh1024.pem
    ca /etc/openvpn/ca.crt
    cert /etc/openvpn/caligula.dinomite.net.crt
    key /etc/openvpn/caligula.dinomite.net.key

    status /var/log/openvpn-status.log
    verb 3
</pre>

<p>The secret sauce in that config is <code>push "redirect-gateway"</code> which is what tells the client to route all of its traffic through the tunnel to the server.  To make this work, the server needs to be set up to do <a href="http://en.wikipedia.org/wiki/Network_address_translation">NAT</a>:</p>

<pre class="brush: bash">
    caligula:~/tmp/vpn/keys$ echo "1" > /proc/sys/net/ipv4/ip_forward
    caligula:~/tmp/vpn/keys$ iptables -t nat -A POSTROUTING -s 10.7.7.0/24 -o eth0 -j MASQUERADE
</pre>

<p>That's all there is to it!  Just restart the server (<code>sudo /etc/init.d/openvpn restart</code>), connect, and all your traffic is now safely encrypted to the server.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Brake Pads for the E36 M3</title>
    <link rel="alternate" type="text/html" href="http://dinomite.net/2010/brake-pads-for-the-e36-m3/" />
    <id>tag:dinomite.net,2010://2.263</id>

    <published>2010-11-20T14:07:15Z</published>
    <updated>2010-11-20T15:37:29Z</updated>

    <summary>I&apos;ve been doing autocross and track days with my 1997 BMW M3 for long enough that I can offer some insight into the brake pads available for E36 M cars. What follows are the brake pads that I have driven,...</summary>
    <author>
        <name>Drew Stephens</name>
        <uri>http://dinomite.net/about-me.html</uri>
    </author>
    
        <category term="Cars" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="bmw" label="bmw" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="cars" label="cars" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="e36" label="E36" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="m3" label="M3" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://dinomite.net/">
        <![CDATA[<p>I've been doing autocross and track days with my 1997 BMW M3 for long
enough that I can offer some insight into the brake pads available for
E36 M cars.  What follows are the brake pads that I have driven, in
order of heat handling. If you only drive on the street, the top of
the list is where you want to be. If you have a race car, the bottom
is your domain.</p>

<h2>EBC Greenstuff</h2>

<p>An awesome street pad, thanks to producing much less dust than stock.  I drove these pads at my very first HPDE with the <a href="http://www.nccbmwcca.org">National Capital Chapter</a> of the <a href="http://bmwcca.org">BMW CCA</a>; the track is not their forte. By the end of the second day, I had burned through 3/4 of the pads, and the car was putting out clouds of smoke braking into turn 1 on Summit Point's main circuit. Unsurprisingly, this was accompanied by significant fade.</p>

<p>Like stock pads, these will work for your first track experience if you are conservative, but I wouldn't recommend it. Thanks to their low dust, EBC Green Stuff work great for street pads and even the
occasional autocross.</p>

<h2>Hawk High Performance Street (HPS)</h2>

<p>The HPS are biled as a stock-replacement pad and I would agree with that.  They dust a bit less than BMW OEM pads, and provide a little bit more fade resistance.  For track use, the HPS is much like stock or the EBC Greenstuff mentioned above--they'll work if you're new &amp; conservative or slow.</p>

<h2>Axxis Ultimate (ULT)</h2>

<p>These are quite similar to the HPS--less dust than stock, good feel even when stone cold, and a bit more heat handling capability than stock.  They work great for street driving and autocrossing, but are only good for limited (read: slower) track use.</p>

<h2>Hawk High Performance Plus (HP+)</h2>

<p>The HP+ are a good compromise between track and street pads.  I recently used them for a fade-free weekend at Thunderhill with ambient temperature of 70-80F.  Unlike a full-on track pad that is downright scary on the street, the HP+ is decidedly OK on the street.  The first stop of a drive (or after not using them on the highway for a few minutes) will be a bit longer than stock pads, but not the Flintstones feeling of track pads.</p>

<h2>Hawk Blue</h2>

<p>I am lazy, so I put my pads on at home before driving to the track, so I got to experience these on the street.  To begin with, the first stop from neighborhood speeds takes about twice the distance you expect, and the initial bit is nonexistent.  After a couple more low speed stops, the brakes have enough heat to work just fine, but they still squeal as though you are murdering cats with each brake application.</p>

<p>On the track, the Hawk Blue is an awesome pad.  Being a true track pad it takes some heat before they really work, as described above.  Just like you need to get your tires and brain up to temperature, with a track pad you need some heat in the brakes before they will do what you expect.  You should be driving judiciously on your out lap anyway, so this ought not be a problem.  The wear on these is much better than any of the aforementioned pads--a day at Laguna Seca burned less than one quarter.  If you have been going to the track for a while, or if you've gotten fast enough to begin feeling fade in your existing brake setup, get some track pads.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Synchronizing an iTunes Library Between Two Computers</title>
    <link rel="alternate" type="text/html" href="http://dinomite.net/2010/synchronizing-an-itunes-library-between-two-computers/" />
    <id>tag:dinomite.net,2010://2.262</id>

    <published>2010-10-26T18:14:03Z</published>
    <updated>2011-07-16T01:47:33Z</updated>

    <summary>Like many folks, I have a desktop that I use for most of my computing, and a laptop that I use while travelling, at a coffee shop, or perhaps while watching tv. The other thing I have is a lot...</summary>
    <author>
        <name>Drew Stephens</name>
        <uri>http://dinomite.net/about-me.html</uri>
    </author>
    
        <category term="Computers" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Mac" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="computers" label="computers" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="itunes" label="iTunes" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="mac" label="Mac" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="programming" label="Programming" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://dinomite.net/">
        <![CDATA[<p>Like many folks, I have a desktop that I use for most of my computing, and a laptop that I use while travelling, at a coffee shop, or perhaps while <a href="http://www.suntimes.com/technology/ihnatko/2745228,ihnatko-multitasking-twitter-internet-092510.article">watching tv</a>.  The other thing I have is a lot of music, all nicely rated and organized in iTunes. The problem is that new music I get goes onto my desktop, but I would like to have the exact same stuff on my laptop.  Enter <a href="http://github.com/dinomite/iTunes-Sync">iTunes-Sync</a>, a simple script that I wrote to synchronize the iTunes library file and all of the content (music, etc.) that it depends upon between the two machines.  </p>

<p>Using iTunes-Sync is simple:</p>

<pre lang="bash">
laptop:~/$ perl itunes_sync.pl dinomite 192.168.1.100
</pre>

<p>That's all there is to it.  The script copies the <code>iTunes Library</code> file wholesale, and uses <code>rsync(1)</code> to pull over the album art, mobile applications, and music directories.</p>

<p>I only care about getting everything from my desktop to the laptop--if you want to go both ways, or perhaps preserve metadata changes made on the laptop the process will be a bit more involved.  Before you use your laptop, close iTunes on both machines, and then run iTunes-Sync from the laptop.  Go out and have fun.  When you get back, close iTunes on both machines and run iTunes-Sync from the desktop.</p>

<p>You can get iTunes-Sync on <a href="http://github.com/dinomite/iTunes-Sync">GitHub</a>; the only thing you need is the <a href="http://github.com/dinomite/iTunes-Sync/raw/master/itunes_sync.pl">itunes_sync.pl</a> file itself.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Tough Mudder Norcal 2010</title>
    <link rel="alternate" type="text/html" href="http://dinomite.net/2010/tough-mudder-norcal-2010/" />
    <id>tag:dinomite.net,2010://2.261</id>

    <published>2010-10-15T00:09:36Z</published>
    <updated>2010-10-28T20:08:09Z</updated>

    <summary>On October 9th, I ran the Northern California Tough Mudder. Billing itself as &quot;the TOUGHEST one day event on the planet&quot;, Tough Mudder is an endurance race helad at a number of venues throughout the United States. The event is...</summary>
    <author>
        <name>Drew Stephens</name>
        <uri>http://dinomite.net/about-me.html</uri>
    </author>
    
        <category term="CrossFit" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Fitness" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="crossfit" label="CrossFit" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="fitness" label="Fitness" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://dinomite.net/">
        <![CDATA[<p>On October 9th, I ran the <a href="http://toughmudder.com/events/northern-california/bear-valley-course-map/">Northern California Tough Mudder</a>.  Billing itself as "the TOUGHEST one day event on the planet", Tough Mudder is an endurance race helad at a number of venues throughout the United States.  The event is basically a trail run punctuated by obstacles.  Except there aren't many trails involved--the terrain covered is largely rock washes and barren mountain.  <a href="http://toughmudder.com/events/">Most of the locations</a> are ski resorts, perfect because they offer challenging ground with significant elevation change to add difficulty.</p>

<p><a href="http://www.flickr.com/photos/ryandoherty/5065905645/"><img alt="Crossing the finish line" src="http://farm5.static.flickr.com/4131/5065905645_acd88fec4e.jpg" width="500" height="375" class="mt-image-right" style="float: right; margin: 0 0 20px 20px;" /></a>
As they say at the start line, this isn't your average trail run, mud run, obstacle course, triathlon, or marathon.  In my mind, Tough Mudder is one of many things that could be considered what <a href="http://www.crossfit.com">CrossFit</a> is all about.  The Norcal event took place at <a href="http://www.bearvalley.com">Bear Valley Mountain Resort</a>, which ranges in elevation from about 7,000 feet up to 8,500 feet.  The start of the run was near the bottom, leaving us to go up and down the entirety of that 1,500 vertical feet twice.  In the midst of that, obstacles ranged from crawling under low wire or through tubes, to being assaulted with freezing cold water from snow machines.</p>

<p>Overall, I'd say the hardest parts of Tough Mudder were the elevation and the running in total.  Having not done the event before, it's hard to know what it will be like.  My expectations were for a demanding obstacle course with some significant running in between.  As mentioned above, I would now describe it in the opposite order: a very difficult trail run with some obstacles along the way.</p>

<p>The preparation advice on the Tough Mudder site can be a bit hard to parse and leaves a lot of questions, so here's my stab at it:</p>

<ul>
<li>Do CrossFit or join an elite military unit; little else that can adequately prepare you for such a demanding event</li>
<li>This is not a marathon; being a running twig won't get you through Tough Mudder in a reasonable time</li>
<li><a href="http://www.mechanix.com/automotive/the-original-glove">Mechanix Gloves</a> which are fairly light, durable, and form fitting are a very good choice</li>
<li>Wear normal workout or outdoor clothes--you'll get dirty, but not ripped up</li>
<li>If you have an older pair of sunglasses, wear them</li>
<li>Don't worry about carrying water, it will be provided on the course every few miles</li>
<li>Walk on the right, run on the left: slowing down is fine, but please stay out of the way of the more dedicated folks</li>
<li>The water will be cold, nothing can change that</li>
</ul>

<p>So how did I do?  Well, Tough Mudder makes a big point of saying, "it's an event, not a race".  I started in the 12:00 group, which gave me a chance to watch the first group, which started at 10:00 and included the most elite runners, begin to finish at 11:16.  I went into my group knowing that 1 hour 16 minutes was the time to beat.  I crossed the finish line at 13:43, putting me at 1 hour 43 minutes.  I discout this a bit because I spent 5 minutes or so waiting to do the spool-jumping obstacle, and nearly 15 minutes waiting at the mud-run obstacle because the pommel horse jumping was backed up.  I'm confident in saying that my correct time was about 1:25.</p>

<p>More pictures:</p>

<ul>
<li><a href="http://www.facebook.com/album.php?aid=31551&amp;id=124998340846518">From Tough Mudder on Facebook</a></li>
<li><a href="http://www.facebook.com/album.php?aid=226592&amp;id=44016588030">Even more from them</a></li>
<li><a href="http://www.brightroom.com/view_user_event.asp?EVENTID=65677&amp;BIB=2921&amp;LNSEARCH=1&amp;PWD=">Me, looking pretty buff and tired</a></li>
</ul>
]]>
        

    </content>
</entry>

</feed>

