<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
	<channel>
		<title>Kris Jordan Blog</title>
		<link>http://krisjordan.com/</link>
		<description></description>
		<language>en-us</language>
		<copyright>Copyright Kris Jordan.</copyright>
		<lastBuildDate>Wed, 31 Dec 1969 19:00:00 -0500</lastBuildDate>
		<docs>http://blogs.law.harvard.edu/tech/rss</docs>
		<generator>HiFi</generator>
		<managingEditor>krisjordan@gmail.com</managingEditor>
		<webMaster>krisjordan@gmail.com</webMaster>
				<item>
			<title>Code Sketch: Paper Trail</title>
			<link>http://krisjordan.com/essays/code-sketch-paper-trail</link>
			<description>
				<![CDATA[
					<p>Often I'll have an idea that's interesting to me. I'll obsess for a weekend, sketch out some proof-of-concept code, prove to myself it'd be possible (with a lot of work), or not, and move along.</p>
<p>Sometimes these sketchy ideas are recurring. "Paper Trail" is one of them; it first surfaced circa 2009.</p>
<p>Rather than sketching ideas in private, I thought it'd be interesting to do publicly. Ridicule away.</p>
<p>This idea's motivation is a thought experiment:</p>
<p><strong>What if you could trace <em>every value</em>&#160;in a program all the way back to its <em>source</em>&#160;at <em>runtime</em>?</strong></p>
<p>This isn't a novel idea. Spreadsheets have been doing this forever, right? For example, assign `1` to cell A1 and `=A1+1` to cell B2. The output value of cell B2 will be `2`, but you can later trace its source back to A1.</p>
<p>It is a foreign idea, though, in general purpose programming languages. For example, assign `a = 1`, then assign `b = a + 1`. The value of `b` is now `2`, but there's no way to know, at runtime, its source is `a`.</p>
<p><strong>Why is this interesting?</strong></p>
<p>Imagine a database-driven website's execution flow. The source of data is now the database, rather than hard coded values. Let's wave our hands with pseudo-code:</p>
<pre># Fetch a blog post
post = Post.first()
# Render template with blog post
render(template, post)
# Print title of blog post in template
&lt;h1&gt;{{ post.title | toUpperCase }}&lt;/h1&gt;
</pre>
<p>The rendered output would be:</p>
<pre>&lt;h1&gt;HELLO, WORLD.&lt;/h1&gt;</pre>
<p>Now imagine a "paper trail" of back references was baked in by default through that program listing. The template engine could just as easily also render (if it wanted to, for content editors):</p>
<pre>&lt;h1&#160;class="papertrail-value"
    data-papertrail-href="http://krisjordan.com/posts/1" 
    data-papertrail-property="title"
    &gt;HELLO, WORLD.&lt;/h1&gt;</pre>
<p>Sprinkle in some JavaScript magic and voil&#224;, front-end content editing becomes possible without the trade-offs it traditionally imposes on front-end developers:</p>
<ul>
<li>no constraints on template structure</li>
<li>no additional work and effort</li>
<li>no new DOM tags</li>
<li>no ugly widgets forced in</li>
</ul>
<p>It'd be powerful.</p>
<p>Interesting follow-on questions and problems fall out quickly:</p>
<ul>
<li>What would it take to implement this in user land?</li>
<li>What about sources that are collections rather than objects?</li>
<li>What about values that combine multiple source values, like string concatenations?</li>
<li>How much overhead would this impose? Would it actually matter?</li>
<li>Is there value in storing the whole trail or just the source(s)?</li>
<li>Is there any value if the source is read-only?</li>
<li>What other applications would a reference trail have?</li>
<li>How much work would a proof-of-concept take?</li>
</ul>
<p>I'm going to keep sketching on this, at least through the weekend, and worst case when it resurfaces for me again in a few years.</p>
<p>Sound interesting to you?&#160;<a href="https://www.twitter.com/KrisJordan">Ping me @KrisJordan</a>.</p>
				]]>
			</description>
			<pubDate>Thu, 02 Jan 2014 23:52:04 -0500</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/essays/code-sketch-paper-trail</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>Encryption with RSA Key Pairs</title>
			<link>http://krisjordan.com/essays/encrypting-with-rsa-key-pairs</link>
			<description>
				<![CDATA[
					<p>During the Thanksgiving holiday I wondered, "how hard would it be to encrypt and decrypt files with my SSH key?" Encryption is the purpose of public/private RSA key pairs, after all.</p>
<p>With `openssl`, it's not too hard. The following tutorial assumes <a href="https://help.github.com/articles/generating-ssh-keys">you've setup RSA private/public keys for ssh/git/github/etc</a>.</p>
<p>(Note: If you're on OSX, you should install the latest versions of OpenSSL and OpenSSH with Homebrew.)</p>
<p>First, let's start with our plaintext file:</p>
<pre>echo "Hello, world." &gt; plain.txt</pre>
<p>Before we can encrypt the plaintext with our public key, we must export our public key into a PEM format suitable for OpenSSL's consumption.</p>
<pre>openssl rsa -in &#126;/.ssh/id_rsa -pubout \
  &gt; &#126;/.ssh/id_rsa.pub.pem
 
cat &#126;/.ssh/id_rsa.pub.pem</pre>
<p>It should look something like this:</p>
<pre>-----BEGIN PUBLIC KEY-----
MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAkq1lZYUOJH2Yeq5IG/TfB3vFbRcc6fSxrwuADNuS10ftI9Nd5lsVKiU+T/NkDQ42I8DMVyjrrFS/bfBUoH1DeyhDVMXvCyfRYNtQdhq0zKMs7l1bmmeBoTiXEyOnjst0LTNzdjY6huvWilACCiU+DeRUvZr73VZty/YoAZsHA4GdnTqyLHnusN/k0r6KaTagUxZl26Wkj2J2sIw+3XIMczmPHO0p4bpynEKmKF3tr7bqBPe6s8azQMElibCAA8jTUs45RvHYtdKajmTxfETIQa8a54ZzZ54dApo0yFXOb2LRgk8H5awk5dUNfcX88FoYDWD/RigJEd3F5Y1unaZXJwIBIw==
-----END PUBLIC KEY-----</pre>
<h2>Encrypt</h2>
<pre>cat plain.txt \
 | openssl rsautl \
     -encrypt \
     -pubin -inkey &#126;/.ssh/id_rsa.pub.pem \
 &gt; cipher.txt</pre>
<p>The important command in the pipeline is `openssl`. The first argument passed to `openssl` is the OpenSSL command you are running. It has a wide variety of commands covering a wide range of cryptographic functionality. For our purposes, we're doing public/private RSA encryption, so we're using the RSA Utility, or `rsautl`, command. Next, the `-encrypt` key indicates we are encrypting from plaintext to cipher text, and finally the `-pubin` flag indicates we are loading a public key from `-inkey [public key file]`.</p>
<p><strong>Print the contents of the ciphertext with `cat cipher.txt`.</strong> You should see fully encrypted gibberish.</p>
<h2>Decrypt</h2>
<pre>cat cipher.txt \
  | openssl rsautl \
      -decrypt \
      -inkey &#126;/.ssh/id_rsa</pre>
<p>"Hello, world."</p>
<p>Boom! We're back to plaintext.</p>
<p>If you actually wanted to trade encrypted messages, PGP is the much "friendlier" and accepted system for doing so. This manual, command-line method of encryption is a neat demo nonetheless.</p>
				]]>
			</description>
			<pubDate>Mon, 02 Dec 2013 00:29:51 -0500</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/essays/encrypting-with-rsa-key-pairs</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>Log Indexing and Analysis with Logstash and Kibana</title>
			<link>http://krisjordan.com/essays/log-warehousing-with-logstash-and-kibana</link>
			<description>
				<![CDATA[
					<p>I was back on <a href="http://www.gethifi.com/">HiFi</a> today after one of our servers went through a minor panic attack.</p>
<p>Memory pressure led to swapping, swapping lead to thrashing, and thrashing led to the dark side where the ready queue was briefly in excess of the number of the machine's cores by a factor of 10. The interruption was brief, but it lead to thinking about low hanging fruit, bottlenecks, and ops.</p>
<p>I've been thinking a lot about <a href="http://12factor.net/">twelve-factor app development</a> and deployment lately. The "Twelve-Factors" are a set of principles put together by Adam Wiggins of Heroku fame. Following the methodology takes some additional thought and effort upfront, but has a lot of upside once you're operational. One of the factors <a href="http://12factor.net/logs">concerns logging</a>:</p>
<blockquote>
<p>Most significantly, the stream can be sent to a log indexing and analysis system such as&#160;<a href="http://www.splunk.com/">Splunk</a>, or a general-purpose data warehousing system such as&#160;<a href="http://hive.apache.org/">Hadoop/Hive</a>. These systems allow for great power and flexibility for introspecting an app&#8217;s behavior over time, including:</p>
<ul>
<li>Finding specific events in the past.</li>
<li>Large-scale graphing of trends (such as requests per minute).</li>
<li>Active alerting according to user-defined heuristics (such as an alert when the quantity of errors per minute exceeds a certain threshold).</li>
</ul>
</blockquote>
<p>I've been meticulous about the maintenance and archival of HiFi's data logs. We have used them in retrospectives and the occasional in-depth analysis, but have stopped short of putting together a system for harvesting and inspecting the data interactively. Today's incident was motivation to set one up.</p>
<p>The triumvirate of&#160;<a href="http://logstash.net/">Logstash</a>, <a href="http://www.elasticsearch.org/overview/kibana/">Kibana</a>, and <a href="http://www.elasticsearch.org/">elasticsearch</a>&#160;came up in a recent Hacker News thread sounded encouraging. Logstash is a flexible event log streamer that makes it simple to extract data from logs and get it into elasticsearch for indexing and analysis (it can do a lot of other neat things, too). Kibana is a beautiful web interface for creating interactive dashboards for your data in elastic search. It's an all HTML5 application running entirely in the browser using elasticsearch's rest API. It's easy to make good looking dashboards:</p>
<p><img src="http://files.krisjordan.com/kibana.png" alt="Kibana" width="700" height="665" /></p>
<p>Getting kibana, logstash, and elasticsearch running only took an afternoon to install and configure after running through <a href="http://logstash.net/docs/1.2.2/tutorials/getting-started-centralized">logstash's Getting Started Guides</a>. I'll need to come back for some additional work (like purging data) after it's fully proven itself. My initial impression: it's great collection of software.</p>
<p>Ignoring the per-server JVM bloat required by logstash, the whole setup seems too good to be true. Especially for open source software. It's simple to get logstash configured and kibana/elastic search are impressive (and fun!) to work with interactively. Diving in to specific events, isolating classes of events (like 500 errors), and composing dashboards to quickly answer your key questions is powerful.</p>
<p>Warehousing, visualizing, and diving into log data has never been easier. Now I just want to log <em>more</em>.</p>
<p><img src="http://files.krisjordan.com/log_all_the_things.jpg" alt="" width="500" height="355" /></p>
				]]>
			</description>
			<pubDate>Fri, 15 Nov 2013 02:15:11 -0500</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/essays/log-warehousing-with-logstash-and-kibana</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>PourBot: Hacking the Kettle</title>
			<link>http://krisjordan.com/essays/pourbot-hacking-the-kettle</link>
			<description>
				<![CDATA[
					<p>I'm building an Arduino-powered coffee machine named PourBot.</p>
<p>In the <a href="http://krisjordan.com/essays/pourbot-introduction">previous post</a>, I decided on an electric kettle to heat the water to the ideal coffee brewing temperature &#126;195F. I cracked the Kettle's base station open and found two boards inside. One was connected to the heating element with thick, scary wires, the other had buttons, the temperature LED, and a microcontroller. They were connected by 5 wires:</p>
<p><img src="http://files.krisjordan.com/pourbot/intro/breakout-board.jpg" alt="Breakout Board" width="700" height="394" /></p>
<p>To MacGyver this kettle for PourBot,<strong> I needed control over the heating element and the ability to read the water's temperature</strong>.</p>
<p>I had five unknown wires and a multimeter. Time to reverse engineer the wires' purposes!</p>
<p>If electronics are also new to you, this is how it feels to open an electronic device, plug it into the wall, and press buttons while trying to discover what the wires do:</p>
<p><img src="http://files.krisjordan.com/pourbot/kettle/HurtLocker-process-s700x300.png" alt="Hurt Locker" width="700" height="300" />&#160;</p>
<p>Reality looks more like this:</p>
<p><img src="http://files.krisjordan.com/pourbot/kettle/MacGruber.jpg" alt="MacGruber" width="640" height="360" /></p>
<p>First discovery: <strong>the kettle's control electronics are regulated to 5V</strong>, which is what the Arduino operates with! This means no extra work to communicate with the kettle, I can jump wires straight to the Arduino.</p>
<p><img src="http://files.krisjordan.com/pourbot/kettle/wire-debugging.jpg" alt="Reverse engineering jumper wires." width="700" height="394" /></p>
<p>The Kettle's base has three states: without Kettle, idle, and on.</p>
<p>Without the Kettle, the LED does not display its temperature, so I started measuring the voltages over the wires in this state. From yellow-to-red, they were:</p>
<ol>
<li>5V</li>
<li>0</li>
<li>0</li>
<li>2.5V</li>
<li>0 (Red)</li>
</ol>
<p>I was off to a good start, finding the positive/anode wire #1. I was unsure of negative/cathode, somewhat expecting it to be the red wire #5, but it could also be wires #2 or #3. The 2.5v wire #4 was a mystery (and still is, <a href="http://twitter.com/KrisJordan">tweet me @KrisJordan</a>&#160;if you know the purpose it serves).</p>
<p>Next, I transitioned to the <strong>idle</strong> state by placing the kettle, with some room temperature water in it, on the base. Here were the voltages of the wires:</p>
<ol>
<li>5V</li>
<li>0</li>
<li>0.37V</li>
<li>2.5V</li>
<li>0 (Red)</li>
</ol>
<p>Ah ha! With the kettle on the base, wire #3 had a voltage. Given its fractional value, this must be the temperature sensor. If so, it should increase as the water heats up.</p>
<p>"Here we go," I winced while pressing the Boil button of the high-wattage electric kettle. Once I heard the heating element doing work, I took another reading of the wires while in the <strong>On</strong> state:</p>
<ol>
<li>5V</li>
<li>0</li>
<li>0.84V</li>
<li>2.5V</li>
<li>5V (Red)</li>
</ol>
<p>With the device on, the negative/ground/anode wire turned out to be #2. The red wire, #5, was a full 5V and clearly the wire controlling the relay to the heating element. Finally, an increasing voltage on the thermal sensor wire #3 confirmed it was rising with the temperature of the water.</p>
<p>Now we have a pin layout!</p>
<ol>
<li>Positive</li>
<li>Negative (Ground)</li>
<li>Thermal Sensor Output</li>
<li>2.5V(?)</li>
<li>Power Relay Input (0 off, 5V on)</li>
</ol>
<p><strong>Mission accomplished: we can read the thermal sensor and control the heating element.</strong></p>
<p>Next, I need to reverse engineer the output from the thermal sensor to know how to convert its voltage reading into degrees fahrenheit. Remember, 195<span>&#176;</span>F is the target temperature for brewing coffee!</p>
				]]>
			</description>
			<pubDate>Sun, 10 Nov 2013 23:19:26 -0500</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/essays/pourbot-hacking-the-kettle</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>Nexus Camera Battle: 5 vs 4</title>
			<link>http://krisjordan.com/essays/nexus-phone-camera-battle-5-vs-4</link>
			<description>
				<![CDATA[
					<p>A shiny new Nexus 5 landed on my front porch today. I enjoy photography, so I was hopeful the Nexus 5 would significantly outperform my Nexus 4. I managed to dual wield the 4 and the 5 to snap off a few comparison shots this evening. You can see the results, below, along with some initial thoughts on how the 5 performed.</p>
<h2>TLDR: More Light + Better Sensor = Happiness</h2>
<p>Nexus 4 (ISO 1000, f/2.7, 1/20s) -&#160;<a href="http://files.krisjordan.com/reviews/culdesac-full-4.jpg" target="_blank">Full Resolution</a></p>
<p><img src="http://files.krisjordan.com/reviews/culdesac-4.jpg" alt="" width="700" height="394" /></p>
<p>Nexus 5 (ISO 172, f/2.4, 1/8s) -&#160;<a href="http://files.krisjordan.com/reviews/culdesac-full-5.jpg" target="_blank">Full Resolution</a></p>
<p><img src="http://files.krisjordan.com/reviews/culdesac-5.jpg" alt="" width="700" height="394" /></p>
<h2><strong>The Good News</strong></h2>
<p><strong>Optical Image Stabilization (OIS) allows the Nexus 5 to choose slower shutter speeds.</strong>&#160;Its autoexposure algorithm makes aggressive use of this.&#160;Shooting with a phone, hand-held, with a 1/8s exposure, and having minimal camera shake blur is pretty amazing.&#160;Almost across the board, the Nexus 5 chose a shutter speed around a full stop slower than the Nexus 4.</p>
<p><strong>The Nexus 5 shoots sharp while wide open at f/2.4.</strong>&#160;In theory, the Nexus 4 also has an f/2.4 maximum aperture, but in none of my reference shots did it choose to open up beyond f/2.7. Combined with the longer shutter speeds, the Nexus 5 is soaking its sensor with more than twice the light of the 4.</p>
<p><strong>The Nexus 5 optics and sensor are better, too.</strong>&#160;In only one test shot did the 4 choose ISO 100 and the 5 went higher. The 5's result was still sharper. With a wave of the hands, this is some evidence that the optics are improved. Once shots get beyond ISO 1000, the Nexus 5 is much less noisy than the 4. The sensor is certainly an upgrade.</p>
<p><strong>Image quality is improved.</strong>&#160;Color looks better than the 4 (I'll come back to this in the bad news).&#160;Images are sharper.&#160;The front-facing camera improved by an even bigger margin than the back.</p>
<h2>The Bad News</h2>
<p><strong>Too saturated.</strong>&#65279; All of the shots felt on the saturated site, some especially so. The Nexus 4 tended to do a better job faithfully reproducing the colors of this cold, cloudy day. That said, the saturated pictures overall look better than the Nexus 4's dullness. It'd be nice if saturation could be dialed down.</p>
<p><strong>Shutter release lag is pretty awful.</strong> Using the stopwatch on the Nexus 4, I unscientifically measured around 1s to 2s between pressing the shutter release and the exposure actually being taken. <em>Even with focus locked in, it takes a full second</em>. The Nexus 4's reaction was closer real time with focus, and still faster without focus.</p>
<p>The lag should get better with software, but there's a part of me that's nervous it's there to enable the slower shutter speeds (or, perhaps, a period of time in which an algorithm decides if the camera is stable enough for such slow shutter speeds).</p>
<p><strong>Longer shutter speeds are a gamble.</strong> A decent number of shots were blurry. I'm guessing my dual-wielding hands were too shaky for the OIS to overcome it. Combined with the shutter release lag, it's quite a long time to maintain a frame. I'm doubtful the Nexus 5 will be able to shoot moving targets.</p>
<p><strong>Auto white balance is slow.</strong> Simple solution: don't use auto white balance. Lazy solution: in warm/incandescent environments, give the camera around 5-10 seconds to adjust. Fun exercise: flip to the front camera and back indoors and watch how long it takes to find white balance. There's a good example of what happens when you don't give it enough time, below.</p>
<h2>Comparison Shots</h2>
<p>All but one of the comparison shots are scaled down from an arbitrary cropping to help highlight differences. These were shot using Android's default camera app. No additional post processing was done beyond crop and scale.</p>
<h3>Natural Light</h3>
<p>Nexus 4 (ISO 100, f/2.7, 1/25s)</p>
<p><img src="http://files.krisjordan.com/reviews/wide-leaves-4.jpg" alt="" width="700" height="394" /></p>
<p>Nexus 5 (ISO 227, f/2.4, 1/50s)</p>
<p><img src="http://files.krisjordan.com/reviews/wide-leaves-5.jpg" alt="" width="700" height="394" /></p>
<p>Nexus 4 (ISO 100, f/2.7, 1/25s, 1:1 pixels)</p>
<p><img src="http://files.krisjordan.com/reviews/actual-leaves-4.jpg" alt="" width="700" height="394" /></p>
<p>Nexus 5 (ISO 227, f/2.4, 1/50s, 1:1 pixels)</p>
<p><img src="http://files.krisjordan.com/reviews/actual-leaves-5.jpg" alt="" width="700" height="394" /></p>
<p>Nexus 4 (ISO 1100, f/2.7, 1/20s)</p>
<p><img src="http://files.krisjordan.com/reviews/krackle-4.jpg" alt="" width="700" height="394" /></p>
<p>Nexus 5 (ISO 216, f/2.4, 1/8s)</p>
<p><img src="http://files.krisjordan.com/reviews/krackle-5.jpg" alt="" width="700" height="394" /></p>
<h3>Incandescent Light</h3>
<p>Nexus 4 (ISO 1200, f/2.7, 1/25s)</p>
<p><span style="font-size: 24px;"><img src="http://files.krisjordan.com/reviews/incan-kitchenaid-4.jpg" alt="" width="700" height="395" /></span></p>
<p>Nexus 5 (ISO 706, f/2.5, 1/17s)</p>
<p><img src="http://files.krisjordan.com/reviews/incan-kitchenaid-5.jpg" alt="" width="700" height="394" /></p>
<p>Nexus 4 (ISO 1600, f/2.7, 1/13s)</p>
<p><img src="http://files.krisjordan.com/reviews/incan-krackle-4.jpg" alt="" width="700" height="394" /></p>
<p>Nexus 5 (ISO 665, f/2.4, 1/8s) - White Balance: fail.</p>
<p><img src="http://files.krisjordan.com/reviews/incan-krackle-5.jpg" alt="" width="700" height="394" /></p>
<p>Nexus 4 (ISO 1400, f/2.7, 1/20s)</p>
<p><img src="http://files.krisjordan.com/reviews/kitkat-4.jpg" alt="" width="700" height="394" /></p>
<p>Nexus 5 (ISO 337, f/2.4, 1/8s)</p>
<p><img src="http://files.krisjordan.com/reviews/kitkat-5.jpg" alt="" width="700" height="394" /></p>
<h3><span style="font-size: 24px;">Low Light</span></h3>
<p>Nexus 4 (ISO 1700, f/2.7, 1/13s)</p>
<p><img src="http://files.krisjordan.com/reviews/low-krackle-4.jpg" alt="" width="700" height="394" /></p>
<p>Nexus 5 (ISO 1624, f/2.4, 1/6s)</p>
<p><img src="http://files.krisjordan.com/reviews/low-krackle-5.jpg" alt="" width="700" height="394" /></p>
<p>Nexus 4 (ISO 1600, f/2.7, 1/13s)</p>
<p><img src="http://files.krisjordan.com/reviews/low-cul-4.jpg" alt="" width="700" height="394" /></p>
<p>Nexus 5 (ISO 1624, f/2.4, 1/6s)</p>
<p><img src="http://files.krisjordan.com/reviews/low-cul-5.jpg" alt="" width="700" height="394" /></p>
<h3>Selfies</h3>
<p><em>(Snapchat friends, watch out. My front-facing camera just got a massive upgrade.)</em></p>
<table border="0">
<tbody>
<tr>
<td>Nexus 4 (ISO 500, f/2.7, 1/10s)</td>
<td>Nexus 5 (ISO 379, f/2.9, 1/17s)</td>
</tr>
<tr>
<td><img src="http://files.krisjordan.com/reviews/selfie-4.jpg" alt="" width="350" height="622" /></td>
<td><img src="http://files.krisjordan.com/reviews/selfie-5.jpg" alt="" width="350" height="622" /></td>
</tr>
</tbody>
</table>
<h2>Conclusion</h2>
<p>I'm pleased with the Nexus 5's camera improvements. Sure, it has some limitations, but there's plenty of headroom to take great photos within those limits. <em>The Nexus 5 is capturing 2x-4x the light of the Nexus 4 and with much better image quality</em>. Well lit exposures will be much higher quality photos, and lower light exposures are now possible. <a href="http://instagram.com/therealkrisjordan">My Instagrams</a>&#160;of coffee are going to look <em>so</em> sexy.</p>
				]]>
			</description>
			<pubDate>Tue, 05 Nov 2013 21:41:46 -0500</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/essays/nexus-phone-camera-battle-5-vs-4</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>Timesaving crontab Tips</title>
			<link>http://krisjordan.com/essays/timesaving-crontab-tips</link>
			<description>
				<![CDATA[
					<p>Setting up a <code>crontab</code> for running scripts on a schedule can be frustrating to debug. Usually, it boils down to cron's environment being different than your user's (i.e. <code>PATH</code> issues).</p>
<h2>Always Setup <code>crontab</code> "Variables"</h2>
<p>Your crontab file is <em>not</em> a shell script, but it has a few special variables that you can setup the same way you would a shell script. <strong>Set these special variables up in every crontab file you work with.</strong> Future you will thank you for it.</p>
<h3>MAILTO="a@b.com,b@b.com"</h3>
<p>When your cron jobs have output, or, more importantly, when they fail, cron will send the output e-mail these addresses.</p>
<h3>PATH="/usr/bin:/sbin:/bin"</h3>
<p>Logged in to the user account whose crontab you're setting up, go ahead and <code>echo $PATH</code> and copy those contents into the <code>PATH</code> variable of your crontab. Remember, this isn't a real script file, so you can't implicitly append :$PATH.</p>
<p>After assigning <code>PATH</code> and <code>MAILTO</code>, setting up your crontab is much easier.</p>
<h3>HOME="/path/to/app/root"</h3>
<p>The <code>HOME</code> variable tells which directory cron should execute the crontab commands from. Often times you'll have a user/crontab per project. If so, set the <code>HOME</code> variable to your project's root directory to avoid long, absolute paths to scripts or from having to <code>'cd /path/to/app/root &amp;&amp; ...'</code>&#160;for each job.</p>
<h3>SHELL="/bin/bash"</h3>
<p>Set the default shell to execute your commands from with the SHELL command. Like PATH, a safe bet is making this the same as your user's shell. Logged in as that user, run <code>which `echo $0`</code> to get an absolute path to your shell.</p>
<h2>Still Stumped? Dump Your Environment</h2>
<p>It's easy to pipe cron's environment variables to a temporary file, <a href="http://stackoverflow.com/a/2546509">as seen on Stack Overflow</a>. Tweak the following to run from your crontab in the near future:</p>
<pre>30 08 * * * env &gt; /tmp/cronenv</pre>
<p>Once it runs, cat /tmp/cronenv to see your crontab's environment variables. Alternatively, if you're getting cron error messages e-mailed to you after setting up <code>MAILBOX</code> above, look at the raw headers of the e-mail. E-mails from cron should set <code>X-CRON-ENV</code> headers with these environment variables, too.</p>
<h2>Happy automating!</h2>
				]]>
			</description>
			<pubDate>Mon, 04 Nov 2013 11:46:28 -0500</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/essays/timesaving-crontab-tips</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>Setting up Push-to-Deploy with git</title>
			<link>http://krisjordan.com/essays/setting-up-push-to-deploy-with-git</link>
			<description>
				<![CDATA[
					<p>I first set up a push-to-deploy system with git and puppet for a side project a few years back. It worked so well I transitioned&#160;<a href="http://www.newmediacampaigns.com">NMC</a>'s development process onto it for all of our new projects starting last year. It offers the simplicity of the "push-to-deploy" model Heroku pioneered, with full control and flexibility over the operating system environment.</p>
<p>I've started thinking about my next iteration of this system for&#160;<a href="http://didsum.com">Didsum</a>, and using pushing for more than just deployment purposes. The Push-to-______ pattern is powerful and easy to use, once you know how the pieces fit together. <strong>In this post, I'll walk through the setting up Push-to-Deploy from the ground up.</strong>&#160;</p>
<p><em>(I'm assuming a working knowledge of: terminal, git, and a scripting language.)</em></p>
<h2>&#65279;Preparing our Repositories</h2>
<p>Let's keep things straightforward by placing our <em>development git repository</em>, <em>remote git repository</em>, and <em>deploy directory</em>&#160;under the same local directory.</p>
<pre>mkdir push-to-deploy
cd push-to-deploy
mkdir {development,remote,deploy}</pre>
<p>Awesome, now let's setup the&#160;<em>remote git repository.</em>&#65279; With a real project, this would be a directory on your production server. There is a special setup for git repositories whose purpose is to receive pushes from developers, they're called "bare" repositories. You can <a href="http://git-scm.com/book/ch4-2.html">read more about "bare" repositories</a>, but for our purposes their purpose is just to receive pushes.</p>
<pre>cd remote
git init --bare
cd ..</pre>
<p>Perfect, now let's setup our development directory with git. (You could also copy one of your git project's contents into the development folder.)</p>
<pre>cd development
git init
echo "Hello, world." &gt;&gt; file.txt
git add file.txt
git commit -m 'First commit.'</pre>
<p>We now have a development repository with its first commit. Our last preparation step is to register the "remote" repository. If you're fuzzy on git remotes,&#160;<a href="http://git-scm.com/book/en/Git-Basics-Working-with-Remotes">the official git site has you covered</a>.</p>
<pre>git remote add production ../remote
git push production master</pre>
<p>Boom. You've just pushed your commit from development to your bare, 'remote' repository. We're ready to setup push-to-deploy.</p>
<h2>Set up Push-to-Deploy</h2>
<p>Now that our remote repository is setup, we're ready to write a script for what it'll do when it receives a push. Let's navigate to the <strong>hooks</strong> folder of our remote repository. <strong>Hooks</strong> are scripts that git runs when certain events happen.</p>
<pre>cd ../remote/hooks
touch post-receive
chmod +x post-receive</pre>
<p>The hook we care about for push-to-deploy is&#160;&#65279;<strong>&#65279;post-receive</strong>&#65279;. It is run after receiving and accepting a push of commits. In the commands above, we're creating the post-receive script file with `touch`, and making sure it's an executable file.</p>
<p>Next, open the post-receive script file in your preferred text editor. Copy the contents below:</p>
<pre>#!/usr/bin/env ruby
# post-receive

# 1. Read STDIN (Format: "from_commit to_commit branch_name")
from, to, branch = ARGF.read.split " "

# 2. Only deploy if master branch was pushed
if (branch =&#126; /master$/) == nil
    puts "Received branch #{branch}, not deploying."
    exit
end

# 3. Copy files to deploy directory
deploy_to_dir = File.expand_path('../deploy')
`GIT_WORK_TREE="#{deploy_to_dir}" git checkout -f master`
puts "DEPLOY: master(#{to}) copied to '#{deploy_to_dir}'"

# 4.TODO: Deployment Tasks
# i.e.: Run Puppet Apply, Restart Daemons, etc
</pre>
<p>Let's walk through each of the steps:</p>
<p>1. When git runs post-receive, the data about&#160;<em>&#65279;what</em>&#65279; was received is provided to the script via STDIN. It contains three arguments separated by spaces: the previous HEAD commit ID, the new HEAD commit ID, and the name of the branch being pushed to. We're reading these values and assigning them to from, to, and branch variables, respectively.</p>
<p>2. Our purpose here is to automate push-to-deploy. Assuming a workflow that keeps production on the master branch, we want to exit this script prior to deploying if the branch being pushed is not master.</p>
<p>3. The first deploy step is to "checkout", basically export or copy, files from the master branch to the directory where our project is deployed to in production. (Remember, in this demo it's the fake "deploy" directory, in the real world this might be /var/www, or wherever your project expects to be in production.)</p>
<p>4. Now that our deploy directory is up-to-date, we can run whatever deployment tasks we need to run. This could be applying Puppet scripts (I'll write a post on this scenario soon), restarting a web or application server, clearing cache files, recompiling static assets, etc. Whatever steps you'd normally need to do manually after updating your project's files, automate them here!</p>
<p>Save your post-receive hook, and let's test it out!</p>
<h2>Testing with Pushing</h2>
<p>We can test our script manually, by creating a new commit in our development directory and pushing:</p>
<pre>cd ../../development
echo "New line." &gt;&gt; file.txt
git add file.txt
git commit -m 'Testing push-to-deploy'
git push production master</pre>
<p>In the output of the git push command, you should see lines starting with "remote:". These lines are the output of our post-receive script:</p>
<pre>Already on 'master'
DEPLOY: master($TO_ID) copied to 'push-to-deploy/deploy'</pre>
<p>The first line is noisy output from the git checkout command in step 3, we can ignore it. The second line, is from the puts command, also from step 3 in our post-receive script.</p>
<p>The directory we're deploying to should now be populated and up-to-date:</p>
<pre>ls ../deploy
diff file.txt ../deploy/file.txt</pre>
<p>Pretty awesome, right?</p>
<h2>Testing without Pushing</h2>
<p>When you're working on a post-receive hook, it's annoying to muck up your project's commit history and push each time you make a change. Luckily, because it's just a script, we can fake it from the command-line.</p>
<pre>cd ../remote
git log -2 --format=oneline --reverse
</pre>
<p>First, we need to get the IDs of our most recent 2 commits. The git log command, above, will give us these two IDs in the order you'll want to replace the $FROM_ID and $TO_ID variables with, respectively.</p>
<pre>echo "$FROM_ID $TO_ID master" | ./hooks/post-receive</pre>
<p>This method makes setting up your post-receive hooks enjoyable, enabling you to quickly iterate on your script and execute it repeatedly.</p>
<h2>Next Steps</h2>
<p>In this post, we've walked through how to setup the push-to-deploy with git. For a real world project, your 'remote' and 'deploy' folders would usually be setup on a server, not locally. The details of doing that and properly configuring SSH is beyond the post of this scope (note to self: I should write on SSH configuration, too!).</p>
<p>From here, it's up to your project to determine what actions to automate! Happy pushing!</p>
<p><em>(If the push-to-X pattern interests you, <a href="https://twitter.com/krisjordan">you should follow me on Twitter</a>, or <a href="http://krisjordan.com/essays.rss">subscribe to my RSS feed</a>, because I've got a few more posts on the subject coming up! Also, feel free to tweet feedback / questions / topics you'd like to read.)</em></p>
				]]>
			</description>
			<pubDate>Sat, 02 Nov 2013 18:23:59 -0400</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/essays/setting-up-push-to-deploy-with-git</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>Running Report Card</title>
			<link>http://krisjordan.com/essays/running-report-card-1</link>
			<description>
				<![CDATA[
					<h2>June 2013 - October 2013</h2>
<p>I started running back in June. In the few years past, I haven't been too active. All hack, no play.</p>
<p>I wanted to get in shape, but I also wanted to test out the group tracking feature of an app I've been working on, <a href="http://didsum.com/auth/register">Didsum</a>. (It's getting close to being open to the public; until then you should sign-up for an invite from that link!) It's been a lot of fun tracking with friends, family, and coworkers. I don't think I would have kept it up without it!</p>
<p>While on my run tonight I thought it would be cool to review my running data from&#160;<a href="http://didsum.com/auth/register">Didsum</a> and see how I've been doing.</p>
<hr />
<h2>41 Runs, 28 #withdog</h2>
<p>Since June I've gone on 41 runs. If we toss out the month of June, it's 37 runs. June was a weak month because I was carb-loading in Italy for a couple weeks. &#160;I've taken my dog, Krackle, on 70% of those runs. She loves it.</p>
<hr />
<h2>1 Run Every 3 Days</h2>
<p>Over this time period, throwing out an outlier while on vacation, I'm running once every three days on average. There's a good bit of variance here, which I want to work on. My rough goal has been to run every other day. For a week I was on a Hal Higdon 5k training schedule, which bumped me to 5 days a week. I'm pretty pleased with this average, but want to avoid those gaps of 5+ days between runs. I did that 8 times this period.</p>
<p><img src="http://files.krisjordan.com/running/days-since-last-run.png" alt="Days Since Last Run" width="918" height="473" /></p>
<hr />
<h2>97 Miles</h2>
<p>Being 3 miles shy of 100mi makes me wish I'd waited for one more run! It's pretty cool to see these miles add up. My first 4 runs, recorded in June, were 1.2, 1.6, 1.7, and 1.8 miles long. They all felt like death. I guess runs still feel like that, but I'm running (a little) further and faster now.</p>
<p>My longest run was 4.5 miles at Oak Island. It was my only point-to-point run and was a lot of fun. I ran as far as I could until meeting my friend, Bryan Deaton, who was driving in to the house I departed from. I <a href="http://xkcd.com/356/">nerd sniped</a> him with the calculus problem of how far I'd be able to run before he picked me up in his car. He somehow got it right.</p>
<p>The following chart shows a 7-run trailing average plot of distance per run to smooth out the noise. It's a neat graph to see go up, but I need to step it back up! I'm liking the 3 mile range, but I wish I had a better loop around my neighborhood for it. Note to self: find one.</p>
<p><img src="http://files.krisjordan.com/running/distance-per-run.png" alt="Distance per Run" width="918" height="454" /></p>
<hr />
<h2>28% Faster</h2>
<p>It's crazy how quickly you can pick up your pace when you're getting started with running. On my third run, I ran 1.8 miles in 21 minutes, for a pace of 12:00/mi. On Monday, I ran the same roads for 2.0 miles in 17.5 minutes, for a pace of 8:45/mi. (It might just be the new running shoes I bought on Monday!)</p>
<p>The following pace chart is also a 7-run trailing average.</p>
<p><img src="http://files.krisjordan.com/running/pace.png" alt="Pace per Run" width="916" height="476" /></p>
<p>If you flip between my distance and pace charts, you can see I slowed down as distance went up, but once it came back down I was moving faster than before.</p>
<hr />
<h2>First 5k Race: 26m 48s, 8:39/mi</h2>
<p>Thanks to some friends (Thanks Annie and Nathan... and Carmen!), I had the opportunity to run my first 5k race on a whim ahead of training schedule. It was the <a href="http://www.cleftpalategallop.com/styled-5/">Chapel Hill Cleft Palate Gallup</a> and it went pretty well: I finished in 6th place amongst females aged 30-39th under Carmen Stanco's bib!</p>
<p><img src="http://files.krisjordan.com/running/cleft_palate_gallup.jpg" alt="Cleft Palate Gallup with Annie and Nathan" width="640" height="640" /></p>
<hr />
<h2>Self-assigned Grade: B-</h2>
<p>"80% of success is showing up."</p>
<p>Nice job overall, better than I would have projected myself to do in June getting started. I need to work on consistency and try to shoot for 3 miles per run.&#160;</p>
<h3>Goals for the next Running Report Card:</h3>
<ul>
<li>No periods of&#160;<strong>5 or more days between runs</strong></li>
<li>&#65279;<strong>&#65279;100 Miles</strong>&#65279; in less than 35 runs / <strong>average 3 miles per run</strong></li>
<li>Finish averaging an<strong> 8:30min/mi pace</strong></li>
<li><strong>Find a good 3 mile loop</strong></li>
<li><strong>Read <a href="http://www.amazon.com/Natural-Running-Simple-Stronger-Healthier/dp/1934030651">Natural Running</a> </strong>cover-to-cover, improve form</li>
<li>Get my wife to join me on <strong>at least 1 run per week*.</strong></li>
</ul>
<p>*This post edited by Kris' wife.&#160;</p>
				]]>
			</description>
			<pubDate>Thu, 31 Oct 2013 01:01:31 -0400</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/essays/running-report-card-1</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>PourBot: Making* an Arduino Pour Over Coffee Machine</title>
			<link>http://krisjordan.com/essays/pourbot-introduction</link>
			<description>
				<![CDATA[
					<p>(* Read: Attempting to make.)</p>
<p>Earlier this month, probably after seeing some neat post on Hacker News, I bought an <a href="http://www.amazon.com/Arduino-Starter-Official-170-page-Projects/dp/B009UKZV0A">Arduino Starter Kit</a>&#160;on a whim. My mission: to hack up a pour over coffee machine (or fail trying).</p>
<p>Why? Well, partly because I love coffee. Especially a good cup made via pour over.</p>
<p>The truth, though, is that I've always been secretly jealous of the kids who broke open electronics and hacked them to do sweet shit. I've been firmly anchored in software<sup><span>1</span></sup> since since a middle school buddy gave me a bootleg copy of Visual Basic 6. (Writing code was love at first sight, even despite the ugliness of VB6.) For me, Arduino offers an approachable way to tinker with electronics and hardware, while still having code as a crutch.</p>
<p>For the sake of reference, here's the Arduino Uno board that comes with the kit:</p>
<p><img src="http://files.krisjordan.com/pourbot/intro/arduino.jpg" alt="Arduino Uno" width="700" height="394" /></p>
<h2>First: What is Pour Over Coffee?</h2>
<p>It's a simple, old method of brewing coffee that is making a revival at boutique (<em>hipster</em>) coffee shops. The pour over method produces a single cup of coffee&#160;brewed deliciously fresh.</p>
<p><img src="http://files.krisjordan.com/pourbot/intro/pour-over.jpg" alt="Pour Over Kit" width="612" height="612" /></p>
<p>Here's roughly how pour over coffee works, step by step:</p>
<ol>
<li>Water is boiled to 192<span>&#176;</span>F-200<span>&#176;</span>F. This is important. (Most drip machines fail to breach 180&#176;F.)&#160;</li>
<li>Coffee is measured and ground fresh, with a burr grinder.</li>
<li>The filter is placed in the dripper (the white ceramic funnel).</li>
<li>The grounds go in the filter and are preheated by pouring just enough water to soak. Wait 30 seconds.</li>
<li>Using a gooseneck kettle, water is poured onto the grounds with a growing spiral starting from center. Add more water as necessary. It should take around 2 minutes to brew.</li>
</ol>
<p>That's it! So, let's see how much of this process can be automated with little electrical knowledge, an Arduino, and some hacking.</p>
<h2>Problem #1) Sourcing a Boiler</h2>
<p>Boiling water to right around 195&#176;F, is step one, so it's the first problem I needed to tackle. Aubrey and I have collected a number of coffee machines over the years. My plan: salvage parts from the most promising of them.</p>
<p><img src="http://files.krisjordan.com/pourbot/intro/kitchenaid-1.jpg" alt="Kitchen Aid" width="700" height="700" /></p>
<p>I pulled our first coffee machine from the attic, a nice looking, red KitchenAid and set it up. I filled its tank, and set it to brew, without any coffee, to test its water temperature.</p>
<p><img src="http://files.krisjordan.com/pourbot/intro/kitchenaid-2.jpg" alt="Kitchen Aid Water Temp" width="700" height="221" /></p>
<p>It started pumping water into the grounds filter almost immediately, with lukewarm water. <em>Gross</em>. The hottest reading I could get it to reach was&#160;160&#176;F. No wonder this machine made coffee that tasted like wet garbage. The good news is, I wouldn't need to clean the filth left in it from the abuse it endured at <a href="http://www.newmediacampaigns.com">NMC</a>'s office back in the 605 building days.</p>
<p><img src="http://files.krisjordan.com/pourbot/intro/keurig.jpg" alt="Keurig Reading" width="700" height="933" /></p>
<p>Next up: the Keurig. I had seen an Arduino Keurig hack before, and it had a nice looking pump system I thought would also be handy. Unfortunately, the warmest reading from the Keurig I could get was 180&#176;F. It wasn't a completely fair test, I couldn't read directly from the spout without the machine refusing to pump water, but this isn't science, it's hacking.&#160;</p>
<p><img src="http://files.krisjordan.com/pourbot/intro/hamilton-beach-1.jpg" alt="Hamilton Beach Electric Kettle" width="700" height="732" /></p>
<p>For some reason, I had mentally blocked out <a href="http://www.amazon.com/Hamilton-Beach-40996-Programmable-1-7-Liter/dp/B0083I7THI">our Hamilton Beach electric kettle</a> as a possible solution. I guess because it lacked pumps. It could certainly get water to boiling, though.</p>
<p><img src="http://files.krisjordan.com/pourbot/intro/hamilton-beach-2.jpg" alt="Kettle Reading" width="700" height="394" /></p>
<p><em><em>200&#176;F!&#160;</em>Hell yes!</em></p>
<p><img src="http://files.krisjordan.com/pourbot/intro/perfect-temperature.jpg" alt="Kettle Thermostat" width="700" height="394" /></p>
<p>The other cool thing about it, I had forgotten: it has a built-in temperature display. I actually bought it&#160;<em>&#65279;for this</em>&#65279; feature. Most electric kettles lack this.</p>
<p>New Theory: If I can read the temperature sensor and control turning on/off the heating element, I've got everything I need to boil water to 195<em>&#176;</em>F!</p>
<p><img src="http://files.krisjordan.com/pourbot/intro/try-wing-flat-head.jpg" alt="Tri-wing Flat Head Bolts" width="700" height="394" /></p>
<p>So I opened up the Kettle's "Docking Station". This was annoying because of the cockamamie Tri-Wing(C) screws they used, I assume, to prevent people like me from from opening it up. "Ah, screw it<sup><span>2</span></sup>,"&#160;I said, forcing a Phillips Head with some pressure to get the bolts out (and strip the heck out of them).</p>
<p><img src="http://files.krisjordan.com/pourbot/intro/popped-open.jpg" alt="Breaking into the Kettle" width="700" height="700" /></p>
<p><em>Boom! We're in!</em></p>
<p><img src="http://files.krisjordan.com/pourbot/intro/breakout-board.jpg" alt="Kettle Breakout Board" width="700" height="394" /></p>
<p>I spent some time looking at the two boards. (Ok, an embarrassingly&#160;long time. I'm coming into this project extremely green with electronics.) My conclusion was, "this is really encouraging".</p>
<p>The board attached to the base, with thick wires going to the heating element's connection, seemed to be the "muscle" of the kettle. The breakout board, attached by 5 jumper wires, contained the buttons for control, the LED, and what looked to be its "brains", a microcontroller, on the backside. If I was correct, it meant I should be able to wire up those jumper cables to the Arduino, and have full control over the kettle <em>and</em> read its thermal sensor!</p>
<p>I tried tracing the circuit on the backside of the breakout board to figure out the purpose of the wires, but realized I was slowly getting nowhere. So I stopped and ordered <a href="http://www.amazon.com/INNOVA-3320-Auto-Ranging-Digital-Multimeter/dp/B000EVYGZA/ref=lp_15707471_1_1?s=automotive&amp;ie=UTF8&amp;qid=1383105625&amp;sr=1-1">a cheap multimeter</a> to be able to read the voltages of the wires while it was in operation.&#160;I had my fingers crossed the breakout board would be operating within the 0-5V range the Arduino does.&#160;<em>That'd be great</em>.</p>
<p>Being physically "blocked", because you're missing a tool or a part you can't get today, is a big change from equivalently simple software learning. The upside: it forces you to stop and go to bed.</p>
<p>In the next post, <a href="http://krisjordan.com/essays/pourbot-hacking-the-kettle">I reverse engineer the Kettle's jumper wires' purposes</a>.</p>
<hr /><ol>
<li>This isn't entirely true. During an awesome Freshman Seminar course, "Robotics with Legos" taught by Prof. Gary Bishop (one of UNC CS's finest), I played with hardware at a &#160;simple level. We never worried about voltages or circuits, Legos abstracted those details away. Here's a fun picture of Joel Sutherland and I in that course, with our final project. Even in this project I avoided most of the mechanical and stayed in the comfortable world of quasi-C code.&#160;This is the first technical project we teamed up on, and dates back to December of 2003 (<em>crazy</em>):<br /><img src="http://files.krisjordan.com/pourbot/intro/candy-outside-before_1_of_2.jpg" alt="Super Skittle Sweeper" width="700" height="525" />&#160;<br />Our robot was <em>S<sup>3</sup> - Super Skittle Sweeper</em>. It used 2 Brick CPUs, one was the "muscle" that powered the motors and took actions, the other was the "brain" which read the sensors sent actions to the muscle brick. Fun little coincidence to see this same concept at play in the electric kettle.<br /><img src="http://files.krisjordan.com/pourbot/intro/candy-outside-before_2_of_2.jpg" alt="Super Skittle Sweeper" width="700" height="394" />&#160;</li>
<li><a href="http://krisjordan.com/essays/letters-to-an-aspiring-programmer-on-loops">Second post in a row with a truly awful pun</a>. Pretty soon this will be a streak.</li>
</ol>
				]]>
			</description>
			<pubDate>Tue, 29 Oct 2013 21:52:39 -0400</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/essays/pourbot-introduction</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>Letters to an Aspiring Programmer: On Loops</title>
			<link>http://krisjordan.com/essays/letters-to-an-aspiring-programmer-on-loops</link>
			<description>
				<![CDATA[
					<p><em>My brother-in-law is learning how to program. I'm naturally psyched. He's tracking the topic and amount of time he's investing into learning how to code with Codecademy on <a href="http://didsum.com" target="_blank">Didsum</a>, which makes it easy for me to follow along with progress. I thought it might be fun, and potentially helpful, to write some quick commentary around the topics he's learning and post them here. Today's notes are about Looping.</em></p>
<hr />
<h2>Patrick,</h2>
<p>Nice work getting through the section on looping today! Being "a bit shaky with them" is nothing to worry about. The details about loops are hard to remember, especially from tutorials that force feed you details too early.</p>
<p>Covering the full power of loops in a single tutorial is kind of like trying to teach someone new to baseball all of the grips and releases a pitcher could use. Until you&#160;<em>&#65279;need</em>&#65279; to throw a curve ball, knowing exactly where to hold your fingers around the stitching and how to release it isn't a big deal.&#160;</p>
<p>Once you're writing a program to do something&#160;<em>&#65279;you</em>&#65279; need it to do, you'll probably hit points where you think "I need to do something a bunch of times" or "I have a bunch of data, I need to do something with every piece of it." When you find yourself thinking that, loops are a powerful tool at your disposal<sup>1</sup>.</p>
<p>Once you have a&#160;<em>&#65279;</em>need&#65279;, and can jot down a basic outline of your strategy for solving it (in English), you can search Google for "types of loops" to decide which kind of loop to use or its specific syntax. Test and tweak until you get it right.</p>
<h2>Common Purposes of Loops</h2>
<p>After you've used loops for a while<sup>2</sup>&#65279;, some patterns will start to emerge in how you use them to help you with a particular kinds of tasks. These tasks are not worth trying to commit to memory, but they're common enough that being aware of them should be useful. All of these examples will use <code>for</code> loops over arrays<sup>3</sup>.</p>
<h3>Do something&#160;<em>for each</em> element</h3>
<pre>var numbers = [1, 2, 3, 4, 5];
// For each number in the `numbers` array:
// log it to console
for(var i = 0; i &lt; numbers.length; i++) {
  console.log(numbers[i]);
}
</pre>
<p>This was the opening demo of your Codecademy tutorial. It loops through each number in the <code>numbers</code> array and takes an <em>action</em> with it. In this example, the <em>action</em> is to print it to console. The action could have been <code>alert(numbers[i]);</code> to get it to show an alert dialog for each number. There will be times when you just need to take an action with every element in an array and this simple pattern will have you covered.</p>
<h3>"Change" elements of an array</h3>
<pre>var numbers = [1, 2, 3, 4, 5];
var numbers_doubled = [];
// For each number in numbers:
// double it and add it to the numbers_doubled array
for(var i = 0; i &lt; numbers.length; i++) {
&#160; numbers_doubled.push(numbers[i] * 2);
}</pre>
<p>In this demo, our goal is to double an array of numbers. The doubling isn't important, what is important is that after we're done we have a new array whose elements are "mapped" from the elements of the original array. In this case, that mapping is to double the element. Maybe your array is made up of investments and you want apply interest on each of them.</p>
<p>Note: We could have <em>changed</em> the elements of original <code>numbers</code> array in place, without using the separate <code>numbers_doubled</code> array, and that would have been fine. One upside of creating a new array is that we still have a way to access our original data later in the program. Another upside is that this program will be easier to debug.</p>
<h3>Filter elements of an array</h3>
<pre>var numbers = [1, 2, 3, 4, 5];
var odds = [];
// For each number in numbers:
// if it is odd, add it to the odds array
for(var i = 0; i &lt; numbers.length; i++) {
  if(numbers[i] % 2 == 1) { 
&#160;   odds.push(numbers[i]);
  } 
}</pre>
<p>In this demo, our goal is to pick out all of the odd numbers in the <code>numbers</code> array and place them in the <code>odds</code> array.</p>
<p>Note: If you haven't seen the <code>%</code> modulo syntax before, it's basically "integer division remainder", i.e. if you divide 3/2 you get a remainder of 1.</p>
<p>When you have a dataset, but only want to focus on a particular chunk of it, you can <em>filter</em> out exactly the data you want using a loop to populate a new, filtered dataset. Creating a new variable to copy the elements you do want into a new array is usually simpler than removing the items you don't want.</p>
<h3>Summarize elements of an array</h3>
<pre>var numbers = [1, 2, 3, 4, 5];
var sum = 0;
// For each number in numbers:
// add it to the sum variable
for(var i = 0; i &lt; numbers.length; i++) {
  sum = sum + numbers[i];
}</pre>
<p>In this example, we're adding up all the numbers. We could have done other things, too, like averaged the numbers. The important takeaway is that we initialized a new variable, <code>sum</code>, to hold the results of our computation. Once we've looped through the array, and <em>reduced</em> it down to a single value, we now have their sum.</p>
<p>For a lot of common mathematical summaries (like sum, product, average, stddev, etc.) there will be libraries you can use so you do not have to write these computations by hand. When you find yourself wanting to summarize in your own special way, this is a useful pattern to come back to.</p>
<h2>Conclusion</h2>
<p>Don't worry about the details of loops until you find yourself needing to do something repeatedly. The important thing to know is that they exist. If you can frame your problem as one or more of the different common types of loops I demoed above: taking repeated actions, modifying a bunch of values, filtering out values, or summarizing values, then you can use those patterns as building blocks.</p>
<p>Once you're more comfortable with functions in JavaScript, it'll be fun to revisit these looping concepts with the full power of functions at your command. Once you've got functions down we could write some that allow you to avoid the hassle of writing loops altogether. Let's save that glory for a rainy day.</p>
<p>Best,</p>
<p>Kris&#160;</p>
<hr /><ol>
<li>Loops aren't the only way to do something a number of times or to operate on sets of data, though...</li>
<li>What an awful pun.</li>
<li>It's somewhat rare to write real programs with loops whose bounds are hard-coded numbers. Looping through arrays is much more common and useful.</li>
</ol>
				]]>
			</description>
			<pubDate>Mon, 28 Oct 2013 21:06:58 -0400</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/essays/letters-to-an-aspiring-programmer-on-loops</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>Hallowindows Time Lapse</title>
			<link>http://krisjordan.com/essays/nmc-window-painting-time-lapse</link>
			<description>
				<![CDATA[
					<p><iframe src="http://www.youtube.com/embed/bJnublhj0PI?modestbranding=1&amp;autohide=1" width="800" height="450" frameborder="0"></iframe></p>
<p>Since we moved into our space on Main Street in Carrboro, now nearly two years ago, we've talked about doing window art. Joel put the pieces in place to make it happen this past Friday for Halloween. <a href="http://www.heymonkeydesign.com/">Lenny Terenzi</a> dropped in to paint life-sized versions of his awesome&#160;<a href="http://instagram.com/p/f2QtZFEr_Q/">Lunchbox Monsters</a>. They turned out great.</p>
<h2>Making the Time Lapse</h2>
<p>We decided to try and shoot a time lapse of the windows being painted. I'd never shot or created a time lapse before, so it was a fun challenge. There are certainly better, more professional ways to put together a time lapse, but for the casual photographer who wants to put one together without super specialized software, here are few tips.</p>
<h3>Stay Warm</h3>
<p>If the temperature is anywhere below comfortable outside, don't underestimate how hard it is to stay warm while sitting still for a few hours. Luckily NMC had an extension cord and a space heater which helped.</p>
<p><a href="http://instagram.com/p/f5oxDqQ6wP/"><img src="http://files.krisjordan.com/hallowindows/warmth.jpeg" alt="Me Trying to Stay Warm" width="640" height="640" /></a></p>
<h3>Canon EOS Utility</h3>
<p>Canon cameras come bundled with a program called EOS Utility. It allows you to control your camera's settings over USB and shoot photos directly to your computer. It also has a timed shutter release feature that works well for doing time lapses. Its only limitation is you can't use an interval less than 5 seconds. EOS utility worked well enough for our purposes.</p>
<h3>Image Quality Settings</h3>
<p>I knew there would be a large number of frames, which would consume space fast in my 5dII's RAW format. The time lapse wound up at 2300 frames. If I shot in RAW, that'd be upwards of 50gb of data. I dialed down to the smallest resolution, high quality JPG mode. In retrospect, if I knew I would be able to consistently crop all of the shots of the same composition I would have probably gone to the middle resolution, high quality JPG mode. One composition wound up needing to be cropped below the video's 1080p resolution.</p>
<h3>Lightroom Bulk Editing with Sync Settings</h3>
<p>If you ever need to apply the same edits to a series of pictures, Lightroom's "Sync Settings" feature is a game changer. I didn't even know it existed prior to doing the shoot. I wish I had. It's like the Copy/Paste Settings functionality for an entire selection of photos. While in the Develop tab, select the batch of photos you want to edit, then focus on the photo with the correct settings, then go to Settings &gt; Sync Settings.</p>
<h3>The Magic is in Post-processing</h3>
<p>Armed with Lightroom, you can turn average source photos into a pretty good looking time lapse. Because the time lapse already feels disconnected from reality, you can be more aggressive with post-process editing than you might otherwise be with stills. At least, that was the theory I operated under. It's fairly rare to see a photographer's before and after post pictures, so I thought it'd be fun to share a few frames. If you don't like knowing how the sausage is made, look away!</p>
<p><strong>Original</strong></p>
<p><strong><img src="http://files.krisjordan.com/hallowindows/candy-before.jpg" alt="Candy Before" width="700" height="394" /></strong></p>
<p><strong>Post-processed</strong></p>
<p><strong><img src="http://files.krisjordan.com/hallowindows/candy-after.jpg" alt="Candy Corn After" width="700" height="394" /></strong></p>
<p><strong>Original</strong></p>
<p><strong><img src="http://files.krisjordan.com/hallowindows/candy-outside-before.jpg" alt="Candy Corn External Before" width="700" height="394" /></strong></p>
<p><strong>Post-processed</strong></p>
<p><strong><img src="http://files.krisjordan.com/hallowindows/candy-outside-after.jpg" alt="Candy Corn External After" width="700" height="394" /></strong></p>
<p><strong>Original</strong></p>
<p><strong><img src="http://files.krisjordan.com/hallowindows/franken-before.jpg" alt="Frankenstein Before" width="700" height="394" /></strong></p>
<p><strong>Post-processed</strong></p>
<p><strong><img src="http://files.krisjordan.com/hallowindows/franken-after.jpg" alt="Frankenstein After" width="700" height="394" /></strong></p>
<p><strong>Original</strong></p>
<p><strong><img src="http://files.krisjordan.com/hallowindows/zombie-before.jpg" alt="Zombie Before" width="700" height="394" /></strong></p>
<p><strong>Post-processed</strong></p>
<p><img src="http://files.krisjordan.com/hallowindows/after-zombie.jpg" alt="Zombie After" width="700" height="394" /></p>
<p><strong>Original</strong></p>
<p><img src="http://files.krisjordan.com/hallowindows/final-before.jpg" alt="Store Front Before" width="700" height="394" /></p>
<p><strong>Post-processed</strong></p>
<p><img src="http://files.krisjordan.com/hallowindows/final-after.jpg" alt="Store Front After" width="700" height="394" /></p>
<h3>iMovie Time Lapse Tips</h3>
<p>iMovie isn't really made to do time lapse or stop motion videos, but it can be done. Dragging in 2,000 images makes iMovie cry and beach ball. Be patient. Once your shots are on the movie's timeline, select all to change the crop away from the Ken Burns Effect Crop and to reduce the duration of the frame. iMovie's lower limit for frame durations is 0.1s. That's OK, because the best way to play with timing is to export this project as a 1080p movie and then reimport that movie into iMovie for the real timing and editing. Trying to do timing/editing with the individual frames would be a world of pain.</p>
<h2>Happy Halloween, Folks!</h2>
				]]>
			</description>
			<pubDate>Sun, 27 Oct 2013 22:22:51 -0400</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/essays/nmc-window-painting-time-lapse</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>The Inverted Pyramid &amp;amp; other Tips on Making Demos</title>
			<link>http://krisjordan.com/essays/tips-on-making-demos</link>
			<description>
				<![CDATA[
					<h3 id="wiretaps_demo_was_fantastic_howd_you_make_it">&#8220;<a href="https://httpkit.com/wiretap">Wiretap</a>&#8217;s demo was fantastic. How&#8217;d you make it?&#8221;</h3>
<p>I was pleasantly surprised to get asked this after releasing&#160;<a href="https://httpkit.com/wiretap">Wiretap</a>'s first demo video. (Embedded below.)</p>
<p>Good demos are hard.</p>
<p>It&#8217;s hard not to get lost in features and technical details. It&#8217;s hard to give enough context, but not too much. It&#8217;s hard to keep a good pace.</p>
<p>I was really afraid of falling into these traps. <a href="https://httpkit.com/wiretap">Wiretap is an HTTP debugger for mobile and web apps integrating with REST APIs</a>. By default, these are the ingredients of a snoozer video.</p>
<p>Here&#8217;s how Wiretap&#8217;s demo avoided putting (most) people to sleep and some other fun, behind-the-scenes details.</p>
<h2><iframe src="http://player.vimeo.com/video/52694108?title=0&amp;byline=0&amp;portrait=0&amp;badge=0&amp;color=ffffff" width="620" height="348" frameborder="0"></iframe></h2>
<h2 id="trust_the_ole_inverted_pyramid">Trust the ole Inverted Pyramid</h2>
<p>Put your most important messages in the beginning. It&#8217;s all most people will see.</p>
<p><strong>If someone stops watching after 30 seconds, will they know what they need to know?</strong></p>
<p>News writers popularized the idea of an <a href="http://en.wikipedia.org/wiki/Inverted_pyramid">Inverted Pyramid</a>, or, &#8220;Bottom Line Up Front&#8221;. The idea is readers should be able to leave a story halfway through and have a good enough understanding of it.</p>
<ul>
<li><img style="float: right;" src="http://files.krisjordan.com/inverted_pyramid-process-s250x213.png" alt="" width="250" height="213" />Who is this product for?</li>
<li>Why does it exist?</li>
<li>What does it do?</li>
<li>How is it used?</li>
<li>When is it useful?</li>
</ul>
<p>The intro to Wiretap&#8217;s demo was something I struggled with. Luckily I got some good feedback on the first take from a friend. More on that in the next section.</p>
<p>In the body of a demo: <strong>tell a story</strong>.</p>
<p>Walk through scenarios that motivate features. Don&#8217;t give a feature tour. Reuse the scenarios you came up with to guide your app&#8217;s design and implementation. Heck, maybe even copy them straight from your BDD tests, if that&#8217;s your bag.</p>
<p>Don&#8217;t expect someone to watch your whole demo, but give them reasons to.</p>
<h2 id="show_friends_act_on_feedback">Show Friends, Act on Feedback</h2>
<p>After hacking on a project for a while it&#8217;s really hard to describe it in a demo context-free.</p>
<p>You need fresh eyes.</p>
<p>Show someone who <em>could be a user</em> of your product but <em>doesn&#8217;t know anything about it yet</em>. Take action on their feedback.</p>
<p>The feedback I got on the first version of my demo was:</p>
<p>&#8220;The intro was missing the why? Why did you build this? Why is it useful?&#8221;</p>
<p>He was right.</p>
<p>(You can <a href="https://vimeo.com/52436748">watch the original with password 'wiretap'</a>.)</p>
<p>I jumped straight into using the product. So I scratched it, recorded new audio, and rearranged the video clips to match. It wasn&#8217;t much work and the improvement was substantial. (It could be better yet: the current intro takes 50 seconds. Tsk, tsk.)</p>
<h2 id="use_bargain_tools_that_are_easy">Use Bargain Tools that are Easy</h2>
<p>Great recording software doesn&#8217;t make a great demo, but it can save you a lot of time. Since folks are always curious about tooling, here&#8217;s what I used.</p>
<p><strong>Video Capture - QuickTime / <a href="http://www.shinywhitebox.com/ishowu-hd/">iShowU HD</a></strong> - Yep, the QuickTime Player installed on every OSX can make screen recordings. Just go to File &gt; New Screen Recording. You can record the screen or a specific bounded rectangle. It&#8217;s a little clunky, though, and lacks some nice features in commercial software like scaling and a better workflow. I&#8217;ve had an iShowU HD license ($30 and worth it) for a few years and used it for the Wiretap demo.</p>
<p><strong>Audio Recording - <a href="http://audacity.sourceforge.net/">Audacity</a></strong> - Awesome, free, open-source software for recording a narration track. This was the first time I wrote a script for a demo and recorded the video and audio independently. It allowed me to crop out places where I misspoke or had long pauses. This helped the pace of the demo. The downside was that the edits and scripting were noticeable at times, but it was good enough.</p>
<p><strong>Post-production - iMovie</strong> - iMovie makes chopping up screen recordings and aligning them with an audio track easy. With software demos you can speed-up and slow-down screen captures to align events with the narration. I abused this freedom. In iMovie just go to &#8216;Clip Adjustments&#8217;, look for the speed section, convert the video, and enter the desired duration of your clip.</p>
<h2 id="have_fun_keep_it_light">Have Fun, Keep it Light</h2>
<p><img class="pull-right" style="float: right;" src="http://files.krisjordan.com/shame-kennel-rnr-process-s160x240.png" alt="" width="160" height="240" /></p>
<p>Sprinkling in some spice won&#8217;t take away from your meat and potatoes.</p>
<p>With Wiretap I wanted to walk through a complete Mobile App + Server-side API + 3rd Party API scenario. Doing something that was the &#8220;AirBnB of ____&#8221; seemed pretty obvious and my dog was laying under my desk looking guilty at the time so I ran with &#8220;ShameKennelRnR&#8221;. I dropped in a few little easter eggs, as well.</p>
<p>Be excited to show off what you&#8217;ve been hacking on and have fun with it.</p>
<hr />
<p><strong>Shameless plug</strong>: Do you hack on REST API integrations or implementations? Wiretap is entering private beta soon. I&#8217;d love your help testing it. Sign-up over on <a href="https://httpkit.com/wiretap">Wiretap's demo page</a>.</p>
				]]>
			</description>
			<pubDate>Thu, 08 Nov 2012 22:13:46 -0500</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/essays/tips-on-making-demos</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>Goodbye, server configuration woes. Hello, Puppet.</title>
			<link>http://krisjordan.com/essays/goodbye-server-configuration-woes-hello-puppet</link>
			<description>
				<![CDATA[
					<p>Another dev is joining your web app project's team. How will you configure their system/VM to be ready for contributing? How will you keep your team's dev server configurations in sync?&#160;Or, the web app you are cranking on is ready to be setup in production. You have a new, clean server awaiting your command. How will you deploy?</p>
<h2>The Marco Polo Method</h2>
<p>SSH in to your new server. You know you need a web server and Ruby or PHP so you <code>sudo apt-get install apache php</code>, or whatever. You copy over an Apache configuration file and enable it as a site. Restart Apache. Marco: directory does not exist. Polo: <code>mkdir /www/awesome-app</code>. Restart Apache. Copy files in. Open up browser. Marco: function <code>pdo mysql driver does not exist</code>. Polo: <code>sudo apt-get install php-pdo-mysql</code> (or whatever). Refresh. Marco: <code>cannot connect to localhost, connection refused</code>. Whoops, forgot to install MySQL. Polo: <code>sudo apt-get install mysql</code>. Eventually, hopefully, it all works.</p>
<p>Deploy by error-Google-fix loop.&#160;Everyone has been down this road before. &#160;The Marco Polo setup is painful, error prone, and time consuming. It's a necessary evil when you are new to configuring systems or rarely have to do it.&#160;The skills you pick up here, though, are fundamental to being successful in evolving to shell scripts and beyond.</p>
<h2>The Scripted Method</h2>
<p>At some point it becomes painfully obvious setting up a system is just running a series of shell commands. What better tool to run a series of commands than a shell script? None, right?</p>
<p>Scripting a complete system setup turns out to be painful, too. Scripts are fragile. All it takes is one remote server being down in the middle of a script and dependent steps will fail. So you try running the script again and the steps that worked are rerun. Source downloads again, recompiles happen, directories already exist, and so on. So you open up the script and either comment out the steps that worked or start wrapping steps in conditionals checking for criteria to be met.</p>
<p>Shell scripts are an imperative approach to mutating a system's state. Your commands describe how to reach a desired state, not what the desired state actually is. By describing steps and not final state the scripted method's sophistication and robustness are a product of time spent crafting the script and an author's ability. In practice, this often leads to scripted setups which are not idempotent; running setup scripts multiple times doesn't generally work without thought and effort. This becomes more troublesome as system setups evolve over the lifetime of a product. Commit logs become riddled with comments like "must run setup script 23-install-redis.sh to run and pass tests". We must be able to abstract away these pains, right?</p>
<h2>The Declarative Method</h2>
<p>Our ideal solution, thus, is automated, declarative, and idempotent. We need a language for describing a system's desired state and a repeatable means for the system to reach that state. Enter Puppet (and other sysadmin automation technologies like Chef).</p>
<p>Puppet is just that: a language for describing a system's desired state and software that can, in essence, diff your system's current state with your desired state and determine the series commands that need to be applied in order to reach that state. It was initially designed for sysadmins managing groups of servers. It's valuable for small custom development projects and single-server deploys, too. For the purposes of this article, we'll only demonstrate its single machine facilities.</p>
<p>Puppet exists in most package manager repositories. On Ubuntu, for example, <code>sudo apt-get install puppet</code> will get you there.</p>
<p>Once Puppet is installed all we need to do is setup a manifest file and run <code>puppet apply</code>. A <code>.pp</code> manifest file uses Puppet's domain-specific language for describing our system's desired state. Let's walk through a simple static HTML nginx server system manifest in Puppet.</p>
<pre># demo.pp
package { "nginx":
    ensure =&gt; installed
}

service { "nginx":
    require =&gt; Package["nginx"],
    ensure =&gt; running,
    enable =&gt; true
}
</pre>
<p>Our <code>demo.pp</code> manifest file opens by declaring the 'nginx' package should be installed and setup as a service. The service requires the package as a dependency and is ensured to be in a running state. Also, it is 'enabled' so that it will start automatically on system boot up.</p>
<p>We can save and apply this puppet manifest file by running <code>sudo puppet apply demo.pp</code> and testing with <code>curl localhost</code>. You should see a dump of nginx's default HTML message. Let's kill the default nginx site with our puppet manifest.</p>
<pre># ...
# demo.pp - part 2 
file { "/etc/nginx/sites-enabled/default":
    require =&gt; Package["nginx"],
    ensure  =&gt; absent,
    notify  =&gt; Service["nginx"]
}
</pre>
<p>The symbolic link enabling the nginx default site will be made <code>absent</code> by Puppet. If reaching this state requires action, as in the symlink being deleted, Puppet will <code>notify</code> the nginx service to reload its configuration automatically. Run <code>sudo puppet apply demo.pp &amp;&amp; curl localhost</code> and it will report nginx is no longer listening; no site is configured. Try running <code>sudo puppet apply demo.pp</code> once more. No actions are taken because the system is already in the desired state. Cool, huh?</p>
<p>Let's setup a new site with a static HTML index file. We'll throw the site in the <code>/www</code> directory.</p>
<pre># ...
# demo.pp - part 3
file { "/www":
    ensure =&gt; "directory"
}
file { "/www/index.html":
    require =&gt; File["/www"],
    ensure =&gt; "file",
    content =&gt; "&lt;!DOCTYPE html&gt;
        &lt;html&gt;&lt;body&gt;
        Hello, world.
        "
}
</pre>
<p>Run <code>sudo puppet apply demo.pp &amp;&amp; ls /www</code> once more to see that our latest additions to the manifest file are setting up the <code>/www</code> directory and then, once it is ready, ensuring the file <code>index.html</code> is placed in the directory with specific contents. Our last step is setting up the nginx configuration for the site in our demo.pp manifest file.</p>
<pre># ...
# demo.pp - part 4
file { "/etc/nginx/sites-available/puppet-demo":
    require =&gt; [
        Package["nginx"],
        File["/www"]
    ],
    ensure =&gt; "file",
    content =&gt; 
        "server {
            listen 80 default_server;
            server_name _;
            location / { root /www; }
        }",
    notify =&gt; Service["nginx"]
}
file { "/etc/nginx/sites-enabled/puppet-demo":
    require =&gt; File["/etc/nginx/sites-available/puppet-demo"],
    ensure =&gt; "link",
    target =&gt; "/etc/nginx/sites-available/puppet-demo",
    notify =&gt; Service["nginx"]
}
</pre>
<p>We've declared an nginx configuration file for our site should be in <code>sites-available</code> and that a symbolic link pointing to that configuration file be placed in <code>sites-enabled</code> to turn the site on. If changes are made to either of these resources nginx will automatically reload its configuration. Run <code>sudo puppet apply demo.pp &amp;&amp; curl localhost</code> and our wonderful hello world HTML file is displayed.</p>
<p>Let's have a little fun showing off the value of Puppet's declarative method. Try turning nginx off with <code>sudo service nginx stop</code>. Rerun <code>sudo puppet apply demo.pp</code>. "Service[nginx] changed from 'stopped' to 'running'". It compared the desired system state, where nginx should be running, with the current system state, and made only the change necessary. We could delete the <code>/www</code> directory, uninstall nginx, and so on, and a simple run of <code>puppet apply</code> will bring us back to our desired state. Same is true on a brand new server.</p>
<p>To be suitable for a gentle introduction to Puppet I have avoided discussing any detail of its language. It is robust. It has variables, units of abstraction and organization, the ability to specify file content with ERB templates, and a great deal more capability than what you have seen here. The practice of putting an entire system definition in a single manifest file is a practice you will quickly outgrow; it is great for learning, though.</p>
<h2>Stop doing the work. Start describing the target.</h2>
<p>Systems can be setup using a variety of methods. From manually pounding away in a shell, to automating repeated installs with shell scripts, to declaring a desired system state in Puppet and letting it figure out what, if anything, needs to be done to get you there. Automating system setups with a declarative configuration tool like Puppet or Chef will change the way you approach both sysops/syadmin work as well as development. With your Puppet manifests stored alongside your projects in source control it is easier to evolve your system setup and your code without getting lost in configuration hell.</p>
<p>Puppet may have been designed for the sysops folks managing farms of servers, but it is also an incredibly valuable technology for smaller teams, single-server projects, and solo devs, who want to abstract away the pains of maintaining system configurations.</p>
				]]>
			</description>
			<pubDate>Wed, 30 May 2012 01:19:31 -0400</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/essays/goodbye-server-configuration-woes-hello-puppet</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>Micro PHP&#039;s Missing Tenet</title>
			<link>http://krisjordan.com/micro-php-manifesto</link>
			<description>
				<![CDATA[
					<p>Ed Finkler's <a href="http://funkatron.com/posts/the-microphp-manifesto.html">post</a> on "MicroPHP Manifesto" made the the rounds last week. It expresses a widely felt desire lurking in the minds of PHP developers. Especially those who have spent time working with libraries from the <a href="http://nodejs.org">Node.js</a> or <a href="http://clojure.org">clojure</a> communities. While the manifesto did a good job covering motivations and aspirations, it missed a key tenet of "micro", and stopped short of covering a few key practical opportunities and obstacles with PHP.</p>
<h2>"I believe functions are the smallest unit of functionality"</h2>
<p>The missing tenet from the Micro PHP Manifesto is: <strong>I believe functions are the smallest unit of functionality</strong>.</p>
<p>Not classes. Not methods. <em>Functions</em>. This belief fits in naturally with, and is a precursor to, most every other tenet of the manifesto.</p>
<p><em>"I like building small things with simple purposes."</em> There is no smaller or simpler reusable unit of functionality than a function.</p>
<p><em>"I like building small things that work together to solve larger problems."</em> Functions and their higher-order friends compose with mathematical simplicity and beauty.</p>
<p><em>"I want code that is easily verifiable."</em> Pure functions are the easiest unit of functionality to test.</p>
<p><em>"I need to justify every piece of code I add to a project."</em> Do we <em>really</em> need to subclass <code>Controller</code> to add a route to our app? Nope, not if you're using <a href="http://www.slimframework.com/">Slim</a>, a great HTTP micro framework (full disclosure [<a href="#footnote-1">1</a>], my office mate wrote it). An anonymous function will do just fine, thank you. Senseless subclassing is what got us into this mess to begin with!&#160;[<a href="#footnote-2">2</a>]</p>
<p>When the traditional PHP framework programmer&#160;looks at a problem, he asks himself these questions, in order of preference:</p>
<ol>
<li>Can I add a method to an existing class?</li>
<li>Can I add a subclass and override a method?</li>
<li>Or should I start a new base class?</li>
</ol>
<p>When the Micro PHP framework programmer looks at a problem, she asks herself these questions:</p>
<ol>
<li>Can I use an anonymous function?</li>
<li>Can I use a named function?</li>
<li>Can I add a method to an existing class?</li>
<li>Can I add a subclass and override a method?</li>
<li>Or should I start a new base class?</li>
</ol>
<p>Namespaced functions and function values being legitimate options in 5.3 enables lighter weight libraries that play together nicely. Combined with <a href="http://jquery.com/">jQuery</a> pushing web developers' collective comfort with a more functional style of programming, the micro PHP movement is in a great position to take off.</p>
<p>But, for the love of <a href="http://en.wikipedia.org/wiki/Rasmus_Lerdorf">Rasmus</a>, PHP has avoided solving two fundamental problems that would radically inspire even smaller, even simpler, even more single-purposed, micro PHP libraries.</p>
<h2><em>Damnit PHP</em>, why can't you just...</h2>
<h3>1. Allow functions to be imported like classes</h3>
<p>User defined functions are second rate compared to user defined classes in the PHP language. You can <a href="http://www.php.net/manual/en/language.namespaces.importing.php">import classes</a> from namespaces but you <a href="http://www.php.net/manual/en/language.namespaces.faq.php#language.namespaces.faq.nofuncconstantuse">can't import functions</a>. Read that again. You can import namespaced classes but not namespaced functions. PHP itself doesn't fully believe that "functions are the smallest unit of functionality". Oh, sweet irony. Most of PHP's <a href="http://www.php.net/manual/en/funcref.php">core functionality</a> (even <a href="http://www.php.net/manual/en/ref.array.php">array manipulation</a>!) is exposed as functions (in a global namespace).</p>
<p>PHP discourages writing plain old functions by making them more painful to reuse than classes. Currently, the best way to write useable "plain old functions" is to write methods on a class you'll only ever invoke statically (i.e., <a href="http://brianhaveri.github.com/Underscore.php/">underscore.php</a>'s <code>__::each</code>). If PHP respected functions they wouldn't need to be wrapped in bastardized classes to be useful.</p>
<h3>2. Indoctrinate a symbol loading algorithm</h3>
<p>So it isn't possible to import namespaced functions directly. But it gets worse. Even using what is available (<code>use namespace; namespace\func();</code>), if the function has not yet been defined, there is no way to autoload that function's source like PHP will do for classes. But it gets worse. The <a href="http://us3.php.net/manual/en/function.spl-autoload-register.php">class loading algorithm</a> is user defined. This is another historical impediment to "micro" component compatibility in PHP, because every framework has its own class loader [<a href="#footnote-3">3</a>]. There is hope in PSR-0, but it won't ship with 5.4.</p>
<p>PHP needs to plant a hard foot in the ground and indoctrinate <strong>one</strong> built-in, automatic symbol loading algorithm that will load classes <em>and</em> functions <em>and</em> constants. The chaos has gone on long enough. If <a href="http://docs.python.org/tutorial/modules.html#packages">Python</a> and <a href="http://nodejs.org/docs/v0.4.8/api/modules.html#loading_from_node_modules_Folders">node.js</a> can be bold enough to do it, so can PHP. The flexibility has stunted our growth.</p>
<p>Please, if you are listening PHP Core Team, for the love of the <a href="http://farm3.staticflickr.com/2009/2218075860_b78fd33f83_z.jpg?zz=1">fat blue elephant</a> in the room, do whatever it takes and break whatever you need to get these fundamental language utilities in the next major point release. Or even the mythical 6.0. The temporary pain will be worth the massive, revitalizing shock it will give to a community of PHP developers who would like to share components and code in a simple and standard way.</p>
<h2>How should micro libraries share plain functions until PHP fixes importing and symbol loading?</h2>
<p><strong>Step 1. Use a PSR-0 class loader</strong> There are plenty. The <a href="http://symfony.com/doc/2.0/components/class_loader.html">Symfony2 ClassLoader</a>'s is good and PSR-0 compliant. It's MIT. Potencier writes great code. Use it.</p>
<p><strong>Step 2. Write plain-old functions as static methods on a bastard, wrapper class.</strong> Ugh. Step 2 is the worst, but distributing plain-old functions puts consumers back in <code>require_once</code> hell. If all you are trying to write and share are plain-old functions, use static methods.</p>
<p><strong>Step 3. Write to your local PHP Core politician.</strong> Demand importable functions and a native, standard symbol loader for PHP.next. Support this PHP <a href="https://wiki.php.net/rfc/autofunc">RFC for function autoloading</a>, and this one for <a href="https://wiki.php.net/rfc/splclassloader">PSR-0 inclusion</a>.</p>
<h2>Finally, will an <a href="http://blog.izs.me/">isaacs</a> please step up? PHP needs a <a href="http://npmjs.org/">modern package manager</a>.</h2>
<p>If someone really wants to blow oxygen on the Micro PHP fire they should start with a new package manager for PHP. PEAR is far too <a href="http://pear.php.net/manual/en/newmaint.proposal.php">bureaucratic</a> and, frankly, <a href="http://pear.php.net/categories/">embarrassing</a> in the face of a modern package manager like node.js's <a href="http://npmjs.org/">npm</a>. PEAR has been around since before PHP5's release in 2004 and there are 179 modules hosted at pear.php.net for 5.0+. (And only 19 for poor <a href="http://pear2.php.net/categories/">PEAR2</a> and PHP 5.3) Contrast with <a href="http://search.npmjs.org/">npm</a> which has been around since August 2010 and hosts 6,157 packages.</p>
<p><em><strong>npm</strong> hosts over 30 times more packages than <strong>PEAR</strong>!?!</em> How? You don't have to pass a <a href="http://pear.php.net/manual/en/newmaint.proposal.php">bureaucratic, written proposal process</a> to publish to npm. Anyone can publish any package they want <a href="http://npmjs.org/doc/developers.html">in under 10 minutes</a>. So do all npm packages have the high quality of PEAR packages? No. Do they all follow the same coding standards like PEAR packages? No. Are these real problems to fear in practice? No. The best packages are naturally high quality and obtain the most attention and dependencies. PEAR is selection by committee, npm is natural selection. The Micro PHP movement really needs a package manager with fewer, smaller rules for publishing and sharing. PEAR may be for sharing small packages with simple purposes, but it is certainly <a href="http://pear.php.net/manual/en/newmaint.proposal.php">not Micro PHP</a>.</p>
<p>(Update: some promising movements in this direction are <a href="http://packagist.org/">Packagist</a> and <a href="https://github.com/lox/phark">Phark</a>.)</p>
<h2>tl;dr</h2>
<p>Functions are the smallest unit of functionality. This is a key missing tenet of the Micro PHP Manifesto. It's a practical precursor to many of <a href="http://funkatron.com/posts/the-microphp-manifesto.html">the others</a>. This isn't to say object-oriented libraries and designs don't have their place in PHP, they most certainly do, but that if you can solve your design problem with functions, choose functions. Prefer small, simple functions over complex, stateful class hierarchies.</p>
<hr />
<h2>Footnotes</h2>
<p>[<a name="footnote-1"></a>1] Even fuller disclosure: I've written a "Full Stack" PHP Framework. A lot of what Ed said is wrong with Zend and Symfony was wrong with <a href="htt://recessframework.org">Recess</a>, which I wrote three years ago. It's intention was to be light weight. In terms of CLOC, it was, under 10k for a RESTful HTTP layer, ORM, "Views", &amp; Annotations. In terms of code written by end-users, it was, comparatively, too. Recess was the first PHP framework to use <a href="http://www.recessframework.org/page/clean-urls-with-route-annotations">Annotations</a>. Declarative-style programming requires less code. I don't use it for new projects anymore. It's still too heavy. It's not line counts or ugly code, though. It caries the PHP 5.2 OOP-only baggage, too [2].</p>
<p>[<a name="footnote-2"></a>2] Ed's post stops short of tracing the legacy leading to the current state of popular frameworks being un-micro. Here's the story. When all you know are objects...all you see are classes. And methods. And private variables. And design patterns. And Java. When all you know is Java all you see is Java.</p>
<p>PHP did not become be one of the <a href="http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html">most popular kids</a> in school without having a "hey look, me too" mindset. PHP grew its popularity in the early 2000s by copying everything it could from Java's object model in the move from PHP4 to PHP5. From <a href="http://www.php.net/manual/en/language.oop5.visibility.php">visibility</a> controls to <a href="http://us3.php.net/manual/en/book.reflection.php">reflection</a>.</p>
<p>When your language is inspired by Java, your libraries and frameworks will be too. You can't look at <a href="http://www.recessframework.org/page/clean-urls-with-route-annotations">Recess' annotations</a> without smelling <a href="https://src.springframework.org/svn/spring-samples/mvc-basic/trunk/src/main/java/org/springframework/samples/mvc/basic/account/AccountController.java">Java</a>. You can't look at <a href="http://www.doctrine-project.org/">Doctrine</a> without smelling <a href="http://www.hibernate.org/">Java</a>. You can't look at <a href="https://github.com/symfony/DependencyInjection">Symfony components</a> without smelling <a href="http://static.springsource.org/spring/docs/2.5.x/reference/beans.html">Java</a>. This isn't to say Symfony is <em>bad</em>, it's not. It's really damned good, but it's manifesto is different. It's manifesto was written by a <a href="http://en.wikipedia.org/wiki/Design_Patterns_(book)">Gang of Four</a>. It's lineage predates PHP 5.3. Popular frameworks and libraries originating before PHP 5.3's release carry the burden of pursuing <a href="http://symfony.com/doc/current/cookbook/service_container/factories.html">best practice object-oriented patterns</a> at the cost of ignoring perfect opportunities where standalone or anonymous functions would suffice.</p>
<p>[<a name="footnote-3"></a>3] PEAR/Zend-style <a href="http://framework.zend.com/manual/en/coding-standard.naming-conventions.html">class naming</a> and directory structuring became somewhat of a norm before 5.3, but it sucked. <em>Class names</em> were combined with <em>namespaces</em> which lead to instantiating classes with names like <a href="http://framework.zend.com/manual/en/zend.db.table.definition.html"><code>Zend_Db_Table_Definition</code></a>. Only in recent history, since 5.3 namespaces, has the community embraced a "standard" class loading algorithm with <a href="https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md">PSR-0</a>. (Design by committee retained PEAR-style support, which is unfortunate, but I digress.) In theory this will make its way into the Standard PHP Library and be bundled with PHP, which will be great.</p>
				]]>
			</description>
			<pubDate>Tue, 10 Jan 2012 01:52:07 -0500</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/micro-php-manifesto</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>multimethod.js</title>
			<link>http://krisjordan.com/multimethod-js</link>
			<description>
				<![CDATA[
					<h2>What is a multimethod?</h2>
<p>The quickest way to understand is by looking at a simple, familiar example implemented with a multimethod. So let's write a recursive Fibonacci function.</p>
<pre>&gt; var fib = multimethod()
                .when( 0, 0 )
                .when( 1, 1 )
                .default( function(n) {
                    return fib(n-1) + fib(n-2);
                });
&gt; fib(20);
6765</pre>
<p>Multimethods are a functional programming "control structure" enabling you to dynamically build-up and manipulate the dispatching behavior of a polymorphic function. Inspired by <a href="http://clojure.org/multimethods">Clojure's multimethods</a>, multimethod.js provides a functional alternative to classical, prototype based polymorphism. The multimethod.js library is MIT licensed, is found on <a href="https://github.com/KrisJordan/multimethod-js">GitHub</a>&#160;and <a href="http://search.npmjs.org/#/multimethod">npm</a> with <code>npm install multimethod</code>, and its&#160;annotated source code&#160;is <a href="http://files.krisjordan.com/multimethod-js/multimethod.html">available here</a>.</p>
<h2>Motivating Examples</h2>
<p>Let's use the node.js REPL to build a few multimethods and see what they are capable of doing. In this first example we'll create a mulimethod that calculates the area of shapes instantiated with object literals.</p>
<pre>&gt; var multimethod = require('multimethod');
&gt; var area = multimethod()
                .dispatch(function(o) {
                    return o.shape;
                })
                .when("square", function(o) {
                    return Math.pow(o.side, 2);
                });
&gt; var aSquare = { "shape":"square", "side": 2 };
&gt; area( aSquare );
4

&gt; var aCircle = { "shape":"circle", "radius": 5 };
&gt; area( aCircle );
undefined

&gt; area.default(function(o) { 
    throw "Unknown shape: " + o.shape;
  });
&gt; area( aCircle );
Unknown Shape: circle

&gt; area.when("circle", function(o) {
    return Math.PI * Math.pow(o.radius, 2);
  });
&gt; area( aCircle );
78.53981633974483
&gt; area( aSquare );
4

&gt; area.remove("circle");
&gt; area( aCircle );
Unknown Shape: circle
</pre>
<p>Notice how <code>dispatch</code> returns the value we'll match to a "method" registered with <code>when</code>. You can introduce, overwrite, and remove new methods dynamically at runtime. Fallback behavior can be established with a <code>default</code> function called when no methods match the dispatched value.</p>
<pre>&gt; var hitPoints = multimethod()
                    .dispatch(function(player){ return player.powerUp; })
                    .when( {"type":"star"} , Infinity)
                    .default(5);

&gt; var starPower = { "type":"star" },
&gt;     mario = { "powerUp": starPower };
&gt; hitPoints(mario);
Infinity

&gt; mario.powerUp = null;
&gt; hitPoints(mario);
5

&gt; var godModeCheat = function() { return starPower; };
&gt; hitPoints.dispatch(godModeCheat);
&gt; mario.powerUp;
null
&gt; hitPoints(mario);
Infinity
</pre>
<p>In this last example notice how we are matching against an object. Matching is done using deep equality so objects and arrays are valid method matching criteria. Also notice how we can completely override our dispatch function to change the logic with which a multimethod evaluates its arguments for dispatch, or, in this case, ignores them!</p>
<h2>Multimethod Dispatch Algorithm</h2>
<ol>
<li>User calls multimethod with argument <code>anArgument</code>.</li>
<li>Multimethod calls its <code>dispatch</code> function with <code>anArgument</code>. The returned value is stored in <code>dispatchValue</code>.</li>
<li>Multimethod iterates through each 'method' registered with <code>when</code> and performs an equality test on the <code>dispatchValue</code> and each method's match value. If a match is found, set <code>matchFunction</code> to the method's function and go to step 5.</li>
<li>If no method match found, set <code>matchFunction</code> to the multimethod's <code>default</code> function.</li>
<li>Multimethod calls <code>matchFunction</code> with <code>anArgument</code>. The returned value is returned to the user who called the multimethod.</li>
</ol>
<h2>A More Detailed Walkthrough</h2>
<h3>The Basics</h3>
<p>A <code>multimethod</code> is instantiated with the <code>multimethod</code> function.</p>
<pre>var stopLightColor = multimethod();
</pre>
<p>A <code>multimethod</code> has methods. A <code>method</code> is has two parts, its match value and its implementation function. Methods are added using <code>when</code>.</p>
<pre>stopLightColor.when("go",    function() { return "green"; })
              .when("stop",  function() { return "red"; });
</pre>
<p>You can call a <code>multimethod</code> just like any other function. It will dispatch based on the argument(s) passed in, invoke the matched <code>method</code>, and return the results of the <code>method</code> call.</p>
<pre>console.log( stopLightColor("go") ); // "green"
</pre>
<p>When no method matches control can fallback to a <code>default</code> method.</p>
<pre>stopLightColor.default( function() { return "unknown"; } );
console.log( stopLightColor("yield") ); // prints "unknown"
</pre>
<p>A <code>multimethod</code> can handle new cases dynamically at run time.</p>
<pre>stopLightColor.when("yield", function() { return "yellow"; });
</pre>
<p>There is a shorter way for a <code>method</code> to return a plain value. Rather than passing an implementation function to <code>when</code>, pass the value.</p>
<pre>stopLightColor.when("yield", "yellow");
console.log( stopLightColor("yield") ); // prints "yellow"
</pre>
<p>A <code>method</code> can be removed dynamically at run time, too.</p>
<pre>stopLightColor.remove("go");
console.log( stopLightColor("go") ); // prints "unknown"
</pre>
<h3>Dispatch Function</h3>
<p>Each <code>multimethod</code> call first invokes a <code>dispatch</code> function whose return value is used to match the correct <code>method</code> to call. The <code>dispatch</code> function is passed the arguments the <code>multimethod</code> is invoked with and returns a value to match against.</p>
<p>The default <code>dispatch</code> function is an identity function. The basic <code>stopLightColor</code> examples could have been created with an explicit <code>dispatch</code> function.</p>
<pre>var stopLightColor = multimethod()
      .dispatch(function(state){
         return state;
      })
      .when('go', 'green');
console.log( stopLightColor('go') ); // green
</pre>
<p>The power of the <code>multimethod</code> paradigm is the ability to dispatch with a user-defined function. This gives a <code>multimethod</code> its "polymorphic" powers. Unlike classical, object-oriented polymorphism where the compiler dispatches based on the type hierarchy, a <code>multimethod</code> can dispatch on any criteria.</p>
<pre>var contacts = [
  {"name":"Jack", "service":"Twitter","handle": "@jack"},
  {"name":"Diane","service":"Email",  "address":"d@g.com"},
  {"name":"John", "service":"Phone",  "number": "919-919-9191"}
];

var sendMessage = multimethod()
     .dispatch(function(contact, msg) {
       return contact.service;
     })
     .when("Twitter", function(contact, msg) {
       console.log("Tweet @"+contact.handle+":"+msg);
     })
     .when("Email", function(contact, msg) {
       console.log("Emailing "+contact.address+":"+msg);
     })
     .default(function(contact, msg) {
       console.log("Could not message " + contact.name);
     });

// Blast a message
contacts.forEach( function(contact) {
  sendMessage(contact, "Hello, world."); 
});
</pre>
<p>Plucking a single property from an object is so commonly used as a <code>dispatch</code> function, like in the example above, there is a shortcut for this pattern. The following <code>dispatch</code> call is equivalent to above.</p>
<pre>sendMessage.dispatch( 'service' );
</pre>
<p>A <code>multimethod</code>'s <code>dispatch</code> is usually specified when constructed.</p>
<pre>var sendMessage = multimethod('service');
</pre>
<p>Just like <code>method</code>s can be added and removed from a <code>multimethod</code> at run time, the <code>dispatch</code> function can also be redefined at run time. Ponder the implications of that for a minute. It is really powerful and really dangerous. Don't shoot your eye out.</p>
<h3>Deep Equality Matching</h3>
<p>A <code>method</code>'s match value is compared to <code>dispatch</code>'s return value using the underscore.js <a href="http://documentcloud.github.com/underscore/#isEqual"><code>isEqual</code></a> function. Deep equality <code>method</code> matching enables concise expressivity. Contrast this with a traditional <code>switch</code> statement that is limited by JavaScript's === equality behavior.</p>
<pre>var greatPairs = multimethod()
      .when( ["Salt", "Pepper"], "Shakers" )
      .when( [{"name":"Bonnie"}, {"name":"Clyde"}], "Robbers" );
console.log( greatPairs( ["Salt", "Pepper"] ) ); // Shakers
</pre>
<h2>API Recap</h2>
<ul>
<li>Constructor: <code>multimethod</code>( [fn | string] ): No arg constructor uses an identity function for <code>dispatch</code>. Single arg constructor is a shortcut for calling <code>dispatch</code> with the same argument.</li>
<li><code>dispatch</code>(fn | string): Sets the <code>multimethod</code>'s <code>dispatch</code> function. String values are transformed into a pluck function which projects a single property value from the first argurment.</li>
<li><code>when</code>(match, fn | value): Add a <code>method</code> to be invoked when the <code>dispatch</code> return value matches 'match'. If a non-function <code>value</code> is provided it will be returned directly. Calling <code>when</code> with the same <code>match</code> value twice will override the previously registered <code>method</code>.</li>
<li><code>remove</code>(match): Remove a <code>method</code> by it's <code>match</code> value.</li>
<li><code>default</code>(fn | value): Catch-all case when no <code>method</code> match is found.</li>
</ul>
<h2>Installation</h2>
<p>Install with <code>npm</code> for use in node.js based projects.</p>
<pre>npm install multimethod
node
&gt; var multimethod = require('multimethod');
</pre>
<p>For in-browser use you will need to grab <a href="http://documentcloud.github.com/underscore/">underscore.js</a> and multimethod.js:</p>
<ul>
<li>underscore.js
<ul>
<li>Development: <a href="http://documentcloud.github.com/underscore/underscore.js">http://documentcloud.github.com/underscore/underscore.js</a></li>
<li>Minified: <a href="http://documentcloud.github.com/underscore/underscore-min.js">http://documentcloud.github.com/underscore/underscore-min.js</a></li>
</ul>
</li>
<li>multimethod.js
<ul>
<li>Development: <a href="https://raw.github.com/KrisJordan/multimethod-js/master/multimethod.js">https://raw.github.com/KrisJordan/multimethod-js/master/multimethod.js</a></li>
<li>Minified: <a href="https://raw.github.com/KrisJordan/multimethod-js/master/multimethod-min.js">https://raw.github.com/KrisJordan/multimethod-js/master/multimethod-min.js</a></li>
</ul>
</li>
</ul>
<h3>How-to Contribute</h3>
<ul>
<li>Submit bugs and feature requests on <a href="https://github.com/KrisJordan/multimethod-js/issues">GitHub Issues</a> page.</li>
<li>Fork the repository and submit pull requests. Pull requests that update the test suite for coverage on changes will be brought in quickly.</li>
</ul>
				]]>
			</description>
			<pubDate>Thu, 15 Dec 2011 17:40:00 -0500</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/multimethod-js</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>Fixing WebKit&#039;s Accept Header</title>
			<link>http://krisjordan.com/fixing-webkits-accept-header-to-support-content-negotiation-and-rest</link>
			<description>
				<![CDATA[
					<p>WebKit has been on the forefront of web browser innovation for years, but their HTTP Accept header has lagged behind. (tl;dr <a href="https://bugs.webkit.org/show_bug.cgi?id=27267">it is fixed now</a>.) The Accept header is how the web browser says to the web server "these are the content-types I can understand and the order in which I prefer them." For more detail, wrote about it in more detail on the <a href="http://www.gethifi.com/blog/browser-rest-http-accept-headers">HiFi CMS Blog</a>.</p>
<p>The <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html">Accept header</a> allows a single object or&nbsp;<em>resource</em> to have a single URI with multiple <em>representations</em>, such as HTML, XML, or JSON. It is a fundamental component of the <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html">HTTP spec</a> and REST style web services. Unfortunately, today's web services rarely use content-negotiation, because browsers have historically chosen bad Accept headers. <a href="http://www.webkit.org/">WebKit</a>'s&nbsp;was the last serious offender:</p>
<pre>application/xml,
application/xhtml+xml,
text/html;q=0.9,
text/plain;q=0.8,
image/png,
*/*;q=0.5       </pre>
<p>Parsed and prioritized:</p>
<pre>1. application/xml
2. application/xhtml+xml
3. image/png
4. text/html
5. text/plain
6. */*
</pre>
<p><a href="http://www.gethifi.com/blog/browser-rest-http-accept-headers">WebKit's Accept header preferred XML over HTML</a>&nbsp;prior to&nbsp;my fix <a href="https://bugs.webkit.org/show_bug.cgi?id=27267">landing in trunk today</a>. Web services could not offer both HTML and XML for a single resource and use content negotiation because WebKit based browsers (Safari, Chrome, et. al.) would be served the XML data not the HTML web page. Developers have had to hack around the issue. <a href="http://apiwiki.twitter.com/w/page/22554648/FrontPage">Twitter's API</a>, for example, uses a common work around that changes the URI by&nbsp;<a href="http://dev.twitter.com/doc/get/statuses/friends_timeline">appending a format extension</a>.</p>
<pre>http://api.twitter.com/<em>version</em>/statuses/friends_timeline.<em>format</em>
format ::= json | xml | rss | atom</pre>
<p>The goal of the fix for WebKit's Accept header was straightforward: prefer HTML over XML. The ultimate solution was to minimize risk and take Firefox's lead. Here is the Accept header, already in order of preference, WebKit-based browsers will be using in the future:</p>
<pre>text/html,
application/xhtml+xml,
application/xml;q=0.9,
*.*;q=0.8</pre>
<h2>Contributing to Open Source Software</h2>
<p><img class="right" src="http://files.krisjordan.com/webkit-contribution-process-s354x148.png" alt="WebKit Contribution" width="354" height="148" />The fix may have been committed today, but the&nbsp;<a href="https://bugs.webkit.org/show_bug.cgi?id=27267">initial bug report was filed in July 2009</a>, almost two years ago! What took such a simple, but important, fix so long to be made?&nbsp;I would like to say it was the need for <a href="https://bugs.webkit.org/show_bug.cgi?id=27267#c4">five other people to chime in</a> on the ticket, <a href="https://bugs.webkit.org/show_bug.cgi?id=27267#c2">someone on the WebKit team to notice</a>, or <a href="https://bugs.webkit.org/show_bug.cgi?id=27267#c0">a duplicate bug request</a> to be filed 15,000 tickets later. But no, <a href="https://bugs.webkit.org/show_bug.cgi?id=27267#c7">all the WebKit team needed</a> was for someone, <em>anyone</em>, to submit a patch. So I checked out the subversion repository, made a patch, submitted it, and boom, <a href="http://trac.webkit.org/browser/trunk/Source/WebCore/loader/FrameLoader.cpp#L7">I have contributed code to WebKit</a> and fixed its Accept header woes. Very cool, but I feel <em>horrible</em> for not doing so with the original bug report in 2009; content negotiation would be more usable today.</p>
<p><strong>Lesson learned</strong>: no matter how big or small an open source project is, when you find a bug and know the fix&nbsp;<em>just do it</em>. Do not assume code to be sacred or untouchable; <em>just <a href="http://www.hulu.com/watch/38477/saturday-night-live-update-thursday-fix-it">fix it</a>&nbsp;</em>and let the committers make the call. Bug reports are helpful, but patches and pull requests are gold. Discussions get read, code gets committed.&nbsp;<em>Code speaks louder than words.</em></p>
				]]>
			</description>
			<pubDate>Thu, 10 Mar 2011 21:25:56 -0500</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/fixing-webkits-accept-header-to-support-content-negotiation-and-rest</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>Refactoring Cache Tables using Memoize</title>
			<link>http://krisjordan.com/refactor-with-memoize</link>
			<description>
				<![CDATA[
					<p>Have you ever written code that feels like this?</p>
<pre>var byKey = function (key) {
	... do slow, expensive stuff ...
	return { value: &ldquo;something expensive&rdquo; };
};</pre>
<p>And later optimized it to feel like this?</p>
<pre>var lookup = {};
var byKey = function (key) {
    if ( lookup[key] === undefined ) {
        ... do slow, expensive stuff ...
        lookup[key] = { name: &ldquo;something expensive&rdquo; };
    }
    return lookup[key];
};</pre>
<p>I certainly have. The lookup table is a trusty pattern for caching the results of expensive calls. With four additional lines of code you can dramatically improve the performance of an often called function. Sprinkle these lines around your most expensive, <a href="http://en.wikipedia.org/wiki/Referential_transparency_(computer_science)">referentially transparent</a> functions and you have a nicely optimized program, right?</p>
<p>With a functional language this pattern is considered harmful; an anti-pattern to refactor. It may be four lines of code, but it is redundant when used over and over. Your function&rsquo;s intentions become conflated with performance concerns. It would be best to keep our intentions and optimizations separate.</p>
<p>Can we simply write &ldquo;cache this function&rsquo;s return values&rdquo;? It would feel like this,</p>
<pre>var byKey = cache( function(key) {
    ... do expensive stuff ...
    return { name: &ldquo;something expensive&rdquo; };
} );</pre>
<p>That feels much better. Although, not knowing what the <code>cache</code> function actually does is a little off-putting. Let&rsquo;s implement it.</p>
<blockquote>If you are unfamiliar with anonymous functions and closures in JavaScript this is about to get slightly hairy. Understanding those concepts will make writing JavaScript much more interesting, and little blog posts like this more palatable. I suggest <a href="http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742">Crockford</a>, but there are plenty of <a href="https://developer.mozilla.org/en/JavaScript/Guide/Closures">good on-line resources</a>, too.</blockquote>
<p>We need our <code>cache</code> function to take any function we throw at it and return a new function. The returned function must accomplish what our imperative lookup table code did: remember the arguments of previous invocations and cache their return values.</p>
<pre><code>var cache = function( expensiveFn ) {
    var lookup = { };
    return function(key) {
        if(lookup[key] === undefined) {
            lookup[key] = expensiveFn(key);
        }
        return lookup[key];
    };
};</code></pre>
<p>Let's walk through this. We have defined <code>cache</code> as a function that takes expensiveFn as a parameter. Within this function we setup the variable lookup to be our hash/cache table. Then we return a function that encapsulates the lookup table pattern used earlier. Do you see how the structure has been extracted and the state hidden within the closure?</p>
<p>In computer science this function is conventionally named <code>memoize</code>. It is often demonstrated using a recursive function like <code>factorial</code>. Factorial is a more beautiful application of memoization than basic key-value caching, but this is an anti-patterm you are more likely to find in real code.</p>
<h3>An Exercise for the Reader</h3>
<p>The most obvious shortcoming to <code>cache</code>, our implementation of <code>memoize</code>, is that it does not generalize to functions of more than one argument. If you have a few minutes, pop open your browser&rsquo;s JavaScript console in Firebug or Webkit Inspector and try writing it.&nbsp;Hints: 1) The <code>arguments</code> keyword provides an array of all arguments a function is called with. 2) A function can be invoked with an array of arguments by using <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/function/apply">Function's <code>apply</code> method</a>.</p>
<h2>Refactor one-off caching via lookup tables with <code>memoize</code></h2>
<p>Plenty of libraries provide a generic memoize function, including <a href="http://documentcloud.github.com/underscore/#memoize">underscore</a> in JavaScript. The next time you catch yourself writing a naive in-memory cache lookup table around a function stop and consider memoizing it instead. Using <code>memoize</code> is faster to write and less bug-prone than a one-off cache, it separates intentional concerns from optimization concerns, and it keeps your code a little cleaner.</p>
				]]>
			</description>
			<pubDate>Sun, 06 Mar 2011 20:51:33 -0500</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/refactor-with-memoize</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>On Muted Methods, Fluent Interfaces, and Bar Game</title>
			<link>http://krisjordan.com/2009/08/24/on-muted-methods-and-fluent-interfaces</link>
			<description>
				<![CDATA[
					<p>One night a weekend back I went out to the local bar back home with my younger sister some of our friends. Back home means Rutherfordton, North Carolina. The kind of charming area that greets you at the county line with the road sign "Welcome to Rutherford County, Small Town Friendly". A friendly place, it is.</p>
<p>While sitting at the bar one of my sisters' friends drew a lot of attention from the gentlemen of Rutherford County. We'll call her Liz (gah, when does 30Rock start up again??). Some would come up and chat, others ask for a dance. The most peculiar case of them all was one who had been ordering drinks from across the bar and finally got up the courage to come over and, without a word, slip Liz a piece of paper with his phone number on it before disappearing into the night.</p>
<p>Yes, this post is about programming, bear with me.</p>
<p>Let's give this guy, say Dennis, the benefit of the doubt and assume that these tactics have worked before with success. On this particular night with a gorgeous girl from out of town: no dice. Dennis wouldn't get the callback.</p>
<p>Let's pseudo-code this scenario:</p>
<pre>$liz = new AttractiveOutOfTownGirl();
$dennis = new SmallTownFriendlyYoungMan();
$liz-&gt;setDrink($dennis-&gt;buyDrink('Vodka Redbull'));
$liz-&gt;setDrink($dennis-&gt;buyDrink('Sex on the Beach'));
$liz-&gt;receiveNumber($dennis-&gt;getPagerNumber());
$dennis-&gt;disappearIntoTheNight();</pre>
<p>Spot any patterns? Thrice Dennis has taken an action that results in some value: he's bought 2 drinks and retrieved his pager number. All of his methods have resulted in some value that is handed to Liz and he's getting no acknowledgement back. He interacted with <strong>muted methods</strong>. Dennis' shot at success depended on Liz having some internal, finite state machine that transitioned from "stranger" to&nbsp; "stranger willing to call a stranger" with every additional drink. How could this have gone better for Dennis?</p>
<p>Before we get there let's talk about <strong>muted methods</strong>. Procedures. Voids. <strong>Black holes in programs where input results in no output. Scary stuff!</strong> But why, what's so bad about muted functions? Let's nitpick our example. It is so&nbsp; <em>choppy</em>. Do you feel the <em>choppiness</em>?</p>
<pre>Noun verb.
Noun verb.
Noun verb.
Liz set drink.
Liz set drink.
Liz give number.</pre>
<p>When your verb is muted, there's nothing more to be said. End of story. Next line. You've got nothing to play off of, no chance to converse. <strong>When you're working with muted functions you have no segue</strong>. You're giving without receiving.</p>
<p>If muted functions are the problem, how could this scene look a little less ugly? Perhaps Dennis could have conversed with Liz. Interacted with her. Made use of a more <strong>fluent interface</strong>...</p>
<pre>$dennis-&gt;saysTo($liz, "Hey girl, from out of town?") // returns $liz
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&gt;saysTo($dennis, "Yes, how'd you know?") // returns $dennis
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&gt;saysTo($liz, "Never did seen you before!") // returns $liz
       -&gt;isStillSmiling()
       ? // If she's smiling
   $liz-&gt;setDrink($dennis-&gt;buyDrink('Vodka Redbull')) // returns $liz
       -&gt;saysTo($dennis, "Thanks, you're kind of cute.")
       -&gt;saysTo($liz, "That's how we're grown here. Can I call you?")
       -&gt;saysTo($dennis, "Sure, my name is Liz and the number is...")
       -&gt;punchesInNumber("919-928-9090") // returns $dennis
       -&gt;says("Great, call you tomorrow!") // returns $dennis
       -&gt;disappearIntoTheNight()
       : // If she's frowning
   $dennis-&gt;movesAlong();</pre>
<p>When you're not dealing with muted methods you give your code the chance to come to life in a more fluid, fluent way. There's only sentences here, it's just longer, richer, and more involved. There's magical, programmatic banter happening here!</p>
<p>This style of object-oriented interface, where <em>method chaining</em> and <em>thoughtful return values</em> enable a pseudo-domain specific language written entirely in a general purpose language, has been called a <a href="http://martinfowler.com/bliki/FluentInterface.html">"Fluent Interface" by Martin Fowler and Eric Evans</a>. It's an inspiring departure from the days of the void, black hole methods like setters.</p>
<p>So, next time you're writing an interface for some new class, or sitting at a bar wondering how best to approach that attractive member of the opposite sex, avoid muted methods at all costs. They're black holes. They're just awkward, feedbackless, and overall uncomfortable for everyone involved.</p>
<p>When your functions or methods don't return ask yourself "if I <em>were </em>to return something here <em>what </em>would be useful?" Most often, it's a reference to the object itself. Or an immutable clone.</p>
<p>"Oh, god no, not an immutable clone! I thought this article was about bar game?" Hmm... you're right. I'll save the immutable clone wars for another post. <a href="http://feeds.feedburner.com/KrisJordan">You should subscribe to this RSS feed if immutable clones pique your interest. Or nerdy bar game.</a></p>
<div id="_mcePaste" style="overflow: hidden; position: absolute; left: -10000px; top: 291px; width: 1px; height: 1px;">setDrink($this-&gt;buyDrink('Vodka Redbull'));</div>
				]]>
			</description>
			<pubDate>Mon, 24 Aug 2009 23:47:02 -0400</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/2009/08/24/on-muted-methods-and-fluent-interfaces</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>What&#039;s on my mind...</title>
			<link>http://krisjordan.com/2009/08/20/whats-on-my-mind</link>
			<description>
				<![CDATA[
					<p>In an hour I'll be out doing late night trivia in a bar in Chapel Hill, North Carolina. Pop trivia has never been something I excel at, but with the right company it's fun to wager a guess, or two, and let go of the problems that consume idle cycles. As of late my thought has been switching between any of the following:</p>
<ul>
	<li><a href="http://www.newmediacampaigns.com/page/the-throw-away-computer-virtualization">Using virtual machines and shell scripts to achieve the Ultimate Small Team Software Engineering Environment</a> (tm)</li>
	<li>Real Software Engineering in PHP</li>
	<li>Trees, Recursion, Permissions, and Architecture of <a href="http://www.newmediacampaigns.com/">my company</a>'s next <a href="http://www.newmediacampaigns.com/page/content-management-system">Content Management System</a></li>
	<li>How to simplify internals and increase functionality of the Recess Framework by leveraging PHP 5.3's new features like <a href="http://www.recessframework.org/page/functional-php-anonymous-functions-lambdas-closures">anonymous functions</a> and <a href="http://www.newmediacampaigns.com/page/php-namespaces-backslash-example">namespaces</a></li>
	<li>A big client integration project that deals with scary acronyms like HIPAA</li>
</ul>
<p>This space should be more lively than the ghosttown that it has become over the last 8 months. More off the cuff writing on the topic of the hour than the more structured pieces I've been writing for <a href="http://www.newmediacampaigns.com/">New Media</a>'s <a href="http://www.newmediacampaigns.com/blog/category/Development">Web Development Blog</a> or the Recess <a href="http://www.recessframework.org/blog">PHP Blog</a>.
</p><p>
To kick that off the off the cuff writing, <a href="http://ejohn.org/blog/eulogy-to-_why/">a few words on _why</a>. I don't know _why, I haven't read the <a href="http://www.ember.co.nz/files/resources/whys-poignant-guide-to-ruby.pdf">poignant guide</a> to Ruby (although I've come across it a number of occasions and been intrigued), nor have I used much of his huge body of open source work. None the less his recent disappearance has been sitting really funny on my stomach. Really funny. This guy is prolithic, talented, and obsessed with teaching the art and joy of programming. I didn't fully appreciate _why until watching <a href="http://www.vimeo.com/5047563?pg=embed&amp;sec=">his recent talk at Carnegie Melon</a> [embedded below]. His excitement and creative knack for opening programming up to a younger audience is energizing. Here's to hoping an even brighter chapter to that story is about to unfold...
</p>
<object width="400" height="220" data="http://vimeo.com/moogaloop.swf?clip_id=5047563&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" type="application/x-shockwave-flash"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://vimeo.com/moogaloop.swf?clip_id=5047563&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" /></object>
				]]>
			</description>
			<pubDate>Thu, 20 Aug 2009 22:39:50 -0400</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/2009/08/20/whats-on-my-mind</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>Recess! Framework Screencast #1</title>
			<link>http://krisjordan.com/2008/12/16/recess-framework-screencast-1</link>
			<description>
				<![CDATA[
					<p>I'm excited to get the first Recess! screencast out on the interwebs over at <a href="http://www.recessframework.org">RecessFramework.org</a>. Special thanks to <a href="http://www.twitter.com/JoelSutherland">Joel Sutherland</a> and the <a href="http://www.newmediacampaigns.com">Raleigh Web Design</a> firm <a href="http://www.newmediacampaigns.com">New Media Campaigns</a> for helping me launch the Recess site in record time!
</p><p>
Without further adieu... <a href="http://www.recessframework.org/page/routing-in-recess-screencast">Routing in Recess</a>!
</p><p>
<a href="http://www.recessframework.org/page/routing-in-recess-screencast"><img class="size-full wp-image-575" title="Recess! Framework" src="http://files.kris.gethifi.com/recesshomepage.gif" alt="Recess! PHP Framework" width="400" height="249" /></a> </p>
				]]>
			</description>
			<pubDate>Tue, 16 Dec 2008 22:34:44 -0500</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/2008/12/16/recess-framework-screencast-1</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>Towards RESTful PHP - 5 Basic Tips</title>
			<link>http://krisjordan.com/2008/12/02/towards-restful-php-5-basic-tips</link>
			<description>
				<![CDATA[
					<strong>What is REST?</strong>
<p>REST is an architectural style, or set of conventions, for web applications and services that centers itself around <em>resource manipulation</em> and the HTTP spec. Web apps have traditionally ignored the HTTP spec and moved forward using a subset of the protocol: GET and POST,  200 OKs and 404 NOT FOUNDs.  As we entered a programmable web of applications with APIs the decision to ignore HTTP gave us problems we're still dealing with today. We have an internet full of applications with different interfaces (GET /user/1/delete vs. POST /user/delete {id=1}). With REST we can say <em>/user/1 is a resource</em> and use the HTTP DELETE verb to delete it. For more detail on REST check out <a href="http://en.wikipedia.org/wiki/REST">wikipedia</a> and "<a href="http://www.megginson.com/blogs/quoderat/2007/02/15/rest-the-quick-pitch/">quick pitch</a>".</p>
<h2>Tip #1: Using PUT and DELETE methods</h2>
<p>In PHP you can determine which HTTP method was used with: $_SERVER['REQUEST_METHOD']; From web browsers this will be either GET or POST. For RESTful clients applications need to support PUT and DELETE (and ideally OPTIONS, etc.) as well. Unfortunately PHP doesn't have $_PUT and $_DELETE variables like it does $_POST and $_GET. Here's how to access the content of a PUT request in PHP:</p>
<pre class="php" name="code">$_PUT  = array();
<p>if($_SERVER['REQUEST_METHOD'] == 'PUT') {</p>
<p>    $putdata = file_get_contents('php://input');</p>
<p>    $exploded = explode('&amp;', $putdata); 
</p><p>
    foreach($exploded as $pair) {</p>
<p>        $item = explode('=', $pair);</p>
<p>        if(count($item) == 2) {</p>
<p>            $_PUT[urldecode($item[0])] = urldecode($item[1]);</p>
<p>        }</p>
<p>    }</p>
}</pre>
<h2>Tip #2: Send Custom HTTP/1.1 Headers</h2>
<p>PHP's <a href="http://www.php.net/header">header</a> function allows custom HTTP headers to be sent to the client. The HTTP/1.x header contains the <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html">response code</a> from the server. PHP will, by default, send back a 200 OK status code which suggests that the request has succeeded even if it has die()'ed or a new resource has been created. There are two ways to change the status code of your response:</p>
<pre class="php" name="code">header('HTTP/1.1 404 Not Found');
<p>/* OR */</p>
header('Location: http://www.foo.com/bar', true, 201); // 201 CREATED</pre>
<p>The first line is a generic way of setting the response status code. If your response requires another header, like the Location header to the resource of a '201 Created' or '301 Moved Permanently', placing the integer status code in the third parameter of header is a shortcut. It is the logical equivalent of the following example, which is easier to read at the cost of being an extra line of code.</p>
<pre class="php" name="code">header('HTTP/1.1 201 Created');
header('Location: http://www.foo.com/bar');</pre>
<h2>Tip #3: Send Meaningful HTTP Headers</h2>
<p>Policy for deciding when it is appropriate to send each HTTP status code is a full post on its own and the <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html">HTTP spec</a> leaves room for ambiguity. There are <a href="http://www.xml.com/pub/a/2004/12/01/restful-web.html">many</a> <a href="http://blog.brianguthrie.com/articles/2008/08/22/rails-and-rest-a-reference-to-commonly-used-http-status-codes-and-their-use-in-rest-apis">other</a> resources on the net which provide insights so I'll just touch on a few.
</p><p>
<strong>201 Created</strong> is used when a new resource has been created. It should include a Location header which specifies the URL for the resource (i.e. books/1). The inclusion of a location header does not automatically forward the client to the resource, rather, 201 Created responses should include an entity (message body) which lists the location of the resource.
</p><p>
<strong>202 Accepted</strong> allows the server to tell the client "yeah, we heard your order, we'll get to it soon." Think the <a href="http://www.twitter.com/">Twitter API</a> on a busy day. Where 201 Created implies the resource has been created before a response returns, 202 Accepted implies the request is ok and in a queue somewhere.
</p><p>
<strong>304 Not Modified</strong> in conjunction with caching and conditional GET requests (requests with If-Modified-Since / If-None-Match headers) allows web applications to say "the content hasn't changed, continue using the cached version" without having to re-render and send the cached content down the pipe.
</p><p>
<strong>401 Unauthorized</strong> should be used when attempting to access a resource which requires authentication credentials the request does not carry. This is used in conjunction with www-authentication.
</p><p>
<strong>500 Internal Server Error</strong> is better than OK when your PHP script dies or reaches an exception.
</p><p>
In the <a href="http://www.recessframework.com">Recess! Framework</a> I use this <a href="http://www.krisjordan.com/php-class-for-http-response-status-codes/">StatusCodes class</a> to provide named constants for all HTTP/1.1 status codes. Example usage:</p>
<pre class="php" name="code">header(StatusCodes::httpHeaderFor(StatusCodes::HTTP_NOT_FOUND));</pre>
<h2>Tip #4: Don't Use $_SESSION</h2>
A truly RESTful PHP application should be entirely stateless- <strong>all requests should contain enough information to be handled without additional server side state</strong>. In practice this means storing authentication information in a cookie with a timestamp and a checksum. Additional data can also be stored in a cookie. In the event you need more than a cookie's worth of data fall back to storing it in a central database with the authentication still in the cookie. <a href="http://www.krisjordan.com/2008/09/16/cal-henderson-scalable-web-architectures-common-patterns-and-approaches/">This is how Flickr approaches statelessness.</a>
<h2>Tip #5: Test with cURL or rest-client</h2>
<a href="http://www.krisjordan.com/wp-content/uploads/2008/12/rest-client.png"><img class="alignright size-thumbnail wp-image-494" title="rest-client" src="http://files.kris.gethifi.com/rest-client-150x150.png" alt="" width="150" height="150" /></a><a href="http://curl.haxx.se/">cURL</a> makes it easy to execute any HTTP METHOD on a resource URL. You can pass request parameters and headers as well as inspect response headers and data. The command line tool 'curl' is standard on many *nix distros. Windows users should check out <a href="http://www.mingw.org/">MinGW/MSYS</a> which supports cURL. Even <a href="http://us2.php.net/curl">PHP has cURL functions</a> which are enabled on most hosts (<a href="http://us2.php.net/manual/en/curl.setup.php">php/curl install page</a>).

<strong>cURL Example Usage &amp; Common Parameters:</strong>
<pre># curl -X PUT http://www.foo.com/bar/1 -d "some=var" -d "other=var2" -H "Accept: text/json" -I</pre>
<strong>-X [METHOD]</strong> Specify the HTTP method.
<strong>-d "name=value"</strong> Set a POST/PUT field name and value.
<strong>-H [HEADER]</strong> Set a header.
<strong>-I</strong> Only display response's headers.
<p>
Alternatively, a free GUI to test REST interfaces is <a href="http://code.google.com/p/rest-client/">Java/Swing based <strong>rest-client</strong></a>. rest-client is scriptable and has support for JSON/XML.</p>
<h2>Tip #6 - Use a RESTful PHP Framework</h2>
<p>Frankly, developers shouldn't have to worry about many of these low-level details of REST when writing PHP apps. REST is based on conventions and conventions, by nature, involve a lot of boilerplate. This is right up a framework's alley (as Rails has shown). What options exist for PHP? CodeIgniter's routing completely ignores the HTTP METHOD so there is <a href="http://blog.medryx.org/2008/10/03/codeigniter-rest/">serious hacking</a> that needs to be done. Cake <a href="http://book.cakephp.org/view/478/Custom-REST-Routing">has</a> REST support but wasn't designed to make specifying useful response status codes a part of the framework. <a href="http://konstrukt.dk/">Konstruct</a> appears to have a very well thought out architecture for a controllers framework built around HTTP and REST. Unfortunately it is not easily approached and lacking (intentionally) many components, like an ORM layer, developers have come to expect in a modern web framework.
</p><p>
(Disclaimer: <em>Shameless Plug!</em>) <strong>The lack of a solid, RESTful PHP framework was one of my primary motivations for creating the <a href="http://www.recessframework.com/">Recess! Framework</a></strong>. Recess is a full-stack, open source (MIT), <a href="http://www.recessframework.com/">RESTful PHP framework</a>. If you're interested in writing RESTful PHP applications check it out and sign-up to be notified of its upcoming release.</p>
				]]>
			</description>
			<pubDate>Tue, 02 Dec 2008 01:33:57 -0500</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/2008/12/02/towards-restful-php-5-basic-tips</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>PHP Class for HTTP Response Status Codes</title>
			<link>http://krisjordan.com/php-class-for-http-response-status-codes</link>
			<description>
				<![CDATA[
					<p>The <a href="http://www.recessframework.com/">Recess! Framework</a> uses the following class which provides constants and simple helper methods for HTTP Response Status Codes.
</p>
<pre name="code" class="php">
<p>&lt;?php</p>
<p>/**</p>
<p> * StatusCodes provides named constants for</p>
<p> * HTTP protocol status codes. Written for the</p>
<p> * Recess Framework (http://www.recessframework.com/)</p>
<p> * </p>
<p> * @author Kris Jordan</p>
<p> * @license MIT </p>
<p> * @package recess.http</p>
<p> */</p>
<p>class StatusCodes {</p>
<p>	// [Informational 1xx]</p>
<p>	const HTTP_CONTINUE = 100;</p>
<p>	const HTTP_SWITCHING_PROTOCOLS = 101;</p>
<p>	// [Successful 2xx]</p>
<p>	const HTTP_OK = 200;</p>
<p>	const HTTP_CREATED = 201;</p>
<p>	const HTTP_ACCEPTED = 202;</p>
<p>	const HTTP_NONAUTHORITATIVE_INFORMATION = 203;</p>
<p>	const HTTP_NO_CONTENT = 204;</p>
<p>	const HTTP_RESET_CONTENT = 205;</p>
<p>	const HTTP_PARTIAL_CONTENT = 206;</p>
<p>	// [Redirection 3xx]</p>
<p>	const HTTP_MULTIPLE_CHOICES = 300;</p>
<p>	const HTTP_MOVED_PERMANENTLY = 301;</p>
<p>	const HTTP_FOUND = 302;</p>
<p>	const HTTP_SEE_OTHER = 303;</p>
<p>	const HTTP_NOT_MODIFIED = 304;</p>
<p>	const HTTP_USE_PROXY = 305;</p>
<p>	const HTTP_UNUSED= 306;</p>
<p>	const HTTP_TEMPORARY_REDIRECT = 307;</p>
<p>	// [Client Error 4xx]</p>
<p>	const errorCodesBeginAt = 400;</p>
<p>	const HTTP_BAD_REQUEST = 400;</p>
<p>	const HTTP_UNAUTHORIZED  = 401;</p>
<p>	const HTTP_PAYMENT_REQUIRED = 402;</p>
<p>	const HTTP_FORBIDDEN = 403;</p>
<p>	const HTTP_NOT_FOUND = 404;</p>
<p>	const HTTP_METHOD_NOT_ALLOWED = 405;</p>
<p>	const HTTP_NOT_ACCEPTABLE = 406;</p>
<p>	const HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;</p>
<p>	const HTTP_REQUEST_TIMEOUT = 408;</p>
<p>	const HTTP_CONFLICT = 409;</p>
<p>	const HTTP_GONE = 410;</p>
<p>	const HTTP_LENGTH_REQUIRED = 411;</p>
<p>	const HTTP_PRECONDITION_FAILED = 412;</p>
<p>	const HTTP_REQUEST_ENTITY_TOO_LARGE = 413;</p>
<p>	const HTTP_REQUEST_URI_TOO_LONG = 414;</p>
<p>	const HTTP_UNSUPPORTED_MEDIA_TYPE = 415;</p>
<p>	const HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;</p>
<p>	const HTTP_EXPECTATION_FAILED = 417;</p>
<p>	// [Server Error 5xx]</p>
<p>	const HTTP_INTERNAL_SERVER_ERROR = 500;</p>
<p>	const HTTP_NOT_IMPLEMENTED = 501;</p>
<p>	const HTTP_BAD_GATEWAY = 502;</p>
<p>	const HTTP_SERVICE_UNAVAILABLE = 503;</p>
<p>	const HTTP_GATEWAY_TIMEOUT = 504;</p>
<p>	const HTTP_VERSION_NOT_SUPPORTED = 505;</p>
		
<p>	private static $messages = array(</p>
<p>		// [Informational 1xx]</p>
<p>		100=&gt;'100 Continue',</p>
<p>		101=&gt;'101 Switching Protocols',</p>
<p>		// [Successful 2xx]</p>
<p>		200=&gt;'200 OK',</p>
<p>		201=&gt;'201 Created',</p>
<p>		202=&gt;'202 Accepted',</p>
<p>		203=&gt;'203 Non-Authoritative Information',</p>
<p>		204=&gt;'204 No Content',</p>
<p>		205=&gt;'205 Reset Content',</p>
<p>		206=&gt;'206 Partial Content',</p>
<p>		// [Redirection 3xx]</p>
<p>		300=&gt;'300 Multiple Choices',</p>
<p>		301=&gt;'301 Moved Permanently',</p>
<p>		302=&gt;'302 Found',</p>
<p>		303=&gt;'303 See Other',</p>
<p>		304=&gt;'304 Not Modified',</p>
<p>		305=&gt;'305 Use Proxy',</p>
<p>		306=&gt;'306 (Unused)',</p>
<p>		307=&gt;'307 Temporary Redirect',</p>
<p>		// [Client Error 4xx]</p>
<p>		400=&gt;'400 Bad Request',</p>
<p>		401=&gt;'401 Unauthorized',</p>
<p>		402=&gt;'402 Payment Required',</p>
<p>		403=&gt;'403 Forbidden',</p>
<p>		404=&gt;'404 Not Found',</p>
<p>		405=&gt;'405 Method Not Allowed',</p>
<p>		406=&gt;'406 Not Acceptable',</p>
<p>		407=&gt;'407 Proxy Authentication Required',</p>
<p>		408=&gt;'408 Request Timeout',</p>
<p>		409=&gt;'409 Conflict',</p>
<p>		410=&gt;'410 Gone',</p>
<p>		411=&gt;'411 Length Required',</p>
<p>		412=&gt;'412 Precondition Failed',</p>
<p>		413=&gt;'413 Request Entity Too Large',</p>
<p>		414=&gt;'414 Request-URI Too Long',</p>
<p>		415=&gt;'415 Unsupported Media Type',</p>
<p>		416=&gt;'416 Requested Range Not Satisfiable',</p>
<p>		417=&gt;'417 Expectation Failed',</p>
<p>		// [Server Error 5xx]</p>
<p>		500=&gt;'500 Internal Server Error',</p>
<p>		501=&gt;'501 Not Implemented',</p>
<p>		502=&gt;'502 Bad Gateway',</p>
<p>		503=&gt;'503 Service Unavailable',</p>
<p>		504=&gt;'504 Gateway Timeout',</p>
<p>		505=&gt;'505 HTTP Version Not Supported'</p>
<p>	);</p>
	
<p>	public static function httpHeaderFor($code) {</p>
<p>		return 'HTTP/1.1 ' . self::$messages[$code];</p>
<p>	}
</p><p>
	public static function getMessageForCode($code) {</p>
<p>		return self::$messages[$code];</p>
	}
	
<p>	public static function isError($code) {</p>
<p>		return is_numeric($code) && $code &gt;= self::HTTP_BAD_REQUEST;</p>
	}
	
<p>	public static function canHaveBody($code) {</p>
<p>		return</p>
<p>			// True if not in 100s</p>
<p>			($code &lt; self::HTTP_CONTINUE || $code &gt;= self::HTTP_OK)</p>
<p>			&& // and not 204 NO CONTENT</p>
<p>			$code != self::HTTP_NO_CONTENT</p>
<p>			&& // and not 304 NOT MODIFIED</p>
<p>			$code != self::HTTP_NOT_MODIFIED;</p>
	}
}
<p>?&gt;</p>
</pre>
				]]>
			</description>
			<pubDate>Mon, 01 Dec 2008 19:37:35 -0500</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/php-class-for-http-response-status-codes</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>How Recess Solves Common PHP/MySQL Issues</title>
			<link>http://krisjordan.com/2008/11/28/how-recess-solves-common-phpmysql-issues</link>
			<description>
				<![CDATA[
					<a href="http://www.justincarmony.com">Justin Carmony</a> wrote a great article titled '<a href="http://www.justincarmony.com/blog/2008/10/25/php-design-biggest-database-oversights/">PHP Design - Biggest Database Oversights</a>'. The article points out 5 naive PHP/MySQL design decisions that will come back to haunt projects if they've been made. As I'm getting closer to the public preview release of the <a href="http://www.recessframework.com/">Recess! Framework</a> this article discusses how Recess! addresses some of the most common oversights in database development.
<p>
<strong>Re: Oversight #1 - No Data Access Layer</strong>
</p><p>
Quality software design and engineering is all about abstracting away details and finding the proper layers of functionality. As Justin points out, if there is no layer of abstraction which wraps data access code then low-level data access code will appear everywhere. PHP projects which interleave data connections and queries throughout their code are difficult to maintain. 
</p><p>
The database stack in Recess! has four major components: 1) SQL statement builder, 2) Data Sources, 3) Data Sets, 4) Object-Relational Mapped Models. The notion of a 'data access layer' is taken care of by Data Sources. Data sources wrap properly around PDO and introduce new methods beyond PDO's, for example: getTables and getColumns($table). The implementation of these methods is specific to the RDBMS so Recess! also has the notion of a vendor specific driver called a DataSourceProvider. Currently Sqlite and MySql are supported.
</p><p>
<strong>Re: Oversight #2 - Design for Only One Database Connection</strong>
</p><p>
Small, greenfield projects often start out with a single database. This leads to naive data access layers which only support connections to a single database. Recess! supports multiple, named Data Sources. Instead of using a singleton pattern it uses a registry to store the Data Sources by name.
</p><p>
Having named Data Sources in an application gets really powerful at higher layers of abstraction, such as at the ORM layer, where we can mark-up a model with a single annotation to define which Data Source the model is persisted in.
</p><p>
<strong>Re: Oversight #3 - No Developer Logging</strong>
</p><p>
This isn't as fully fleshed out yet as I'd like but the plans and hooks are in place to be able to log queries, their stack traces, as well as their EXPLAIN'ed strategies for execution in the RDBMS.  In Recess! there is a distinct difference between Development mode and Production mode. Sql logging will be a toggle option on by default in development and off by default in production.
</p><p>
<strong>Re: Oversight #4 - Queries Written in Procedural Processes</strong>
</p><p>
My dislike of queries being written in procedural code may run even deeper than Justin's! Recess! abdicates SQL string manipulation to a low-level SqlBuilder class. An instance of SqlBuilder allows SQL query strings to be built incrementally using chained method calls. Let's take a look at some examples:
</p>
<pre name="code" class="php">
<p>$sqlBuilder = new SqlBuilder();</p>
<p>$sql = $sqlBuilder</p>
<p>            -&gt;from('people')</p>
<p>            -&gt;like('name','Kris')</p>
<p>            -&gt;orderBy('age')</p>
<p>            ->toSql();</p>
<p>// $sql is now: </p>
<p>// 'SELECT people.* </p>
<p>//    WHERE people.name = :people_name </p>
<p>//    ORDER BY people.age</p>
<p>$args = $sqlBuilder-&gt;getPdoArguments();</p>
<p>// $args is now array( 'people_name' =&gt; 'Kris' );
</p><p>
// Let's add another criterion</p>
<p>$sql = $sqlBuilder->equal('home_city', 'Charlotte')->toSql();</p>
<p>// $sql is now: </p>
<p>//  SELECT people.* </p>
<p>//      WHERE people.name LIKE :people_name </p>
<p>//      AND people.home_city = :people_home_city </p>
<p>//      ORDER BY people.age
</p><p>
$args = $sqlBuilder-&gt;getPdoArguments();</p>
<p>// $args is now array( </p>
<p>//                   'people_name' =&gt; 'Kris', </p>
<p>//                   'people_home_city' =&gt; 'Charlotte' );</p>
</pre>
<p>
SqlBuilder can do more complex things like joins, as well as inserts, updates, and deletes. Recess! users, though, will likely never use SqlBuilder because it's still too low level of an abstraction. Internally, however, having the ability to incrementally construct query strings has made the framework code quite pretty.
</p><p>
Here's code at the level of abstraction Recess! developers can expect to write:
</p>
<pre name="code" class="php">
<p>class Person extends Model { }</p>
<p>$person = new Person();</p>
<p>$person-&gt;name = 'Kris';</p>
<p>$person-&gt;homeCity = 'Charlotte';</p>
<p>$people = $person-&gt;find()-&gt;orderBy('name');</p>
<p>foreach($people as $person) {</p>
<p>   echo $person-&gt;name, ' ', $person-&gt;age, '&lt;br /&gt;';</p>
}
</pre>
<p>
This example just scrapes the surface of Recess! object-relational mapping. Relationships, CRUDS, cascading deletes, etc. are all handled as well. In a future post I'll step through the data access stack's capabilities in more detail. Needless to say, in Recess! queries won't be mixed with procedural code!
</p><p>
<strong>Re: Oversight #5 - No Separation of Reads and Writes</strong>
</p><p>
Once projects outgrow a single server RDBMS the next step is often to do a Master/Slave setup in MySQL. In a Master/Slave setup expensive and less frequent writes are channeled to the Master server while reads are channeled to the Slave server.
</p><p>
In Recess!, by using named data sources as described in #2, we can handle Data Sources on a per model basis. A natural extension of this is handling reads and writes independently on a per model basis. The pseudo-code below shows how this may look on a model:
</p>
<pre name="code" class="php">
<p>/** </p>
<p> * !Source master, For: Writes</p>
<p> * !Source (slave1, slave2, slave3), For: Reads</p>
<p> * !HasMany books</p>
<p> */</p>
<p>class Person extends Model {}
</p><p>
/**</p>
<p> * !Source master</p>
<p> * !BelongsTo person</p>
<p> */</p>
<p>class Books extends Model {}</p>
</pre>
<p>
In a future post I'll describe the Recess! annotations system which will explain the constructs you're seeing in the DocComments. Recess! annotations give us a way of providing static metadata about a class and are built-in to the framework's core. Recess! annotations should be familiar to Java and .Net programmers who have used annotations.
</p><p>
<strong>Conclusion</strong>
</p><p>
So that's a quick look at how Recess! handles Justin Carmony's commonly made MySQL/PHP mistakes. These issues are abstracted away in the internals of Recess. If you're a PHP developer check out <a href="http://www.recessframework.com/">RecessFramework.com</a> and sign-up to be notified when it is publicly released "very soon now".</p>
				]]>
			</description>
			<pubDate>Fri, 28 Nov 2008 16:25:25 -0500</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/2008/11/28/how-recess-solves-common-phpmysql-issues</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>Dynamic Properties in PHP and StdClass</title>
			<link>http://krisjordan.com/dynamic-properties-in-php-with-stdclass</link>
			<description>
				<![CDATA[
					<p>Languages like JavaScript and Python allow object instances to have dynamic properties. As it turns out, PHP does too. Looking at the official PHP documentation on objects and classes you might be lead to believe dynamic instance properties require custom __get and __set magic methods. They don't.</p>
<h2>Simple, Built-in Dynamic Properties</h2>
<p>Check out the following code listing:</p>
<pre name="code" class="php">class DynamicProperties { }
$object = new DynamicProperties;
print isset($object-&gt;foo) ? 't' : 'f'; // f

// Set Dynamic Properties foo and fooz
$object-&gt;foo = 'bar';
$object-&gt;fooz = 'baz';

// Isset and Unset work
isset($object-&gt;foo); // true
unset($object-&gt;foo);

// Iterate through Properties and Values
foreach($object as $property =&gt; $value)&nbsp; { 
     print($property . ' = ' . $value . '&lt;br /&gt;'); 
}

// Prints:
//   fooz = baz</pre>
<p>Using the built-in dynamic instance properties is an order of magnitude faster (30x, by my profiling) than using magic __get and __set methods. Built in dynamic property accesses happen without invoking a method call back to PHP script.</p>
<p>So when does it make sense to use __get and __set? If you need more complex behavior, like calculated properties, you must use __get and __set. Also, as an astute comment points out, if you would prefer <em>not</em> to have dynamic properties on a class you can throw errors from __get and __set.</p>
<h2>StdClass: Anonymous Objects</h2>
<p>Sometimes all that is necessary is a property bag to throw key value pairs into. One way is to use array, but this requires quoting all keys. Another way is to use dynamic properties on an instance of StdClass. StdClass is a sparsely documented class in PHP which has no predefined members.</p>
<pre name="code" class="php">$object = new StdClass;
$object-&gt;foo = 'bar';
json_encode($object);</pre>
<p>Next I'll touch on the SPL's Countable and ArrayAccess as a means of being able to accomplish the following in PHP:</p>
<pre name="code" class="php">class MyClass implements Countable, ArrayAccess { ... }
$myObject = new MyClass();
// Using array access notation
$myObject[0] = 'hello';
$myObject[1] = 'world';
$myObject['foo'] = 'bar';
</pre>
<p><em>Thanks to the folks pointing out that you don't need to extend from StdClass in order to have dynamic properties!</em></p>
				]]>
			</description>
			<pubDate>Thu, 27 Nov 2008 00:49:15 -0500</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/dynamic-properties-in-php-with-stdclass</guid>
			<category>HiFi</category>
			<author></author>
		</item>
				<item>
			<title>How does the quality of political candidates’ websites correlate with campaign success?</title>
			<link>http://krisjordan.com/2008/10/29/how-does-the-quality-of-political-candidates%e2%80%99-websites-correlate-with-campaign-success</link>
			<description>
				<![CDATA[
					<a href="http://www.votethesite.com/">VoteTheSite.com</a>, a micro-site my good friends at <a href="http://www.newmediacampaigns.com">New Media Campaigns</a> have built, is conducting an on-line experiment to explore just that question. <a href="http://www.votethesite.com/">VoteTheSite.com</a> pits congressional candidates’ websites against each other race-by-race. Races can be viewed <a href="http://www.votethesite.com/races/chance">randomly</a> or by <a href="http://www.votethesite.com/races">state</a>. I was surprised by the range of quality congressional websites have. From top notch sites in <a href="http://www.votethesite.com/races/show/168">Texas' 5th</a> to the really poor websites in <a href="http://www.votethesite.com/races/show/378">Georgia's 1st</a> they run the quality gamut.
<p>
<a href="http://www.votethesite.com/"><img class="size-full wp-image-446" title="VoteTheSite.com" src="http://files.kris.gethifi.com/votethesite.jpg" alt="VoteTheSite.com - Vote on Political Websites" width="300" height="213" /></a>
</p><p>
After the elections have taken place the votes on websites will be tallied up and compared to election results. Should be really interesting to see what the outcome is and how strong website quality correlates with campaign success.
</p><p>
Within the first 24 hours over 5,000 votes have been cast. Congrats to the <a href="http://www.newmediacampaigns.com">New Media</a> team for getting this out the door so quickly (with a little help from the Mechanical Turk)! <a href="http://www.votethesite.com/races">Go vote on the websites in your state</a>…
</p><p>
VoteTheSite.com was written (in under 2 days!) on an early version of the PHP Framework, the <a href="http://www.recessframework.com/">Recess! Framework</a>, I’ve had my head down plugging away on the past couple of weeks. Expect blog activity to pick up as the <a href="http://www.recessframework.com/">Recess! Framework</a> moves closer to a public release. Sign up to be notified of the release at <a href="http://www.recessframework.com/">RecessFramework.com</a>.</p>
				]]>
			</description>
			<pubDate>Wed, 29 Oct 2008 17:11:41 -0400</pubDate>
			<guid isPermaLink="true">http://krisjordan.com/2008/10/29/how-does-the-quality-of-political-candidates%e2%80%99-websites-correlate-with-campaign-success</guid>
			<category>HiFi</category>
			<author></author>
		</item>
			</channel>
</rss>
