<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom">
    <title>Contentment</title>
    <link rel="alternate" type="text/html" href="http://contentment.org/" />
    
    <id>tag:contentment.org,2008-03-23://3</id>
    <updated>2009-11-04T04:18:29Z</updated>
    <subtitle>The place where I get my geek on...</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.21-en</generator>

<link rel="self" href="http://feeds.feedburner.com/Contentment" type="application/atom+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry>
    <title>Bluga WebThumbs 1.0 for Drupal 6</title>
    <link rel="alternate" type="text/html" href="http://contentment.org/2009/11/bluga-webthumbs-10-for-drupal.html" />
    <id>tag:contentment.org,2009://3.674</id>

    <published>2009-11-04T04:02:47Z</published>
    <updated>2009-11-04T04:18:29Z</updated>

    <summary>If you use Drupal and would like to automatically generate thumbnails of web sites, you might want to take a look at the Bluga WebThumbs module. Once that module is installed on Drupal and you have given the module your...</summary>
    <author>
        <name>Andrew Sterling Hanenkamp</name>
        <uri>http://andrew.sterling.hanenkamp.com</uri>
    </author>
    
        <category term="Drupal" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="blugawebthumb" label="Bluga WebThumb" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="drupal" label="drupal" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="modules" label="modules" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="webservices" label="web services" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://contentment.org/">
        <![CDATA[<p>If you use <a href="http://drupal.org">Drupal</a> and would like to automatically generate thumbnails of web sites, you might want to take a look at the Bluga WebThumbs <a href="http://drupal.org/project/bluga">module</a>. Once that module is installed on Drupal and you have given the module your <a href="http://webthumb.bluga.net/home">Bluga WebThumb</a> API key, you can then inject a PHP snippet like this into a node using the PHP filter or into a theme file:</p>

<pre><code>&lt;?php
print bluga_webthumb('http://contentment.org/');
?&gt;
</code></pre>

<p>Now, when you view the page containing that snippet, you will see a thumbnail generated using the Bluga WebThumb service within a few seconds that shows that web site. The thumbnail is cached locally on your server.</p>

<p>You can further customize your thumbnail with many options. You can read the full <a href="http://drupal.org/node/620684">documentation</a> for the module at Drupal&#8217;s web site as well. New features since March of last year also include a script for updating the thumbnail in place without requiring a page reload and a nicer looking (and CSS-styled) place holder, which is an improvement over the graphic previously used.</p>

<p>Last week, I was approached by the owner of <a href="http://konigi.com">Konigi.com</a> to do some Drupal work. He&#8217;s a user of the Bluga WebThumbs module I wrote in March of last year and wanted to see it work with Drupal 6. I have finished the update and have made a full release of the Drupal 5 version of the module after making a few improvements and then ported the module to Drupal 6.</p>

<p>Cheers.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Google Wave is Nothing Special</title>
    <link rel="alternate" type="text/html" href="http://contentment.org/2009/10/google-wave-is-nothing-special.html" />
    <id>tag:contentment.org,2009://3.673</id>

    <published>2009-10-15T23:28:10Z</published>
    <updated>2009-10-15T14:28:34Z</updated>

    <summary>In the past, I’ve done a fair bit of work on Jifty with Jesse Vincent by way of my previous job. He had some Google Wave invites and I begged one off of him. After waiting a week, it came...</summary>
    <author>
        <name>Andrew Sterling Hanenkamp</name>
        <uri>http://andrew.sterling.hanenkamp.com</uri>
    </author>
    
    
    <content type="html" xml:lang="en-us" xml:base="http://contentment.org/">
        <![CDATA[<p>In the past, I&#8217;ve done a fair bit of work on <a href="http://jifty.org">Jifty</a> with <a href="http://www.fsck.com/">Jesse Vincent</a> by way of my previous job. He had some <a href="http://wave.google.com/">Google Wave</a> invites and I begged one off of him. After waiting a week, it came through and splat. Google Wave is a wasteland of nothing. Playing with some posts to myself led to about 10 minutes of use and then I hung up.</p>

<p>A <a href="http://nowthis.com/">colleague</a> of mine, who (last I knew) does not have a Google Wave account had come across a LifeHacker <a href="http://lifehacker.com/5372853/the-first-google-wave-search-you-must-know">post</a> describe the &#8220;with:public&#8221; search that provides at least some content for Google Wave. However, that content is mostly just a dearth of &#8220;What can I do?&#8221; and &#8220;Anybody else here from Canada?&#8221; and &#8220;What happens if I post porn?&#8221; It was initially interesting, but I got about another 10 minutes and hung up again.</p>

<p>Okay, so there&#8217;s not much to do, but it&#8217;s brand spanking new. Thus, criticizing it now is like calling a bridge useless when the engineers have only just finished putting up the supports. There are couple things I&#8217;d like to note, though.</p>

<p>First, there&#8217;s not just a whole lot new here. Google Wave is merely a new combination of social networking, email, wiki, forums, chat, document and image sharing, and widgetry. If you&#8217;ve used a Wiki, Twitter, IM, and Email before, you have a good idea what Google Wave is already. They&#8217;ve just taken the next step and attempted to combine things in a way that will be challenging to scale, but I think Google is up to the task.</p>

<p>Second, that all said there is something I hope that can be achieved here, if not by Wave, by something like it. They consider Google Wave to be a reinvention of email. They have the idea that they might be able to replace email with it. Maybe. I think email has already been replaced by SMS, Twitter, and Facebook for many people. I end up using Facebook to send messages to folks much more often than Email these days and would probably use SMS if I weren&#8217;t so cheap and had someone other than my wife that I communicated with regularly via cell phone. </p>

<p>Problem: Services like Twitter and Facebook have a very significant problem. They&#8217;ve taken the Internet backwards by providing a single hosted service in the cloud. Email has an important advantage in that if my email provider has an outage, everyone else on the Internet is probably fine. If my email provider goes out of business or provides terrible service, I have the alternative to go somewhere else. Twitter and Facebook have competitors, but unless you can convince all your family and friends to move with you, you can&#8217;t leave them unless you&#8217;re willing to sever your ability to communicate with them.</p>

<p>Solution: Something like Google Wave or Twitter or a consortium of social networking sites needs to come up with a new decentralized mechanism for communicating between people. Whether that means you can switch services but they have hooks between one another to send messages and share friend lists or Google Wave provides some sort of decentralized platform for doing this independent of the social networking sites, something needs to happen here.</p>

<p>There are other dangers here to privacy and such that I haven&#8217;t even touched on either. Something like Google Wave (assuming Google Wave can become decentralized like email) should happen if social networking is going to continue to develop. That&#8217;s my thought anyway.</p>

<p>Cheers.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Driving an Empty Bus or a Clown Car?</title>
    <link rel="alternate" type="text/html" href="http://contentment.org/2009/09/driving-an-empty-bus-or-a-clow.html" />
    <id>tag:contentment.org,2009://3.670</id>

    <published>2009-09-11T02:44:30Z</published>
    <updated>2009-09-11T03:00:34Z</updated>

    <summary>This morning I had an epiphany about a difference in project management style between the two major development jobs I’ve held. One style was like driving an empty bus and the other was like riding in a clown car. I...</summary>
    <author>
        <name>Andrew Sterling Hanenkamp</name>
        <uri>http://andrew.sterling.hanenkamp.com</uri>
    </author>
    
    <category term="development" label="development" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="fun" label="fun" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="management" label="management" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="project" label="project" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="software" label="software" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="style" label="style" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="work" label="work" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://contentment.org/">
        <![CDATA[<p>This morning I had an epiphany about a difference in project management style between the two major development jobs I&#8217;ve held. One style was like driving an empty bus and the other was like riding in a clown car. I am going to examine both as anecdotes from my perspective and try to avoid grandiose analysis.</p>

<h3>The Empty Bus</h3>

<p>So, I start the job and the first thing the company does is hand me the keys to the bus. Actually, they dither on what kind of bus to give me for several months before getting me a suitable one and give me a loaner to drive in the meantime. However, once on the bus driving, I am pretty much on my own. I have a destination to reach that has been vaguely described on a scribbled piece of paper. The directions are unclear and no one in the company has been there before. They keep changing the directions. But I get to drive. That is fun.</p>

<p>Every now and then, I pick somebody from the company up, they make changes to the directions and then they get off again before I go very far. Every six months, everybody climbs on to the bus and sits in the very back. They do a lot of yelling while I park and then they take away my scribbled directions and give me new scribbles to follow and a new destination to reach. But I get to drive. That&#8217;s usually fun.</p>

<p>All in all, I am asked to develop software with very little cooperation or direction. I am left on my own to make almost all the decisions. Even though I have weekly meetings with my manager, I am not really given much feedback on whether I&#8217;m going the right way. He&#8217;s not a developer, so he doesn&#8217;t really know enough about what I do to give me useful feedback. My quarterly reviews aren&#8217;t very cooperative or helpful, they are more about the manager wishing I would drive faster and make fewer mistakes (mutually exclusive goals when you think about it).</p>

<p>I nearly get into a wreck a couple times, but there&#8217;s no one on the bus to help me out. Don&#8217;t get me wrong, I&#8217;m not an excellent driver. I&#8217;m still learning, but some help should help things go faster in process, you&#8217;d think. Usually, though, my directions are so unclear and difficult to follow that I am directed to get into wrecks. This is not actually all that fun as time goes on.</p>

<h3>The Clown Car</h3>

<p>Clown cars are funny. They drive around in circles and then the doors pop open and an absurd number of hilarious characters hop out of the little car. This job is not quite like this. It&#8217;s actually more like a really crowded minivan, like the trip I took the other day with my wife, son, dad, mom, brother, sister, and her boyfriend, all crammed into our little Pontiac Montana. But now, imagine, that all of these people have a stake in where the van goes and have a slightly role and different idea about how to go about getting there. Now, we&#8217;ve got a good analogy. Clown cars are fun, though.</p>

<p>The CEO&#8217;s seat is next to mine and he gets in and out of the van whenever he feels the need. He&#8217;s a busy man: lots of vans to help. Usually, he gets in right before we wreck or near the major turns to make sure we drive carefully at those point and turn the right direction. Directly behind me sits an analyst whose job it is to navigate. He tells me where to go and annotates those instructions pretty regularly. Beside him sits another analyst whose job it is to talk to the customer and figure out what they want. He then tells the first analyst and me where we need to think about going next. I get to drive, though, they keep reaching from the back for the wheel and the pedals. That&#8217;s annoying, but still fun.</p>

<p>Behind the analysts sit a whole team of project managers, executives, sales people and between them and between the front seats sit a bunch of other engineers. Sometimes the other engineers help drive, make suggestions, and they often critique or commend my driving. There are a lot of people in this minivan, sometimes there&#8217;s a lot of yelling about what to do next. All the activity does make for quite a bit of fun, even if it gets a bit distracting at times.</p>

<p>I get to drive. As I mentioned, sometimes the analysts and engineers have their hand on the wheel and help push the pedals for me. This is pretty fun too, unlike the car though, this actually gives us a lot more control. We seem to be getting places in a much more controlled way, though we do have to control our speed much more carefully. It might take us longer, but the drive is fun along the way.</p>

<p>Software development in this style takes away some of my freedom as a coder. That&#8217;s a bummer in some ways, not as much fun. I like control. Yet, it also lets me focus on my strengths while others worry about talking to customers, making sure we have a plan that does what the customer wants, and while the constant feedback makes it hard to see the big picture, I usually have a lot of warning before I drive off the road or get into a wreck. Overall, this is more fun.</p>

<p>So far, I prefer the &#8220;clown car&#8221;/stuffed minivan to the empty bus. It&#8217;s less bipolar and more slow, steady, and directed.</p>

<p>Cheers.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Mario AI Competition and Perl</title>
    <link rel="alternate" type="text/html" href="http://contentment.org/2009/08/mario-ai-competition-and-perl.html" />
    <id>tag:contentment.org,2009://3.667</id>

    <published>2009-08-17T14:15:30Z</published>
    <updated>2009-08-17T14:45:24Z</updated>

    <summary>Last week, a coworker let me know about this. It’s been on Slashdot and such, but I’m a little behind on my feeds. For some reason, the competition intrigued me so I’ve put together a set of Perl classes that...</summary>
    <author>
        <name>Andrew Sterling Hanenkamp</name>
        <uri>http://andrew.sterling.hanenkamp.com</uri>
    </author>
    
    
    <content type="html" xml:lang="en-us" xml:base="http://contentment.org/">
        <![CDATA[<p>Last week, a coworker let me know about this. It&#8217;s been on Slashdot and such, but I&#8217;m a little behind on my feeds. For some reason, the competition intrigued me so I&#8217;ve put together a set of Perl classes that will allow agents written in Perl to control the Mario AI simulator using the server agent. I considered trying Java, but I started and quickly remembered why I hate Java, so I quit that and wrote this up over the weekend instead. You can fork it and give it a look here.</p>

<ul>
<li><a href="http://github.com/zostay/AI-Mario/tree/master">http://github.com/zostay/AI-Mario/tree/master</a></li>
</ul>

<p>It includes a very stupid and blind robot for testing at this point. However, it is able to get through most levels I&#8217;ve tried on difficulty 0 (though, not many on any higher difficulty). Once you install that and fetch the latest JAR file from the Mario AI competition site:</p>

<ul>
<li><a href="http://github.com/zostay/AI-Mario/tree/master">http://groups.google.com/group/mariocompetition/files</a></li>
</ul>

<p>You can then run an agent via:</p>

<pre><code>java -jar iMario.jar -server on
</code></pre>

<p>to start the server, then:</p>

<pre><code>cd AI-Mario
bin/agent.pl
</code></pre>

<p>This will run the blind Perl agent (named <code>AI::Mario::Agent::Simple</code>) on the same level over and over. A more interesting run might be:</p>

<pre><code>bin/agent.pl --config AI::Mario::Config::Random -o level_difficulty=2
</code></pre>

<p>This will run the same agent through a random series of levels (restarting each time the agent wins or loses) and sets the level difficulty to 2&#8212;which means, the simple agent nearly always loses.</p>

<p>The system is built with Modern Perl (i.e. Moose) and uses POE and POE::Declarative to talk to the Mario AI server agent. You can implement new configuration (to customize how options are set at the start of each run) and agent and set them to run using the arguments available on the CLI.</p>

<p>To write an agent, for example, you just need to create a class that does the <code>AI::Mario::Agent</code> role and implements the required methods.</p>

<ul>
<li><strong>name</strong>: should return the agent name to be sent to the server agent as greetings</li>
<li><strong>reset</strong>: a method called to reset the agent when a simulation is about to start</li>
<li><strong>update</strong>: a method called during each frame, given an observation object (see <code>AI::Mario::Observation</code>) and should set the <code>left</code>, <code>right</code>, <code>duck</code>, <code>jump</code>, and <code>run</code> controls appropriately to keep moving.</li>
<li><strong>fitness</strong>: this is called at the end of the simulation with a fitness report to tell the agent how well it did (see <code>AI::Mario::Fitness</code>)</li>
</ul>

<p>Then, you can run your agent via:</p>

<pre><code>bin/agent.pl --agent MyAgentClass -p foo=1
</code></pre>

<p>where you can pass a series of parameters to the agent constructor using the <code>-p</code> option.</p>

<p>I plan to add a bit more to it, but the interface is mostly set.</p>

<p>I&#8217;m not even sure they&#8217;ll accept a Perl submission, but it seems to be implied by the instructions on the site. I&#8217;ve asked to be sure. If I can confirm that, I&#8217;ll also add a <code>Makefile.PL</code> and such so that the solution can be packaged with all the required libraries to make it run.</p>

<p>I still haven&#8217;t decided whether or not to enter or just goof around, but whatever. :)</p>

<p>Cheers.</p>

<p><strong>Update:</strong> Julian already replied. Yes, Perl submissions would be accepted. I&#8217;ll definitely try to add a submission script which will help build all the requirements to submit.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Goofing Around with HTML 5 Canvas</title>
    <link rel="alternate" type="text/html" href="http://contentment.org/2009/08/goofing-around-with-html-5-can.html" />
    <id>tag:contentment.org,2009://3.666</id>

    <published>2009-08-08T04:53:04Z</published>
    <updated>2009-08-08T05:05:53Z</updated>

    <summary>I was goofing around with HTML 5 canvas for giggles this week. The canvas allows you to draw using JavaScript to a section of the page. HTML 5 defines a “2d” context, which allows you to draw lines, polygons, images,...</summary>
    <author>
        <name>Andrew Sterling Hanenkamp</name>
        <uri>http://andrew.sterling.hanenkamp.com</uri>
    </author>
    
    
    <content type="html" xml:lang="en-us" xml:base="http://contentment.org/">
        <![CDATA[<p>I was goofing around with HTML 5 canvas for giggles this week. The canvas allows you to draw using JavaScript to a section of the page. HTML 5 defines a &#8220;2d&#8221; context, which allows you to draw lines, polygons, images, boxes, etc. You can style your stroke, fill, and shadow, etc. It&#8217;s pretty easy to goof around with. Oh, and if you&#8217;re using Internet Explorer, these won&#8217;t work. You&#8217;re out of luck because Microsoft is too cool for canvas.</p>

<h3>Box Fractal Renderer</h3>

<p>First, I built a box fractal renderer, which are my favorite things to doodle on graph paper.</p>

<p><canvas id="vicsek" style="width:100%;height:200px;background:white"></canvas></p>

<script language="JavaScript">
;(function(){
var canvas = document.getElementById('vicsek');
canvas.width  *= 5;
canvas.height *= 5;
var size = Math.min(canvas.width, canvas.height);
var c = canvas.getContext('2d');

function draw_square(x, y, size) {
    c.fillRect(x, y, size, size);
}

function draw_squares(x, y, size, iter) {
    var draw_next = iter > 0 ? draw_squares : draw_square;
    var next_size = size / 3;
    var next_iter = iter - 1;

    draw_next(x, y, next_size, next_iter);
    draw_next(x + next_size * 2, y, next_size, next_iter);
    draw_next(x, y + next_size * 2, next_size, next_iter);
    draw_next(x + next_size, y + next_size, next_size, next_iter);
    draw_next(x + next_size * 2, y + next_size * 2, next_size, next_iter);
}
draw_squares(0, 0, size, 5);
})();
</script>

<h3>Fractal Coastline</h3>

<p>Then, I played some more with fractals and eventually ended up with this fractal coastline builder. Each view of this will be a little different. Some look more like coastlines than others.</p>

<p><canvas id="coastline" style="width:100%;height:200px;background:white"></canvas></p>

<script language="JavaScript">
;(function(){
var canvas = document.getElementById('coastline');
canvas.width  *= 5;
canvas.height *= 5;
var c = canvas.getContext('2d');

function LinePoint(pos, delta) {
    this.pos   = pos;
    this.delta = delta - 0.5;
}

function Point(x, y) {
    this.x = x;
    this.y = y;
}

var length = Math.random() * 8 + 4;
var line_points = new Array();
for (var i = 0; i < length; i++) {
    line_points.push(new LinePoint(Math.random(), Math.random()));
}
line_points = line_points.sort(function(a, b) { return a.pos - b.pos; });

var start = new Point(0, Math.random() * canvas.height);
var end   = new Point(canvas.width, canvas.height - start.y);

function draw_segments(start, end, iter, coeff) {
    var draw_next = iter > 0 ? draw_segments : draw_segment;
    var last = start;

    var delta = new Point(end.x - start.x, end.y - start.y);
    var det   = Math.sqrt(delta.x * delta.x + delta.y * delta.y);
    var perp  = new Point(-delta.y / det, delta.x / det);

    // console.log("DELTA");
    // console.dir(delta);
    // console.log("PERP");
    // console.dir(perp);
    // console.log("COEFF = " + coeff);

    //console.log("x = " + start.x + ", y = " + start.y);
    for (var i = 0; i < line_points.length; i++) {
        var line_point = line_points[i];

        var x = start.x + delta.x * line_point.pos 
                        + perp.x  * line_point.delta * coeff;
        var y = start.y + delta.y * line_point.pos
                        + perp.y  * line_point.delta * coeff;
        var next = new Point(x, y);
        // console.log("NEXT");
        // console.dir(next);

        //console.log("x = " + x + ", y = " + y + ", line_point.delta = " + line_point.delta);
        draw_next(last, next, iter - 1, coeff / 4);
        last = next;
    }
    //console.log("x = " + end.x + ", y = " + end.y);
    draw_next(last, end, iter - 1, coeff / 4);
}

function draw_segment(start, end) {
    c.lineTo(end.x, end.y);
}

c.strokeStyle = 'black';
c.fillStyle = 'silver';

c.beginPath();
c.moveTo(start.x, start.y);
draw_segments(start, end, 3, 300);
c.lineTo(canvas.width, canvas.height);
c.lineTo(0, canvas.height);
c.lineTo(start.x, start.y);
c.stroke();
c.fill();
})();
</script>

<p>Anyway, just some random goofing off I thought I&#8217;d share.</p>

<p>Cheers.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Time Estimation Sucks</title>
    <link rel="alternate" type="text/html" href="http://contentment.org/2009/07/time-estimation-sucks.html" />
    <id>tag:contentment.org,2009://3.664</id>

    <published>2009-07-29T01:43:22Z</published>
    <updated>2009-07-28T21:19:13Z</updated>

    <summary>From the perspective of myself, a software developer, time estimation always sucks. I believe I’m working in an environment which has a better view of time estimation than those I’ve worked in before, but we still do it and I...</summary>
    <author>
        <name>Andrew Sterling Hanenkamp</name>
        <uri>http://andrew.sterling.hanenkamp.com</uri>
    </author>
    
    
    <content type="html" xml:lang="en-us" xml:base="http://contentment.org/">
        <![CDATA[<p>From the perspective of myself, a software developer, time estimation always sucks. I believe I&#8217;m working in an environment which has a better view of time estimation than those I&#8217;ve worked in before, but we still do it and I think that it&#8217;s sucking is inherent. I&#8217;ll explain why in a minute.</p>

<p>However, I want to say that time estimation is probably essential for project managers, product managers, executives, sales, and the like. For them, perhaps they can provide a barometer giving them a good indication of where things will be in the future. However, I don&#8217;t speak for any of them, I&#8217;m speaking from the selfish position in which I stand (as we all do and would admit when we&#8217;re being honest).</p>

<h3>Time Estimates are Guesses</h3>

<p>A time estimate is, by definition, going to be inaccurate. Until someone finds a prophet willing to use his gift for mundane predictions like, &#8220;How long will this new feature take to implement?&#8221; Or, &#8220;What&#8217;s the timeline on this fix?&#8221; The answer will be wrong. </p>

<p>To a person without the training it may seem like a software developer works magic and comes up with solutions, but that&#8217;s not the case. She&#8217;s merely working through developing an explicit set of directions, logic, and math to allow the computer to do something. However, the complexity of a problem is rarely well-known until you try to work through it. Thus, you don&#8217;t know what problems you are going to run into.</p>

<p>This is further complicated by the fact that you have to work within some framework including programming language, available libraries, code already in built up, customer expectations, code maintainability, solution flexibility, etc. A software developer often has to make decisions and compromises along the way and it&#8217;s not always clear what the ramifications of each of these decisions will have.</p>

<h3>Implied Margin of Error</h3>

<p>All time estimates include an implied, but rarely recorded or even knowable, margin of error. When I estimate the time it will take to do something, I will often say something like, &#8220;Well, since I just did a very similar process in importing that fail for client X, it will take about 2/3rd&#8217;s as much time to do it for client Y since I&#8217;m familiar with the code and added some pieces there to make doing this task easier.&#8221; I&#8217;m implying a narrow margin of error.</p>

<p>On the other hand, I might say, &#8220;Well, the code in that part of the application was not well future-proofed and this will build on there. I may have to do some refactorings, so I&#8217;d say we&#8217;re looking at 2 days, plus or minus a week.&#8221; I&#8217;m even stating it here, the large margin error.</p>

<p>Yet, what if the first task turns out to take 5 times as long as I said, does that mean my margin of error was wrong or does that mean I was operating on incomplete information? </p>

<p>When a meteorologist says, &#8220;50%&#8221; chance of rain, is he wrong when it rains on your house? Or when it doesn&#8217;t? No, it was just an estimate, which is a statistical entity that cannot be analyzed on those terms as a data point. Only after you have a collection of data points that shows that when the meteorologist suggested 50% chance of rain, it actually rained 60% of the time. Then, he&#8217;s been wrong (and even in this analysis, you have to be careful about data bias and all the other statistical issues your analysis may contain).</p>

<h3>Large Estimates</h3>

<p>Getting into the actual business case, we find that making a large time estimate on something will get you into trouble when you make the estimate. </p>

<p>I recall a case when I suggested I was starting on something during the last week of December after Christmas. I broke the task down into all the steps I would have to do to complete the task and concluded that an reasonable estimate of time would be the end of the second week of February. I told this to the executive in charge of the product and he said, &#8220;We&#8217;d really like to be able to tell the clients the start of the third week in January.&#8221; I said, &#8220;No. I don&#8217;t think that&#8217;s reasonable.&#8221; He said, &#8220;We&#8217;d really like to be able to tell the clients the start of the third week in January.&#8221; In other words, &#8220;I don&#8217;t care what your estimate is, this is the estimate we&#8217;ll use.&#8221; My response, &#8220;I will give you something at that time, but it won&#8217;t be finished.&#8221; </p>

<p>In this case, it actually took all the way through April to get it done, largely because the project ended up having twice as many features as originally spec&#8217;d.</p>

<p>As a software developer, I am strongly motivated to report short estimates to avoid pressure from above. Sometimes, however, a long estimate is the only one that will work, but I always expect to be criticized if I give a long estimate on something.</p>

<h3>Short Estimates</h3>

<p>If I end up giving an estimate for a project that actually takes me 2 to 5 times as long to complete, then I&#8217;m in big trouble. These are the times when executives yell at people. Directors and project leads ask you what lessons you&#8217;ve learned, and if someone really gets upset, you have weekly phone calls with someone in HR listening in.</p>

<p>So here&#8217;s where making a long estimate for a short task seems like a good idea. But then, what happened in the last section? There&#8217;s no win in this game.</p>

<h3>Accurate Estimates</h3>

<p>So what happens when you get it dead on? Do you get a big promotion, cigars and cognac with the executives, and a fat bonus? Nope. You just plod on. You might get such if you made a long estimate, got away with it, and then delivered way early, but that might just mean you&#8217;re a good con-artist, not necessarily good at estimating your time.</p>

<h3>What&#8217;s the Answer?</h3>

<p>I don&#8217;t have one for managers. That&#8217;s not my problem, but managing my managers is. So, here&#8217;s the solution (at least what seems to work best for me at this point):</p>

<ol>
<li><p><strong>Communicate frequently with the bosses.</strong> Anyone you know to be a stakeholder in your project should get something from you often enough to keep them in the loop, but not so often they get annoyed. Hard to balance, but in generally you ought to be talking to your supervisor at least once every day, your project/product managers should get information at least twice a week and as much as once every day, and executives should get direct feedback from you once a week if they have a stake.</p>

<p>And if you find out something is really critical to someone, update them as often as your supervisor. If it&#8217;s an emergency or something critical to a sales pitch being made tomorrow, send out an update at every stopping point. </p>

<p>Regular status reports help managers feel in control and you want them to feel in control. If they feel out of control, expect them to blame you for not telling them what was going on.</p></li>
<li><p><strong>Make your guesses as good as you can.</strong> On complex tasks, break the task down as far as you can ahead of time and estimate each piece. Give yourself an explicit margin of error and percentage of accuracy you&#8217;d place on that margin. Sum up the time estimates and margins and use that to present you estimate. Take some time to do this well, don&#8217;t rush and spend more time considering the harder to estimate parts.</p>

<p>When you give your estimate, you might share some or all of this with your supervisor (depending on how well you think he&#8217;ll be able to cope with the information). Don&#8217;t give this to anyone else, but use this information to determine how to talk about it when reporting on your estimate. Use vague, fuzzy language for parts you aren&#8217;t sure about and use concise, direct language on the parts you are pretty sure about.</p></li>
<li><p><strong>Stand by your estimate.</strong> If your boss says, &#8220;Unacceptable,&#8221; or doubts you, listen to them and explain more about your estimate. Especially if you&#8217;ve worked through the time it will take in details, wavering in a moment of doubt is probably not going to serve you or anyone.</p></li>
<li><p><strong>Be flexible.</strong> If the bosses need a shorter estimate for some reason or even expected a longer one, use that to your advantage. If you&#8217;ve done your homework and got it with you, perhaps you can negotiate parts of the spec away that aren&#8217;t as critical in order to cut down on time. Or perhaps there are things you can iron out a little better and get working really well in the time you have. Or perhaps you can use that opportunity at the tail end to get better testing and quality in place.</p></li>
<li><p><strong>Meekness wins when all else fails.</strong> Never ever burn your bridges. When it hits the fan because you prove to be the woeful prophet you are, stand by your mistake, but stay calm. Be humble. You might have a really good idea what went wrong, but your bosses are pointing at something else. Point that out, but don&#8217;t beat them with it if they disagree.</p></li>
</ol>

<p>Other than that, be you. I work really hard to never blame someone for a mistake, even if they made it. I do not tell on fellow employees when they aren&#8217;t doing their job. However, I try to make it a point to point out excellence in my fellows whenever I can. I don&#8217;t feel like it&#8217;s my job to do management (which, in my mind, means correcting and rebuking employees when they fail at something), but pointing out excellence and success is everyone&#8217;s business. If I really appreciate something a fellow developer has done or someone on the business side writing a really great spec, I try to make it a point to say so in conversation. Unfortunately, being the loner that I am, I don&#8217;t think I notice these things as often as I could.</p>

<p>Time estimation sucks, but it&#8217;s pretty much inevitable. The key is understanding why it sucks and how to deal with that.</p>

<p>Cheers.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Weight Loss, My Way</title>
    <link rel="alternate" type="text/html" href="http://contentment.org/2009/06/weight-loss-my-way.html" />
    <id>tag:contentment.org,2009://3.662</id>

    <published>2009-06-25T17:24:04Z</published>
    <updated>2009-06-25T18:59:53Z</updated>

    <summary>Disclaimer: IANAD: I AM NOT A DOCTOR. Please consult one prior to engaging in any attempt at weight loss. I provide no recommendation you do things my way and take no responsibility for your health. Disclaimer 2: I am not...</summary>
    <author>
        <name>Andrew Sterling Hanenkamp</name>
        <uri>http://andrew.sterling.hanenkamp.com</uri>
    </author>
    
    
    <content type="html" xml:lang="en-us" xml:base="http://contentment.org/">
        <![CDATA[<p><strong>Disclaimer:</strong> <em>IANAD: I AM NOT A DOCTOR. Please consult one prior to engaging in any attempt at weight loss. I provide no recommendation you do things my way and take no responsibility for your health.</em></p>

<p><strong>Disclaimer 2:</strong> <em>I am not affiliated with, have never given money to, and have no relationship at all with the <strong>Unnamed Diet System</strong> I have based my diet plan upon. I do not recommend for or against their system, I am just sharing the fact that I my own variation of it and have had success.</em></p>

<p>Since my birthday this year, I&#8217;ve been working to lose a little extra weight. I now weigh around what I did when I was in high school and am still losing. I did this to show solidarity with my wife who wanted to lose a bit, but I needed to do this for myself as well.</p>

<p>Wanting to lose weight presented a few problems for me. First, I can not stand to do what somebody else tells me to do. My wife calls that being &#8220;obstinate-defiant.&#8221; Depending on my mood I usually either say I&#8217;m just selfish or I have a built-in distrust of the crowd. In any case, it was clear that unless I could tweak my plan a bit, I wasn&#8217;t going to be be happy with it. I&#8217;ve ended up tweaking less than I thought I would, but I still can, so there.</p>

<p>My next problem is that I refuse to do cruel or unusual dieting. I&#8217;m not going in for any fad or diet that drastically changes things. I&#8217;m not giving up cookies or eating grapefruit or doing Adkins. Regardless of what science there is or is not backing these things up, anything that changes what I eat is going to make me grumpy. I <em>love</em> food and there is no shame in that. The shame comes in consistently eating more than I need. I also find the idea of using a pill or surgery repulsive (no offense to those who do such, I won&#8217;t). For me, this process is about developing self-control, which means I need to learn to do it and my wife provides enough accountability to that end.</p>

<p>While metabolism and other factors adjust a person&#8217;s dietary needs, failure to consume enough calories to maintain a person&#8217;s current weight will cause a reduction. (Unless, which I suppose is possible, a person&#8217;s body is somehow capable of storing fat, but incapable of using it. I don&#8217;t know if any such disease exists, but I don&#8217;t have it if it does, so it&#8217;s not my problem.) Therefore, my diet plan would have to be something as mundane as journaling what I eat.</p>

<p>Which brings up my next problem, counting calories is too easy and not really addressing the full magnitude of the problem. Because not only should I eat less, but I should encourage myself to eat healthier. The system ought to take other factors into account.</p>

<p>My final problem is that whatever it is I do must be something I can do on a computer. I sit in front of one for around 8-12 hours per day. I can set my computer to remind of things, I can share things between myself and my wife to provide accountability on my computer, and while I like writing down notes, particularly when I&#8217;m brainstorming, I really don&#8217;t want to do all the math we&#8217;re talking about in my head all the time. It&#8217;s too tedious.</p>

<p>Fortunately, my wife <a href="http://terri.hanenkamp.com/ww/">previously</a> went on and successfully completed a plan using <strong>Unnamed Diet System</strong> for which you may have seen ads. This system met all my basic requirements. Yet, other than they way they count points, they don&#8217;t provide any value to me, at least none I would pay for. Fortunately, everything I needed was published at various places on the Internet and I built myself a Google Docs spreadsheet to do it.</p>

<p>I provide a link to a version of it here for anyone interested in weight loss on similar terms. <em>Go re-read the disclaimers again now.</em> I&#8217;ll wait&#8230; Done? Okay, I don&#8217;t recommend this plan to you, but if you find the spreadsheet useful, great. I&#8217;m providing it under a <a href="http://creativecommons.org/licenses/by/3.0/us/">Creative Commons 3.0</a> license. </p>

<ul>
<li><a href="http://spreadsheets.google.com/ccc?key=rEBiFNc8PjWLNtjKepbm00g">Food Points Sheet</a></li>
</ul>

<p>If you have a Google account, you can create a copy of the spreadsheet to use it or you can download it in another format to use with Excel or OpenOffice (I think, haven&#8217;t tried that).</p>

<p>To use it, I first scroll right until I fill in some information about myself. This sets up the basic tolerances for my diet plan based upon sex, age, current weight, height, daily activity, etc. Then scroll back left and log my consumption. Under each meal, the wide column is for a description of the item eaten and the narrow for recording the points. Once I have &#8220;0&#8221; points left for the day, I stop eating. The spreadsheet does have a weekly allowance of extra points that I can use as well to indulge in something or just allow me to consume all the points for a day without worrying about going over by a couple. I use all the points I have for a day unless I&#8217;m really not hungry. This is not a starvation diet, so I try to use up as many of my daily points as possible. I do not worry too much about using or not using the weekly points. I often consume most of them.</p>

<p>The formula for calculating this points is simple, but elegant in that it encourages me to get more fiber and avoid fatty foods, while consuming fewer calories than I need to maintain my weight:</p>

<pre><code>Points = Calories / 50 + Fat (g) / 12 + MIN(Fiber (g) / 5, 1)
</code></pre>

<p>I&#8217;ve been told that <strong>Unnamed Diet System</strong> actually divides Fiber by 4, but whatever. I have embedded a couple calculators in the spreadsheet for the times when I&#8217;m too lazy to do the math in my head.</p>

<p>I weigh myself once a week to track my progress (on a separate spreadsheet).Every 10 pounds, I adjust the chart to the right since the spreadsheet gives one less point per day for each 10 pounds I lose. I also copy the spreadsheet (actually, Terri manages this part) each week and blank it out to use the next week.</p>

<p>Eventually, I should reach my goal weight (I haven&#8217;t really decided what that is). When that happens, I&#8217;ll need to adjust the spreadsheet to deal with maintenance. When that happens, I will give myself more points until my weight stabilizes. I plan to continue recording points for the foreseeable future this way.</p>

<p>Cheers.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Wascally Perl Operators</title>
    <link rel="alternate" type="text/html" href="http://contentment.org/2009/06/wascally-perl-operators.html" />
    <id>tag:contentment.org,2009://3.660</id>

    <published>2009-06-03T03:34:13Z</published>
    <updated>2009-06-03T04:03:58Z</updated>

    <summary>I just finished writing a test that discovered I’d made a rather dumb and (upon looking back) rather obvious mistake in a return value in this Perl application I’m working on. The mistake involves a certain errant combination of return...</summary>
    <author>
        <name>Andrew Sterling Hanenkamp</name>
        <uri>http://andrew.sterling.hanenkamp.com</uri>
    </author>
    
    
    <content type="html" xml:lang="en-us" xml:base="http://contentment.org/">
        <![CDATA[<p>I just finished writing a test that discovered I&#8217;d made a rather dumb and (upon looking back) rather obvious mistake in a return value in <a href="http://qublog.net">this Perl application</a> I&#8217;m working on. The mistake involves a certain errant combination of <code>return</code> and <code>and</code> must be dealt with carefully.</p>

<p>The particular bit of code looks something like this:</p>

<pre><code>sub blah {
    return $foo and $bar;
}
</code></pre>

<p>For those who don&#8217;t know Perl intimately, Perl has two &#8220;and&#8221; operators. One named &#8220;and&#8221; and the other named &#8220;&amp;&amp;&#8221; like C. These are not strict synonyms. They are both shortcut operators, but the &#8220;&amp;&amp;&#8221; and the &#8220;and&#8221; sit at very different places in the operator precedent order. In Perl &#8220;&amp;&amp;&#8221; has a relatively high precedent and &#8220;and&#8221; is very, very low.</p>

<p>Back to the problem: this return was returning true when <code>$foo</code> was true and <code>$bar</code> was false. After rereading this line I smacked my forehead and said, &#8220;Duh!&#8221; The problem is that &#8220;return&#8221; actually has a higher operator precedent than &#8220;and&#8221; so this is how Perl would break it out if it showed the AST with parenthesis:</p>

<pre><code>sub blah {
    (return $foo) and ($bar);
}
</code></pre>

<p>This means the code immediately return <code>$foo</code> in all circumstances. I might as well have just written:</p>

<pre><code>sub blah {
    return $foo;
}
</code></pre>

<p>The solution, then, is to either use the &#8220;&amp;&amp;&#8221; operator:</p>

<pre><code>sub blah {
    return $foo &amp;&amp; $bar;
}
</code></pre>

<p>Or use explicit parenthesis:</p>

<pre><code>sub blah {
    return ($foo and $bar);
}
</code></pre>

<p>Or don&#8217;t use the &#8220;return&#8221; operator (since subroutines in Perl always return the value of the last expression executed):</p>

<pre><code>sub blah {
    $foo and $bar;
}
</code></pre>

<p>Cheers.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Converting from iTunes to Banshee</title>
    <link rel="alternate" type="text/html" href="http://contentment.org/2009/05/converting-from-itunes-to-bans.html" />
    <id>tag:contentment.org,2009://3.659</id>

    <published>2009-05-22T23:12:40Z</published>
    <updated>2009-06-02T20:17:17Z</updated>

    <summary>This past week I purchased for myself a mini laptop. I wanted something nice and portable that I could use for personal use on trips and do hobby projects on. This thing is great. I got Ubuntu installed and started...</summary>
    <author>
        <name>Andrew Sterling Hanenkamp</name>
        <uri>http://andrew.sterling.hanenkamp.com</uri>
    </author>
    
    
    <content type="html" xml:lang="en-us" xml:base="http://contentment.org/">
        <![CDATA[<p>This past week I purchased for myself a mini laptop. I wanted something nice and portable that I could use for personal use on trips and do hobby projects on. This thing is great. I got Ubuntu installed and started playing around since it&#8217;s been a couple years since I had a Linux desktop, and even then I usually had a Mac OS X laptop I used with it. As such, when it came to copy over my music and such, I needed to convert to a new music player. I&#8217;ve settled on <a href="http://banshee-project.org/">Banshee</a> for the moment.</p>

<p><strong>Problem:</strong> There&#8217;s no import tool out there to go from iTunes to the current version of Banshee. </p>

<p><strong>Solution:</strong> However, the process turned out to be not so hard for me. Here&#8217;s what I did:</p>

<ol>
<li>Copied the iTunes music folder from my Mac to the music folder on my new laptop.</li>
<li>Started up Banshee and used Media > Import Media&#8230; to tell Banshee where to find all the files and let it do it&#8217;s thing.</li>
<li>Went back into iTunes on my old machine and used File > Library > Export Library&#8230; to generate a <code>Library.xml</code> file, which I copied to the new laptop</li>
<li>Ran a Perl script I wrote to pull out the play lists, song play counts, last play date, and ratings and push them into the Banshee database</li>
</ol>

<p>Fortunately the <code>Library.xml</code> file output by iTunes is in a standard format that is pretty easy to understand. Also, Banshee keeps much of the information about your music and such in a SQLite database. So, I could very easily automatically copy over all the ratings and other information I&#8217;ve been assembling for the past several years.</p>

<p>Here&#8217;s the conversion script, <code>itunes-to-banshee.pl</code> that I wrote for download:</p>

<p><span class="mt-enclosure mt-enclosure-file" style="display: inline;"><a href="http://contentment.org/files/itunes-to-banshee.pl">Download itunes-to-banshee.pl</a></span></p>

<p><strong>Update (thanks to Rolo):</strong> You will need to install a few dependencies as well. On Debian or Ubuntu, this is done by installing:</p>

<ul>
<li>libdatetime-perl </li>
<li>libdatetime-format-iso8601-perl </li>
<li>libclass-dbi-sqlite-perl</li>
<li>libxml-twig-perl</li>
<li>libmime-base64-perl</li>
</ul>

<p>This can be done from Synaptics or by running this on the command-line:</p>

<pre><code>sudo apt-get install libdatetime-perl libdatetime-format-iso8601-perl \
    libclass-dbi-sqlite-perl libxml-twig-perl libmime-base64-perl
</code></pre>

<p>Once Banshee has finished adding your song files to its music library, close Banshee. Make a backup copy of <code>banshee.db</code> to somewhere in case something goes wrong (which can be found at <code>~/.config/banshee-1/banshee.db</code>). Then run:</p>

<pre><code>perl itunes-to-banshee.pl Library.xml ~/.config/banshee-1/banshee.db
</code></pre>

<p>This may take a few minutes, depending on how many songs you have. It might show you some warnings if your <code>Library.xml</code> is weird (remember I wrote this just for me). It may also tell you if it can&#8217;t find some songs in Banshee that it found in your <code>Library.xml</code>. (It did for me because I&#8217;d deleted some songs from the disk and iTunes never figured it out.)</p>

<p>Once it finishes, start Banshee back up and it should have the play lists, ratings, play counts, and last played date set for all the songs that had such information in iTunes.</p>

<p>There are a couple things you might want to know about how the program works. First, it does not touch smart play lists. I don&#8217;t know and don&#8217;t particularly care how to read the smart playlist configuration from iTunes. I was able to recreate the smart play lists I had in a few minutes.</p>

<p>Second, the import script uses the song title and song file size to match songs from the iTunes library in the Banshee library. This is probably safe since I&#8217;ve never seen two CDs with the same songs on them end up being the same size, but it&#8217;s theoretically possible it could be a problem.</p>

<p>Third, if you have duplicates in your library, this script will only change one of them. I&#8217;d recommend weeding those out first.</p>

<p>I&#8217;m not interested in maintaining the script, but I&#8217;ll answer questions about it. If you ask really nicely and I&#8217;m in a good mood and the change you want is very small, I might be willing to make it, but that&#8217;s a lot of &#8220;ifs&#8221; to line up.</p>

<p>Cheers.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>The Best Way to Add Icons</title>
    <link rel="alternate" type="text/html" href="http://contentment.org/2009/05/the-best-way-to-add-icons.html" />
    <id>tag:contentment.org,2009://3.657</id>

    <published>2009-05-13T23:00:00Z</published>
    <updated>2009-05-13T19:33:50Z</updated>

    <summary>With my work on qublog.net continuing to progress toward hosting this service on the qublog.net web site. I’ve been using the silk icon set for the icons, but recently decided to switch over to the fugue icons. In the process,...</summary>
    <author>
        <name>Andrew Sterling Hanenkamp</name>
        <uri>http://andrew.sterling.hanenkamp.com</uri>
    </author>
    
    
    <content type="html" xml:lang="en-us" xml:base="http://contentment.org/">
        <![CDATA[<p>With my work on <a href="http://qublog.net">qublog.net</a> continuing to progress toward hosting this service on the qublog.net web site. I&#8217;ve been using the <a href="http://www.famfamfam.com/lab/icons/silk/">silk icon set</a> for the icons, but recently decided to switch over to the <a href="http://www.pinvoke.com/">fugue icons</a>. In the process, I rethought how I added icons to the system, which I subsequently chose to try on some work things as well. There&#8217;s no magic here, nothing to patent (at least I hope not), but it&#8217;s worked pretty well, so I&#8217;ll share. I suppose this might not be &#8220;The Best Way&#8221;, but it&#8217;s certainly now &#8220;My Best Way.&#8221;</p>

<p>First, these icons are all being added without IMG-tags. This keeps my content less cluttered and allows me to very quickly switch icons if I change my mind later just be changing my stylesheet. Typically, these are added to buttons, links, and spans like so:</p>

<pre><code>&lt;span class="icon o-time"&gt;12:44 PM&lt;/span&gt;
&lt;a class="icon v-add o-task"&gt;Create Task&lt;/a&gt;
&lt;input type="submit" class="icon v-save o-time" name="op" value="Save"/&gt;
</code></pre>

<p>The first class &#8220;icon&#8221; performs the work of making sure the icon itself is attached to the element properly. This looks like:</p>

<pre><code>.icon {
    padding-left: 18px;
    background-repeat: no-repeat;
    background-position: 1px 1px;
    min-height: 18px;
}
</code></pre>

<p>This basically makes sure that my 16 pixel icon has 1 pixel of space around it and makes sure the element is at least tall enough not to cut anything off.</p>

<p>Then, the icon itself is chosen by examining the other associated classes. I&#8217;ve divided the classes into nouns (with an &#8220;o-&#8221; prefix), adjectives (with an &#8220;a-&#8221; prefix), verbs (with a &#8220;v-&#8221; prefix), and adverbs (with a &#8220;r-&#8221; prefix). I define these classes within the style sheet in that order so that adjectives will override nouns, verbs override both nouns and adjectives, and adverbs will override everything. So, now my style sheet looks something like this:</p>

<pre><code>.o-task { background-image: url(ticket.png) }
.o-time { background-image: url(clock.png) }

.a-group { background-image: url(folder.png) }
.o-task.a-project { background-image: url(briefcase.png) }

.v-add { background-image: url(plus.png) }
.v-add.o-task { background-image: url(ticket__plus.png) }
.v-add.o-task.a-project { background-image: url(briefcase__plus.png) }
</code></pre>

<p>By setting up the style sheet this way, a regular task reference shows up with a ticket icon. However, a project (which is a kind of task in Qublog) shows up as a briefcase. In case I need a generic add link, I can use a lone plus sign, but if I want a specific add link for tasks I can have a ticket with a plus sign. Finally, I can add a new project with a briefcase with a plus sign.</p>

<p>Later, if I want to modify the icons used, I can do so by just adding another class or something. It&#8217;s pretty flexible and if I make sure and include enough information on every link, span, or button that might have icon, I can make my icons more or less particular later just be adding a line or two to my style sheet. (For example, if my icon set lacked a briefcase with a plus next to it and then added one or I created one, then I could add that last rule later and rely on the ticket with a plus sign in the meantime.)</p>

<p>Some final varations I also use are things like having the icon only and ignoring the text itself:</p>

<pre><code>.icon.only {
    display: inline-block;
    overflow: hidden;
    white-space: nowrap;
    width: 0;
}
</code></pre>

<p>Now I can add the &#8220;only&#8221; class to my spans and links and the text becomes hidden. I combine this with a jQuery code similar to this:</p>

<pre><code>jQuery(document).ready(function() { 
    jQuery('.icon.only').each(function(){
        jQuery(this).attr('title', jQuery(this).text());
    });
});
</code></pre>

<p>This causes the text of the element itself to show up as a tooltip when you hover your mouse over the icon. Generally speaking, though, I usually try to do this on the server side when I use the &#8220;icon only&#8221; classes.</p>

<p>I have a few other &#8220;icon&#8221; class variants for changing the position of the icon, dealing with small 9-pixel icons, and making sure buttons and specific other things look good with the icons, but I&#8217;ll leave these as exercises for the reader.</p>

<p>Cheers.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Mutator Defaults: The Wrong Way</title>
    <link rel="alternate" type="text/html" href="http://contentment.org/2009/03/mutator-defaults-the-wrong-way.html" />
    <id>tag:contentment.org,2009://3.653</id>

    <published>2009-03-03T03:35:20Z</published>
    <updated>2009-03-03T03:57:23Z</updated>

    <summary>I’m messing around with Drupal again for a church web site. The task I’m working with at the moment is trying to make it so that the breadcrumb is based upon a menu other than than that Navigation menu (which...</summary>
    <author>
        <name>Andrew Sterling Hanenkamp</name>
        <uri>http://andrew.sterling.hanenkamp.com</uri>
    </author>
    
    
    <content type="html" xml:lang="en-us" xml:base="http://contentment.org/">
        <![CDATA[<p>I&#8217;m messing around with Drupal again for a church web site. The task I&#8217;m working with at the moment is trying to make it so that the breadcrumb is based upon a menu other than than that Navigation menu (which is the normal way content breadcrumbs are set in Drupal). Long story short, we&#8217;ve chosen to make the Primary Links the site map rather than the more typical Navigation menu.</p>

<p>The technique that really ought to work is this:</p>

<pre>
menu_set_active_menu_name('primary-links');
$breadcrumb = menu_get_active_trail();
drupal_set_breadcrumb($breadcrumb);
</pre>

<p>That&#8217;s simple enough, but it doesn&#8217;t work. At least, it doesn&#8217;t work unless it gets called at some point very early in the request life cycle. After some digging through the <a href="http://api.drupal.org/">Drupal API</a>, I found that <code>menu_get_active_trail()</code> is actually defined like this:</p>

<pre>
function menu_get_active_trail() {
  return menu_set_active_trail();
}
</pre>

<p>I vaguely remembered this from a year ago when I was last mucking with Drupal. This is a pretty common Drupal idiom. It&#8217;s basically the Drupal developer&#8217;s way of using the mutator (i.e., <code>menu_set_active_trail()</code>) simultaneously as a accessor and default setting. That&#8217;s fine. However, when you look into <code>menu_set_active_trail()</code> I found something wrong. The code looks like this (minus some code that I don&#8217;t want to spew here):</p>

<pre>
function menu_set_active_trail($new_trail = NULL) {
  static $trail;

  if (isset($new_trail)) {
    $trail = $new_trail;
  }
  elseif (!isset($trail)) {
    // LOTS OF CODE HERE TO CONFIGURE THE DEFAULT
    // BASED UPON THE OUTPUT OF menu_get_active_menu_name()
  }
  return $trail;
}
</pre>

<p>Do you see the problem? If you happen to set the value returned by <code>menu_get_active_menu_name()</code> (via <code>menu_set_active_menu_name()</code>) in time, you can get it to setup your breadcrumb using some fairly smart code that does the right thing for you. </p>

<p>However, if you don&#8217;t set it before the first call to <code>menu_set_active_trail()</code>, you can <strong>never</strong> run that helpful default code ever again. There&#8217;s no way to unset <code>$trail</code> because <code>$new_trail</code> is ignored if it is unset. There&#8217;s no way to execute the default code without unsetting <code>$trail</code> since it&#8217;s all within this single function.</p>

<p>Bah! The correct solution is to move the default code into a separate method so that it can be called separately later and reused.</p>

<p>My work-around will probably be to install the <a href="http://drupal.org/project/menu_breadcrumb">Menu Breadcrumb</a> module. I&#8217;m trying to keep the number of modules installed on this particular site very low, so I was hoping to avoid it. Yet, installing a module is going to work out better than me reinventing the wheel with a module of my own, in this case. It&#8217;s these little frustrations that drove me away from Drupal in my personal site. I&#8217;m probably being too picky and hypocritical, but whatever.</p>

<p>Cheers.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Dabbling in Git</title>
    <link rel="alternate" type="text/html" href="http://contentment.org/2008/10/dabbling-in-git.html" />
    <id>tag:contentment.org,2008://3.631</id>

    <published>2008-10-23T11:00:00Z</published>
    <updated>2008-10-23T14:45:08Z</updated>

    <summary>Recently, I started trying out git to see what the relative advantages and disadvantages of it are over Subversion, SVK, and CVS. I am not quite ready to give up the use of Subversion as the mechanism for sharing my...</summary>
    <author>
        <name>Andrew Sterling Hanenkamp</name>
        <uri>http://andrew.sterling.hanenkamp.com</uri>
    </author>
    
    
    <content type="html" xml:lang="en-us" xml:base="http://contentment.org/">
        <![CDATA[<p>Recently, I started trying out git to see what the relative advantages and disadvantages of it are over Subversion, SVK, and CVS. I am not quite ready to give up the use of Subversion as the mechanism for sharing my projects with others, if only for the fact that I know more programmers familiar with it than with git (and also for the fact that my web host provides built-in support for Subversion, not git, at this time). Therefore, I&#8217;m actually using git as the front-end to access my Subversion repositories, which is quite similar to how I use SVK (and the normal model for SVK use).</p>

<p>The first difference I had to deal with was simply that the command-line is just a bit different. So, I had to map various ideas in Subversion/SVK/CVS into git before I could use it very successfully. Now that I&#8217;m using it comfortably, I&#8217;m certain I like it better than anything I&#8217;ve yet tried and will likely continue to use it over SVK, which was my preference up until now. On the other hand, I don&#8217;t think I&#8217;ll ever completely give up using Subversion, SVK, or CVS entirely unless and until they become obsolete tools that no one is using.</p>

<h3>Adding Changes</h3>

<p>Why do I like git over the alternatives? First, it helps protect me from common mistakes. For example, one thing that annoyed me at first is that you have to add any files you change to the list to be committed before committing.</p>

<pre><code>% git add lib/Net/Google/PicasaWeb.pm
% git commit
</code></pre>

<p>That seemed a little annoying compared to how SVK lets you commit with a single &#8220;svk commit&#8221; command and select which files to commit by editting the commit message. Yet, once I got used to it, I realized that I rarely ever have to back out a mistakenly committed file. It only commits those you explicitly ask for. If you&#8217;re sure you want to commit everything, you can add whole directories or use the <code>-a</code> switch to commit, but the fact that you have to explicitly make these decisions rather than just committing whatever makes it difficult to make mistakes in what you commit (unless you are in hurry).</p>

<h3>Commit by Hunk</h3>

<p>Next, I can commit only parts of a file. This feature blew my mind. This should be a mandatory feature for any source code storage system. When I&#8217;m making a complex set of changes, but don&#8217;t make intermediate commits for whatever reason (laziness, forgot, not sure if what I&#8217;m doing in one part really serves the whole yet, etc.), I can perform an interactive patch.</p>

<pre><code>% git add -p
% git commit
</code></pre>

<p>When running add with the <code>-p</code> switch, you will iterate through all the listed files (or in this case, all files changes in the repository), and be shown the diff. You can then add individual hunks from the diff to the commit or not. On the latest release of git, you can even edit the diff to pick out individual lines from the hunk to stage and leave the rest out for the moment. This is a killer feature.</p>

<h3>Tracking Patches, Not Files</h3>

<p>Another nice feature has to do with how git manages to deal with tracking changes. In Subversion, SVK, and CVS the most important unit to work with is the code itself. However, with git, the most important unit to work with is the diff of how the code changed from one commit to the next. </p>

<p>What do I mean? As an example, if I take a project and branch it to work on some complicated feature while the trunk continues to move forward. Then, I merge them when I am done, Subversion, SVK, and CVS handle the merge by diffing the branch with the trunk and then putting all the changes together in a single revision. These will use the history of the trunk and branch in various ways to help resolve problems, but they essentially treat a merge as a single diff. (SVK is a partial exception if you use the &#8220;-I&#8221; option during merges.) </p>

<p>With git, all the changes of the merge are copied over to the top of the trunk and then you deal with conflicts one diff at a time. This way the entire history gets pulled over from the branch onto top of the trunk, as if the work had been done from the top of the trunk in the first place. You take a little extra time to &#8220;rewrite history&#8221; this way, but it makes your patches a little more logical.</p>

<p>This same handling of patches works all over the place. For example if you just want to take advantage of some new features placed on the trunk, you can do something called a &#8220;rebase&#8221; rather than a &#8220;merge.&#8221; This is the same process as the merge, except all the patches remain on the same branch.</p>

<pre><code>% git rebase master
</code></pre>

<p>You can even move the entire branch to a different base point if you want to try your branch out using features still in progress on a different branch:</p>

<pre><code>% git rebase --onto bar master foo
</code></pre>

<p>The above command would move all the changes on branch &#8220;foo&#8221; on to branch &#8220;bar&#8221; as if these changes had been written for &#8220;bar&#8221; originally.</p>

<p>Under SVK or Subversion, a merge would be done by pulling in the latest trunk changes over into the branch. This adds a the trunk changes into the middle of your branch as either an individual commit (or as a set of commits with &#8220;-I&#8221; in SVK).</p>

<h3>Work in Progress</h3>

<p>Have you ever tried out some code changes and then realized they weren&#8217;t going to get you where you want to go? At the same time, though, there are some good ideas here that you don&#8217;t want to just throw away. In Subversion you might create a special branch to hold them, but probably not. In SVK, you might create a local branch or something to hold work in progress, but again, probably not.</p>

<p>In git, you can just run:</p>

<pre><code>% git stash
</code></pre>

<p>This takes all of the changes you&#8217;ve just made and stores them quickly in a special stash. You can then see the stash and recover the latest stashed item using:</p>

<pre><code>% git stash list
% git stash apply
</code></pre>

<p>There are a few other commands with the stash as well that are handy, but these are the ones I use most.</p>

<p>Those are a few of the reasons why I really like git. On the other hand, there are some aspects of SVK that are nice, such as the fact that it is very easily extended using Perl (since SVK is written in Perl and written for extensibility). I&#8217;ve been thinking about looking into adding features like these into SVK as a fun exercise since I&#8217;ve been playing with git. I sure don&#8217;t have time to do any of the other of the fun projects I do on my own time, so why not?</p>

<p>Cheers.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Android and Development Tools</title>
    <link rel="alternate" type="text/html" href="http://contentment.org/2008/10/android-and-development-tools.html" />
    <id>tag:contentment.org,2008://3.636</id>

    <published>2008-10-21T23:20:00Z</published>
    <updated>2008-10-21T20:18:04Z</updated>

    <summary>I think if I had my way, I would develop tools for developers most of the time. This would be a good implementation of Yegge’s “only build stuff for yourself” principle. The Android project catches my eye because it offers...</summary>
    <author>
        <name>Andrew Sterling Hanenkamp</name>
        <uri>http://andrew.sterling.hanenkamp.com</uri>
    </author>
    
    
    <content type="html" xml:lang="en-us" xml:base="http://contentment.org/">
        <![CDATA[<p>I think if I had my way, I would develop tools for developers most of the time. This would be a good implementation of Yegge&#8217;s &#8220;<a href="http://steve-yegge.blogspot.com/2008/08/business-requirements-are-bullshit.html">only build stuff for yourself</a>&#8221; principle. The <a href="http://source.android.com/">Android project</a> catches my eye because it offers the possibility of being able to get rid of the Microsoft OS on my phone without having to buy a new phone. However, after looking at the site, I&#8217;m now more interested in the tools they&#8217;ve put together to aid this development.</p>

<p>The first is a tool called &#8220;<a href="http://source.android.com/submit-patches">repo</a>&#8221;. It&#8217;s somewhat similar to a tool we use at work for managing our source repositories. It basically adds some higher level niceties to git and helping connect with code reviews. In addition, it interacts with a nice web-based UI for code reviews they&#8217;ve called &#8220;<a href="http://review.source.android.com/">garrit</a>&#8221;. </p>

<p>Garrit is kind of like a ticket tracker for submitting patches and works almost in reverse of the usual ticket tracker. Normally, you post a problem and then put together a solution. This tool lets you submit a solution and then lets the reviewers determine whether it&#8217;s a good idea or not. This is important for a project like Android where it will likely be common for someone to write a patch to get Android working for his particular phone or app and then submit it to the community for general inclusion. It supports the git model for development pretty well.</p>

<p>Anyway, I&#8217;m interested in Android and hope some smart folks with better C skills than me can make it work on my phone in the near future, but in the meantime, I think dev tools present some interesting ideas on their own.</p>

<p>Cheers.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>CPAN To Go</title>
    <link rel="alternate" type="text/html" href="http://contentment.org/2008/10/cpan-to-go.html" />
    <id>tag:contentment.org,2008://3.634</id>

    <published>2008-10-20T21:53:44Z</published>
    <updated>2008-10-20T22:10:57Z</updated>

    <summary>I don’t travel away from a network very often, particularly now that I have an EVDO card. However, it is inevitable that when am away from a network (on a plane, in snow storm, on the road) I want to...</summary>
    <author>
        <name>Andrew Sterling Hanenkamp</name>
        <uri>http://andrew.sterling.hanenkamp.com</uri>
    </author>
    
    
    <content type="html" xml:lang="en-us" xml:base="http://contentment.org/">
        <![CDATA[<p>I don&#8217;t travel away from a network very often, particularly now that I have an EVDO card. However, it is inevitable that when am away from a network (on a plane, in snow storm, on the road) I want to try out a CPAN module or need one that I haven&#8217;t yet installed. When this happens and I can&#8217;t do whatever it was that I wanted to do because I didn&#8217;t have it, I get grumpy. However, thanks to <a href="http://search.cpan.org/dist/CPAN-Mini/">CPAN::Mini</a>, I don&#8217;t have to worry about this problem anymore.</p>

<pre><code>% sudo cpan CPAN::Mini
% mkdir -p ~/projects/minicpan
</code></pre>

<p>That installs the module itself and sets up the directory for the local repository. Then, I added a nice alias to my shell config:</p>

<pre><code>alias cpansync="minicpan -l $HOME/projects/minicpan -r http://ftp.osuosl.org/pub/CPAN/"
</code></pre>

<p>I picked the OSL mirror here since I happen to know the man responsible for admin&#8217;ing that mirror. I can then run this to get a copy of the latest and greatest on CPAN:</p>

<pre><code>% cpansync
</code></pre>

<p>After that runs, I can run it again any time I want to refresh, which I usually do right before I travel and any other time I want a fresh copy.</p>

<p>Finally, I modified the list of CPAN mirrors to include:</p>

<pre><code>file:///home/sterling/projects/minicpan
</code></pre>

<p>Now, whenever I install modules, the modules are installed directly from my hard drive. This is also a bit faster than having to download the modules at install time (i.e., as long as I have already done the download previously).</p>

<p>This setup makes me happy, especially when on airplanes.</p>

<p>Cheers.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Pittsburgh, Perl, and Working in Shops</title>
    <link rel="alternate" type="text/html" href="http://contentment.org/2008/10/pittsburgh-perl-and-working-in.html" />
    <id>tag:contentment.org,2008://3.630</id>

    <published>2008-10-13T02:36:42Z</published>
    <updated>2008-10-13T04:53:14Z</updated>

    <summary>I found out about the fact that I would be giving two talks at the Pittsburgh Perl Workshop this week about 2 weeks ago and have been working frantically to get my stuff together since. Well… at least, I worked...</summary>
    <author>
        <name>Andrew Sterling Hanenkamp</name>
        <uri>http://andrew.sterling.hanenkamp.com</uri>
    </author>
    
    
    <content type="html" xml:lang="en-us" xml:base="http://contentment.org/">
        <![CDATA[<p>I found out about the fact that I would be giving two talks at the Pittsburgh Perl Workshop this week about 2 weeks ago and have been working frantically to get my stuff together since. Well&#8230; at least, I worked frantically for the last week. The first week, was not quite frantic. It was more like somewhat diligent, but I did spend a couple nights playing Zelda that should have been spent prepping. Anyway, I got my talks done and I don&#8217;t think they were particularly excellent, but I don&#8217;t think they went badly (at least, I hope they didn&#8217;t). But, this post isn&#8217;t really about my talks so much as it is about debriefing PPW 2008. On to the festivities&#8230;</p>

<h3>Travel To</h3>

<p>It all started on a completely average Friday morning of packing&#8230; okay, skipping ahead. I flew to Pittsburgh through Milwaukee. In Milwaukee, I was supposed to take a late flight from there, but that wasn&#8217;t supposed to me I took off from Milwaukee after midnight. However, the flight the airplane hadn&#8217;t even taken off yet from <em>Dallas</em> when we landed. So, I worked more on my slides which weren&#8217;t quite finished while I waited. And waited. Finally, the plane arrived and took me to Pittsburgh, where I landed around 2am. </p>

<p>Strange thing about the flight, though. There were only 5 actual passengers on an Embraer 170. For those of you that aren&#8217;t airplane fanatics (like me), that&#8217;s a plane that seets about 70. There were two flight attendants, the pilot and copilot, and another 4 or 5 airline personnel catching a ride to Pittsburgh. That&#8217;s all.</p>

<p>I was the only one that had a checked bag. Uh-oh. When I got off the plane, a baggage handler was asking each of the 5 real passengers if they checked a bag and I said, &#8220;Yes.&#8221; He said he&#8217;d meet me at baggage claim. He met me there, but with no bag. It was lost. Poop. I almost never check a bag and this time I did. Dumb. Oh well.</p>

<p>So, I catch a cab and go on to the hotel and finally get to sleep sometime after 3am.</p>

<h3>PPW Saturday</h3>

<p>My phone alarm woke me up around 7am. Yeesh. I felt like something scraped off the bottom the mattress, but I got up and showered and got some coffee. I am in a hotel about 1.5 miles from the conference, so I figured I walked. I think this was a good thing as it helped me wake up a bit and it has been a glorious weekend in Pennsylvania. I stopped off to get some antiperspirant and some Listerine breath strips to minimize in odious scents I might be emitting since I was lacking my toiletries.</p>

<p>I made it to Wean Hall on CMU campus and promptly picked up my conference T-shirt and took it to the bathroom to exchange it for the mildly damp shirt I had been wearing that had probably picked up odors from a shuttle bus, three airports, two airplanes, and a cab, not to mention a 35 minute walk on a warm morning with a 30 pound backpack. Okay, so with new shirt donned and odor opposing chemicals applied to my underarms and mouth, I went in to the keynote on Perl 6 in progress.</p>

<h4>Perl 6</h4>

<p>The keynote was by Patrick Michaud and the news for Perl 6 is good! Yay! For anyone who has followed the drama of Perl 6, you know that some of the history hasn&#8217;t necessarily been positive. However, it sounds like things might actually be moving on the right track now. The final release of Perl 6 still expected on Christmas, as it has been for at least a couple years now. But, given Patrick&#8217;s report, it sounds like it might actually be a Christmas before my son starts elementary school. (I wasn&#8217;t always sure of that.)</p>

<h4>Bug Labs</h4>

<p>After the first talk, a company called <a href="http://buglabs.net/">Bug Labs</a> gave a presentation. It was kind of an odd talk I thought since it really didn&#8217;t have much to do with Perl (existing APIs are Java), but it was more of a suggestion that Perl hackers <em>could</em> get involved. I&#8217;m a bad candidate for that. The product itself looked like an interesting diversion, but nothing I&#8217;d be willing to sink that much cash into. I&#8217;m not so much a hardware guy anyway.</p>

<p>My personal feelings aside, I have some doubts about the business plan of Bug Labs. It&#8217;s nice that they support Open Source, but the viability of the business model is a little questionable to me. The presenter kept saying they wanted to make it so easy that &#8220;your mom&#8221; could come up with a custom device. First, my mom is not likely to care about a device unless it comes prefab with as few buttons as possible. Second, my mom is not going to put down that kind of cash just so she can create some sort of customized web-cam/motion-sensor/GPS something-or-other. She has better things to do. I suspect she didn&#8217;t mean my mom literally, but that doesn&#8217;t mean my statements are any less valid for the hypothetically average mom either.</p>

<h4>SQLite Extensions</h4>

<p>After that was a talk on extending SQLite, which I admit I paid very little attention to because I was still trying to finish my slides for my first talk on Sunday. I thought this sounded interesting and it would be nifty to have more of that in some of the code we do at work, but since we don&#8217;t use SQLite for the work I&#8217;m thinking of, the talk doesn&#8217;t really apply to that. </p>

<h4>Data::Rx</h4>

<p>Ricardo Signes then gave a talk on something I&#8217;d never heard of before, Rx, but I think I&#8217;m going to check out. He&#8217;s basically put together a data validation system similar to XSD or RELAX-NG, but for general data structures in memory. It&#8217;s a really cool idea and I want to see what I might be able to gain from it, so it&#8217;s on my short list of things to try out in the near future. The fact that he&#8217;s got implementations for it in Ruby, Python, and PHP is also very interesting for interoperability.</p>

<h4>Lunch</h4>

<p>Next was lunch where I met <a href="http://www.klein.com/dvk/">Dan Klein</a>, a fellow consultant for Grant Street, in person for the first time and had a pretty mediocre chicken marsala, but an excellent salad with fetta cheese, roasted almonds, and strawberries with a raspberry vinaigrette.</p>

<h4>Advanced Pattern Matching</h4>

<p>Paul Grassie, another co-consultant, gave a talk on regexes, which I again confess I mostly missed to work on my own talk. What material I did catch was a good review and there were bits that were somewhat new, but I wasn&#8217;t paying close enough attention to really learn them.</p>

<p>By the way, Paul and Dan work for <a href="http://training.perl.com">Tom Christiansen Perl Consultancy</a>. Given what I know of them now (having seen Paul in action and spent part of a day with Dan), I&#8217;d recommend their services if you have some need of Perl training for your company.</p>

<h4>Network Introspection</h4>

<p>This talk I almost completely ignored. There were some things in it that were interesting, but it was mostly for the sysadmins. I was familiar with and impressed with some of what was presented, but I did the system administrator thing already and have turned a new leaf. I&#8217;m not going back to the land of putting out fires in the world of hardware.</p>

<h4><strike>R</strike>DBMS</h4>

<p>The next talk was on a database tool called Kioku::DB, which is an interesting idea and something I&#8217;m glad to be aware, but not something that will change the way I do my work or hobbies. Again, I&#8217;m still working on slides as I glance up now and then and this didn&#8217;t really capture my attention.</p>

<h4>Email Hates the Living!</h4>

<p>Finally, Ricardo gave his second talk of the day on Email. Having myself engaged in mortal combat against the spam monster at one of my first tech jobs and having been a systems administrator, this talk was flipping hilarious. His analysis on the insanity of email and the email specs is right on. For example, &#8220;asdf@!#$&amp;&#8221; is a valid email address within the To: or From: line of your email, even though such an email couldn&#8217;t possibly be delivered. Yet, &#8220;asdf@!#$&amp;.&#8221; is not. Stupid. It&#8217;s a great talk and helps to explain why his CPAN repository is filled with email code, when it doesn&#8217;t seem like it should really be quite that hard.</p>

<h4>Dinner and Sleep</h4>

<p>After that, the Grant Streeters still around headed out for dinner where there was some lively discussion of work and politics. Then, I went back to the hotel room and came up with a Lightning talk, did the final clean up on my slides, and then tried to get more sleep.</p>

<h3>The Saga of the Missing Bag</h3>

<p>I haven&#8217;t finished the story about my bag. Early Saturday, I called Midwest Airlines to find out about my bag. As I mentioned, mine was to be the only checked bag and the handler that I talked to couldn&#8217;t find it. He made me out a claim for the bag and said it would be delivered as soon as he could get it to me.</p>

<p>When I called Midwest, the conversation with the woman went something like this:</p>

<blockquote>
  <p><strong>Me:</strong> Hi, I&#8217;m calling to find out about my missing bag. <br />
  <strong>Woman:</strong> What&#8217;s your name? <br />
  <strong>Me:</strong> Andrew Hanenkamp. H-A-N-E-N-K-A-M-P. <br />
  <strong>Woman:</strong> Mr. Hanenkamp? Yes, your bag came in on your flight. Why didn&#8217;t you pick it up? <br />
  <strong>Me:</strong> Um, because the guy who said he was going to pull it out of the plane said he didn&#8217;t find it and gave me a baggage claim ticket. <br />
  <strong>Woman:</strong> Okay, I&#8217;m very busy right now, I will try to get them delivered to you hotel. Can I get your number?  </p>
</blockquote>

<p>I gave her the number and then finally was able to get back with her during lunch. This conversation went something like this:</p>

<blockquote>
  <p><strong>Me:</strong> Hi, I&#8217;m returning a call made to my cell phone? <br />
  <strong>Woman:</strong> Who is this? Is this Mr. Hanenkamp? <br />
  <strong>Me:</strong> Yes, I believe you have my bags, have they been sent to my hotel yet? <br />
  <strong>Woman:</strong> Well, your bag was here last night. My supervisor wants to know why didn&#8217;t you pick it up last night. It was here already. <br />
  <strong>Me:</strong> I know. As I told you before, the guy who pulled it out of the plane told me it didn&#8217;t come. <br />
  <strong>Woman:</strong> Hmm. Okay. Umm. Did he give you a baggage claim ticket? <br />
  <strong>Me:</strong> Yes. I have it in my wallet. <em>(Thinking, do you want me to shove it through the phone?)</em> <br />
  <strong>Woman:</strong> Okay, well, I guess I can have the delivery service take your bag over. Which hotel are you at? Do you know the zip code? <br />
  <strong>Me:</strong> <em>[chuckle]</em> Um, no, I don&#8217;t generally memorize the zip codes of the hotels I&#8217;m staying at.  </p>
</blockquote>

<p>Anyway, so when I got back, I had my bag and was finally able to change into completely fresh clothing and brush my teeth and such. Ah.</p>

<h3>Sunday</h3>

<p>I walked over to Wean Hall again after picking up my coffee and started out in the Rakudo Perl talk.</p>

<h4>Rakudo Perl</h4>

<p>This talk was also given by Patrick Michaud and I went to it rather than the Moose talk because I&#8217;m already somewhat familiar with Moose and because Perl 6 and Parrot are something I&#8217;d like to volunteer my time on. Perhaps I will at some point, but I have too many other things I&#8217;m doing that I&#8217;m more immediately interested in. I don&#8217;t have any excuse for not joining for reasons due to not knowing how now, though. Patrick went over all the sorts of things someone wanting to contribute might want to do to get started.</p>

<h4>Managing Open Source Projects</h4>

<p>Next I went to this talk by Tom Lane rather than attending Schwern&#8217;s talk on the y2038 bug. The talk was moderately interesting since Tom Lane is a Red Hat employee who spends most of his time contributing to PostgreSQL. It was interesting to here the differences between how Perl is managed and PostgreSQL, but I confess, I was again distracted, but this time by a bug report on one of my CPAN modules.</p>

<h4>Data Structures</h4>

<p>This was another talk by Paul Grassie and at a very introductory level. I don&#8217;t think he covered anything I don&#8217;t use on a nearly daily basis, but I was still working on bugs on my CPAN module. I did note that Paul has a very soothing voice and since I&#8217;ve only had about 8 hours of sleep total in the past 48 hours, it was making me a bit sleepy.</p>

<h4>MooseX::Tour</h4>

<p>Next was Jonathon Rockway&#8217;s talk on MooseX extensions. There are some pretty cool extensions to Moose available for dealing with various customizations to your meta-programming code. I&#8217;d recommend looking over his slides when they are posted on his <a href="http://blog.jrock.us/">blog</a>. There&#8217;s some interesting things in there.</p>

<h4>Lunch</h4>

<p>We had more lunch. I got to meet Tom Welsch&#8217;s kids, since Tom brought them with him as he did a little light recruiting for Grant Street. I had more yummy salad and a decent sandwich (at least for having been catered).</p>

<h4>Jifty Talk</h4>

<p>I gave and got through my whole talk on Jifty. I&#8217;ve <a href="http://qublog.net/2008/10/talk-introduction-to-jifty.html">posted</a> the slides, which is enough summary.</p>

<h4>Prophet</h4>

<p>I watched part of Kevin Falcone&#8217;s talk on <a href="http://syncwith.us">Prophet</a> and this is another one of those things that I have got to get my hands on in the near future. <a href="http://qublog.net/">Qublog</a>, in particular, could benefit from what it does very nicely.</p>

<h4>Perl REST</h4>

<p>Again, I gave this talk and the slides are <a href="http://contentment.org/2008/10/talk-making-your-perl-rest.html">posted</a>.</p>

<h4>Method Signatures</h4>

<p>Lastly, I attended the talk Schwern gave on his new method signatures class. It&#8217;s pretty nice overall, but I&#8217;m a little hesitant to actually use it. His point about there being 240,000 extra lines of code that can be taken off of CPAN because of it is well-taken, but I&#8217;m not quite convinced to actually use it yet. On the other hand, the parser module that Matt Trout wrote, Devel::Declare, which has some interesting possible implications for the DSL work I want to do with Jifty.</p>

<h4>Lightning Talks</h4>

<p>Most of the lightning talks were great, mine excluded. I fail. </p>

<p>Ricardo gave a talk on Dist::Zilla, which I am also adding to my short list. It&#8217;s kind of a replacement for Makefile.PL and Module::Starter and Module::Release and such, but does some very smart things. If I find out that it&#8217;s extensible and mostly makes sense when I take a first hand look, I&#8217;ll likely be using this to manage my modules in the future.</p>

<p>Kelli Ireland gave a talk on the orange shirt that&#8217;s been traveling with various members of the Perl community to exotic destinations and offered it to anyone going somewhere interesting if they will take pictures.</p>

<p>There was a talk on going <em>Sixty to Zero</em> in Perl (a play on the <em>Zero to Sixty</em> tutorial given). This talk was great in that it showed how very readable Perl can be turned very unreadable if someone wishes to do so deliberately in order to maintain job security. It was a very good example of why serious Perl developers don&#8217;t understand why Perl gets kicked in the face so much when it is not difficult to write good Perl code if you actually try to do so.</p>

<p>Probably the most memorable lightning talk, though, was the LOLCAT history of Perl. Unfortunately, there&#8217;s no way such a talk can be translated into this summary in any useful fashion, so I will just say, that it was <em>awesome</em>.</p>

<p>After that, I skipped out because I&#8217;m sleepy and should have been asleep already, but decided to write this instead&#8230; Okay, so I think that does it for PPW 2008. This is Sterling Hanenkamp signing off. Good night and God bless.</p>
]]>
        

    </content>
</entry>

</feed>
