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

  <title></title>
  <link href="http://junctionbox.ca/atom.xml" rel="self"/>
  <link href="http://junctionbox.ca/"/>
  <updated>2011-05-29T21:14:35-07:00</updated>
  <id>http://junctionbox.ca/</id>
  <author>
    <name>Nathan Fisher</name>
    
      <email>nfisher+jbx@junctionbox.ca</email>
    
  </author>

  
	
  <entry>
    <title>Branching by Abstraction 101</title>
    <link href="http://junctionbox.ca/2011/05/28/branching-by-abstraction-101/"/>
    <updated>2011-05-28T00:00:00-07:00</updated>
    <id>http://junctionbox.ca/2011/05/28/branching-by-abstraction-101</id>
    <content type="html">&lt;p&gt;Committing to mainline is an important feature of CI and always keeping your mainline deployable is a requisite for Continuous Delivery and a cornerstone of DevOps.  So what&amp;#8217;s an easy way to maintain code quality and get new features in? Feature Flags and Branching by Abstraction!&lt;/p&gt;
&lt;p&gt;So what exactly does this look like?&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s start with a simple function that outputs your name:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
	&lt;span class=&quot;vi&quot;&gt;@first_name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Now we want to change the function but it&amp;#8217;s going to be significant in someway, how would we achieve that while minimising the risk on the current functionality? The simplest way would be to introduce a binary variable that allows for flow control. I&amp;#8217;m not a big fan of this option as it can lead down a difficult path for wiring in configuration files to it.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name_flag_name2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@enable_name2&lt;/span&gt;
	&lt;span class=&quot;vi&quot;&gt;@name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;name_flag_name2&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;# TBD&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;That&amp;#8217;s a simple on/off approach for rolling out a new feature what if you want to do canary releases?  Well you&amp;#8217;ll need something that handles a little more logic:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name_flag_name2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@features&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enabled?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:enable_name2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@user_account_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;vi&quot;&gt;@name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;I leave the implementation details for the feature manager up to the user. Here are a few thoughts to consider during it&amp;#8217;s implementation; How many application servers do you have? Do you want to control your features during release or live? How do you want to manage the configuration of those features? Are you interested in canary releases? How should the features be stored and how will queries to the storage medium affect performance?&lt;/p&gt;</content>
  </entry>
	
  
	
  <entry>
    <title>Bootstrapping Windows</title>
    <link href="http://junctionbox.ca/2011/02/10/bootstrapping-windows/"/>
    <updated>2011-02-10T00:00:00-08:00</updated>
    <id>http://junctionbox.ca/2011/02/10/bootstrapping-windows</id>
    <content type="html">&lt;p&gt;Finding myself back in the Windows domain I really miss package repository tools like &lt;span class=&quot;caps&quot;&gt;YUM&lt;/span&gt; and apt-get.  In what seems eons ago I used a toolset called Unattended for windows installations.  It&amp;#8217;s a little rough around the edges but it gave me some interesting ideas.  I put together a quick script to download some common tools I find myself using on windows servers.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s the general code cobbled together;&lt;/p&gt;
&lt;pre&gt;
Const BINARY = 1
Const SAVE_CREATE_OVERWRITE = 2
Const SAVE_CREATE_NOT_EXIST = 1
Const ERR_DOWNLOAD_FILE_UNAVAILABLE = -1
Const ERR_DOWNLOAD_FILE_UNSAVABLE = -2
temp = WScript.CreateObject(&quot;Scripting.FileSystemObject&quot;).GetSpecialFolder(2).Path &amp;amp; &quot;\&quot;

Dim http, WshShell, file_stream

Set WshShell = WScript.CreateObject(&quot;WScript.Shell&quot;)



download_file &quot;http://javadl.sun.com/webapps/download/AutoDL?BundleId=44457&quot;, &quot;jre.exe&quot;
WshShell.Run temp &amp;amp; &quot;jre.exe /s /v &quot;&quot;/qn ADDLOCAL=ALL IEXPLORER=1&quot;&quot;&quot;, 1, TRUE
' JRE


' Download a file to the temp folder and specified filename.
'
'
Function download_file(src, dest)
	' TODO: Add better error handling for http and file handles.

	Set http = CreateObject(&quot;MSXML2.ServerXMLHTTP&quot;)

	If IsNull(http) Then
		WScript.Echo &quot;Microsoft.XmlHttp creation failed&quot;
	End If

	http.open &quot;GET&quot;, src, FALSE
	http.send

	Set file_stream = CreateObject(&quot;Adodb.Stream&quot;)

	file_stream.type = BINARY
	file_stream.open
	file_stream.write http.responseBody
	file_stream.saveToFile temp &amp;amp; dest, SAVE_CREATE_OVERWRITE 
	file_stream.close

	Set file_stream = nothing
	Set http = nothing
End Function
&lt;/pre&gt;</content>
  </entry>
	
  
	
  <entry>
    <title>Initial Configuration of Puppetd on OS X</title>
    <link href="http://junctionbox.ca/2010/10/05/initial-configuration-of-puppetd-on-os-x/"/>
    <updated>2010-10-05T00:00:00-07:00</updated>
    <id>http://junctionbox.ca/2010/10/05/initial-configuration-of-puppetd-on-os-x</id>
    <content type="html">&lt;p&gt;Configuring puppetd on OS X&lt;/p&gt;
&lt;p&gt;Create the User and Group accounts;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;sudo dscl . -create /Groups/puppet
sudo dscl . -create /Groups/puppet PrimaryGroupID 300

sudo dscl . -create /Users/puppet
sudo dscl . -create /Users/puppet PrimaryGroupID 300
sudo dscl . -create /Users/puppet UniqueID 300
sudo dscl . -create /Users/puppet UserShell /usr/bin/false
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Create the folders&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;sudo mkdir /etc/puppet
sudo mkdir -p /var/puppet/log
sudo chown -R puppet:puppet /var/puppet
sudo chown -R puppet:puppet /etc/puppet
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Create the config file.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;sudo puppetd --genconfig &amp;gt; /etc/puppet/puppet.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Modify your /etc/hosts file with an entry for puppet (setting the server in the puppet.conf offers more flexibility should you move servers or change IP&amp;#8217;s).&lt;/p&gt;
&lt;p&gt;If you run into issues with your certificates;&lt;/p&gt;
&lt;h4&gt;Client&lt;/h4&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;rm -rf /etc/puppet/ssl
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4&gt;Server&lt;/h4&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;puppetca --clean CERT_ID
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</content>
  </entry>
	
  
	
  <entry>
    <title>Dance and Pivot SQL Style</title>
    <link href="http://junctionbox.ca/2010/08/01/dance-and-pivot-sql-style/"/>
    <updated>2010-08-01T00:00:00-07:00</updated>
    <id>http://junctionbox.ca/2010/08/01/dance-and-pivot-sql-style</id>
    <content type="html">&lt;p&gt;Found myself looking at Open Flash Charts for a reporting system.  I wanted to create page views broken down by day.  A simplified schema is as follows:&lt;/p&gt;
&lt;h3&gt;Schema&lt;/h3&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;td&gt; id &lt;/td&gt;
		&lt;td&gt; created_at &lt;/td&gt;
		&lt;td&gt; page &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; Integer &lt;/td&gt;
		&lt;td&gt; DateTime &lt;/td&gt;
		&lt;td&gt; Varchar(255) &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;I wanted to create a table like the following:&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;td&gt; page &lt;/td&gt;
		&lt;td&gt; monday &lt;/td&gt;
		&lt;td&gt; tuesday &lt;/td&gt;
		&lt;td&gt; wednesday &lt;/td&gt;
		&lt;td&gt; thursday &lt;/td&gt;
		&lt;td&gt; friday &lt;/td&gt;
		&lt;td&gt; saturday &lt;/td&gt;
		&lt;td&gt; sunday &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; index &lt;/td&gt;
		&lt;td&gt; 3 &lt;/td&gt;
		&lt;td&gt; 5 &lt;/td&gt;
		&lt;td&gt; 2 &lt;/td&gt;
		&lt;td&gt; 8 &lt;/td&gt;
		&lt;td&gt; 9 &lt;/td&gt;
		&lt;td&gt; 30 &lt;/td&gt;
		&lt;td&gt; 32 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; contact &lt;/td&gt;
		&lt;td&gt; 2 &lt;/td&gt;
		&lt;td&gt; 1 &lt;/td&gt;
		&lt;td&gt; 4 &lt;/td&gt;
		&lt;td&gt; 3 &lt;/td&gt;
		&lt;td&gt; 7 &lt;/td&gt;
		&lt;td&gt; 12 &lt;/td&gt;
		&lt;td&gt; 16 &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;My first though was just do a simple &lt;span class=&quot;caps&quot;&gt;GROUP&lt;/span&gt; BY and pivot the table through code.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;mysql&quot;&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;created_at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;COUNT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hits&lt;/span&gt; 
&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;page_views&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;GROUP&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;created_at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;I figured I could alternatively use temp tables but, I had an itch to find out if there was another way using pure &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; and no temp tables.  During my search I ran across all sorts of queries some obscure head scratchers.  After much frustration I started reading the MySQL for any reprieve particularly the section on &lt;a href=&quot;http://dev.mysql.com/doc/refman/5.1/en/functions.html&quot;&gt;functions and operators&lt;/a&gt;.  After a small meal and some strange query results I ran into a presentation created by &lt;a href=&quot;http://datacharmer.org/&quot;&gt;Giuseppe Maxia&lt;/a&gt; aka the &amp;#8220;Data Charmer&amp;#8221;.  I reamed through his presentation and found what I was looking for in the form of a 2 query crosstab.  I reformulated his query to suit my needs and came up with the following:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;mysql&quot;&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;page_name&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;COUNT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CASE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;created_at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;?&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ELSE&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;COUNT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CASE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;created_at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;?&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ELSE&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tues&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;COUNT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CASE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;created_at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;?&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ELSE&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;COUNT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CASE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;created_at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;?&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ELSE&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thurs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;COUNT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CASE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;created_at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;?&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ELSE&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;COUNT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CASE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;created_at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;?&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ELSE&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;COUNT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CASE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;created_at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;?&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ELSE&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sun&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;COUNT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CASE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;created_at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
  &lt;span class=&quot;k&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;?&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;?&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;?&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;?&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;?&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;?&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;?&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ELSE&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;total&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;page_views&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;GROUP&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;What are your thoughts? Any similar implementations how did you handle it?&lt;/p&gt;</content>
  </entry>
	
  
	
  <entry>
    <title>Simplified TDD with Sinatra autotest</title>
    <link href="http://junctionbox.ca/2010/04/17/simplified-tdd-with-sinatra-autotest/"/>
    <updated>2010-04-17T00:00:00-07:00</updated>
    <id>http://junctionbox.ca/2010/04/17/simplified-tdd-with-sinatra-autotest</id>
    <content type="html">&lt;p&gt;General overview of what we&amp;#8217;re building;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Simple autotest compatible directory structure.&lt;/li&gt;
	&lt;li&gt;Sinatra application.&lt;/li&gt;
	&lt;li&gt;Sinatra unit test.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;File setup:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;project&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;MyApp
mkdir -p &lt;span class=&quot;nv&quot;&gt;$project&lt;/span&gt;/&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;lib,test&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$project&lt;/span&gt;
cat &lt;span class=&quot;s&quot;&gt;&amp;lt;&amp;lt;EOT &amp;gt; test/test_app.rb&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;$:.unshift File.join(File.dirname(__FILE__),&amp;#39;..&amp;#39;,&amp;#39;lib&amp;#39;)&lt;/span&gt;

&lt;span class=&quot;s&quot;&gt;require &amp;#39;app&amp;#39;&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;require &amp;#39;test/unit&amp;#39;&lt;/span&gt;

&lt;span class=&quot;s&quot;&gt;class AppTest &amp;lt; Test::Unit::TestCase&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;  def test_fail&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    flunk &amp;#39;Write your App tests!&amp;#39;&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;  end&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;EOT&lt;/span&gt;

autotest
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This should output something akin to the following, if you don&amp;#8217;t get that then somethings amiss that you&amp;#8217;ll need to investigate further.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;sr&quot;&gt;/Library/&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Ruby&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Site&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rubygems&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;custom_require&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`gem_original_require&amp;#39;: no such file to load -- app (LoadError)&lt;/span&gt;
&lt;span class=&quot;sb&quot;&gt;	from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;	from ./test/test_app.rb:4&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;	from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `gem_original_require&amp;#39;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; /Library/&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Ruby&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Site&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rubygems&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;custom_require&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`require&amp;#39;&lt;/span&gt;
&lt;span class=&quot;sb&quot;&gt;	from -e:2&lt;/span&gt;
&lt;span class=&quot;sb&quot;&gt;	from -e:2:in `&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;#39;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Next create a new file named &amp;#8216;lib/app.rb&amp;#8217;.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;touch lib/app.rb
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Once saved your test should kick to life with one failure:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Failure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;test_fail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;AppTest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Write&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;your&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tests!&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Hugely simplified test suite, but it gets you going and doesn&amp;#8217;t contain reams of mystical cruft to debug.&lt;/p&gt;
&lt;p&gt;Next up is introducing rack&amp;#8217;s test suite, modify your test_app.rb to look like the following;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;vg&quot;&gt;$:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unshift&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;__FILE__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;..&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;lib&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;app&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;test/unit&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;rack/test&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:test&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AppTest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Unit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TestCase&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Methods&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;app&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;App&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test_fail&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;flunk&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Write your App tests!&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Back to a test that doesn&amp;#8217;t run? Good!&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s get it back to a running test with the following change to &amp;#8216;lib/app.rb&amp;#8217;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;sx&quot;&gt;%w{rubygems sinatra}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Now you should have a failing test.  Lets start on something meaningful remove the test_fail method and add the following:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test_root_is_accessible&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ok?&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Your autotest should switch to the error output below:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;test_root_is_accessible&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;AppTest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;NameError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;uninitialized&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;constant&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;AppTest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;App&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`app&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;That&amp;#8217;s an indicator we&amp;#8217;re missing our application class.  Dealing with one problem at a time lets implement the skeleton class in &amp;#8216;lib/app.rb&amp;#8217; as outlined below.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Sinatra&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;You should get a failing test case with the output below, which indicates the route is not found.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Failure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;test_root_is_accessible&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;AppTest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Next up lets add the route in &amp;#8216;lib/app.rb&amp;#8217;.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And there we go our first of hopefully many tests is now passing, congratulations!&lt;/p&gt;
&lt;p&gt;For the source see;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;git://github.com/nfisher/Sinatra-Skeleton.git&quot;&gt;git://github.com/nfisher/Sinatra-Skeleton.git&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
	
  
	
  <entry>
    <title>Dom A Regato, My Tests Are Auto</title>
    <link href="http://junctionbox.ca/2010/03/24/dom-a-regato--my-tests-are-auto/"/>
    <updated>2010-03-24T00:00:00-07:00</updated>
    <id>http://junctionbox.ca/2010/03/24/dom-a-regato--my-tests-are-auto</id>
    <content type="html">&lt;p&gt;So in my ever increasing commitment to &lt;span class=&quot;caps&quot;&gt;TDD&lt;/span&gt;, I&amp;#8217;ve started seeking an efficient way to run tests.  Call me what you will but, I find running tests breaks my tempo.  So how do I keep aware of my testing state, but stay with my head in the code.  Some out there might call for NetBeans, I&amp;#8217;ve used it and loved it, but I&amp;#8217;m drawn to vim like a moth to the proverbial flame.&lt;/p&gt;
&lt;p&gt;Mix 1 vertical pinch of &lt;strong&gt;NERDTree&lt;/strong&gt;, 1 horizontal slice of &lt;strong&gt;bufexplorer&lt;/strong&gt;, a gram of &lt;strong&gt;FuzzyFinder&lt;/strong&gt;, &lt;strong&gt;rails.vim&lt;/strong&gt;, and some custom bindings and what do you get?  A pimped out ride in vim for rails development.  Sure it may look like a Honda with those over-sized spoilers, but its just the way I like it!  Long story short, NetBeans is a great package, but I just can&amp;#8217;t stay away from vim long.  Alas I digress, the goal is to maximize my productivity while staying committed to the Tao of &lt;span class=&quot;caps&quot;&gt;TDD&lt;/span&gt;.\nSo under the hood I&amp;#8217;ve got MacVim runnin&amp;#8217;, lean, mean and full-screen but, how do I maximize my productivity?  The first thing that came to mind was &lt;span class=&quot;caps&quot;&gt;FAM&lt;/span&gt;, at first I was considering rolling my own tool&amp;#8230; mmm maybe we&amp;#8217;ll just consult with the interwebz a little before we take it that far.  Came across autotest, interesting, but it uses polling&amp;#8230;.or does it?  Enter autotest-fsevent, just what the doctor ordered for keepin&amp;#8217; those idle cycles, idle.  Add a sprinkle of autotest-growl (highly recommend &amp;#8220;Music Video&amp;#8221; as your default growl style) and autotest-rails-pure and you&amp;#8217;ve got a nice setup for &lt;span class=&quot;caps&quot;&gt;TDD&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;So a quick rundown of my setup.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;MacVim
	&lt;ul&gt;
		&lt;li&gt;Rails.vim&lt;/li&gt;
		&lt;li&gt;NERDTree.vim&lt;/li&gt;
		&lt;li&gt;bufexplor.vim&lt;/li&gt;
		&lt;li&gt;FuzzyFinder.vim&lt;/li&gt;
		&lt;li&gt;keyboard mapping love&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;gems
	&lt;ul&gt;
		&lt;li&gt;autotest&lt;/li&gt;
		&lt;li&gt;autotest-fsevent&lt;/li&gt;
		&lt;li&gt;autotest-growl&lt;/li&gt;
		&lt;li&gt;autotest-rails-pure&lt;/li&gt;
		&lt;li&gt;test-unit&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
  </entry>
	
  
	
  <entry>
    <title>Fresh Book It</title>
    <link href="http://junctionbox.ca/2010/02/23/fresh-book-it/"/>
    <updated>2010-02-23T00:00:00-08:00</updated>
    <id>http://junctionbox.ca/2010/02/23/fresh-book-it</id>
    <content type="html">&lt;p&gt;A few years ago I signed up for a &lt;a href=&quot;http://www.freshbooks.com/&quot;&gt;Freshbooks&lt;/a&gt; account while I was running my own business.  A year and a half later I was employed at a small start-up that had about 12 people.  I was involved in much of the software selection and design of some of our core infrastructure.  We needed a time tracking system.  My suggestion was Freshbooks as there was the potential to integrate it with some of our other systems.&lt;/p&gt;
&lt;p&gt;We&amp;#8217;re now close to 100 people, and over 200 projects.  Freshbooks project selection just isn&amp;#8217;t cutting it anymore, but I was sure there was a solution, namely a project selector with type ahead search.&lt;/p&gt;
&lt;p&gt;One late night at work, waiting for a &lt;strong&gt;large&lt;/strong&gt; db dump to load, I decided to do a little hacking.  I cracked open the page source to see what JS framework was used.  JQuery was available and I was elated!  Firebug was up next.  I was pretty certain I could pull the data I wanted from the Project selection box.  I got the id from the inspector, fired up the console and started poking around.&lt;/p&gt;
&lt;p&gt;I came up with some code that worked in the console and turned it into a one-liner for a bookmarklet&amp;#8230; and presto&amp;#8230;fizzo.  No dice, no workie&amp;#8230; just rendered [Object object].&lt;/p&gt;
&lt;p&gt;Hmmm so I did a little research and found that var assignments act like a return which explains the [Object object].  A little googling and I found what I hoped to be the solution;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;(function(){})()&lt;/code&gt;\nOkay that dealt with the [Object object] problem, but sadly not the solution I was looking for.  The javascript errors were coming on fast and furious because of variable scope.&lt;/p&gt;
&lt;p&gt;Now I know when you look at the code you&amp;#8217;ll scream &amp;#8220;&lt;span class=&quot;caps&quot;&gt;GLOBALS&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;ARE&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;BAD&lt;/span&gt;&amp;#8221;, but its a bookmarklet and I was just having fun with javascript.&lt;/p&gt;
&lt;p&gt;Turns out my solution was to wrap the variable initialization in void().&lt;/p&gt;
&lt;p&gt;&lt;code&gt;void(project_list = null)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Hold the applause, but here&amp;#8217;s the final code (for now :).&lt;/p&gt;
&lt;pre&gt;
javascript:
void(project_list = null);
void(project_select = null);

function init( ) {
        project_list = $('#projectid option');
        project_select = $('#projectid');
        search_box = '&amp;lt;input type=&quot;text&quot; onkeyup=&quot;projectSearch(this);&quot; style=&quot;width:200px&quot; id=&quot;search_entry&quot;/&amp;gt;&amp;lt;div id=&quot;search_results&quot; style=&quot;position:absolute;width:22em;overflow:auto;max-height:12em;&quot;&amp;gt;&amp;lt;/div&amp;gt;';
        project_select.css('visibility','hidden');
        project_select.after(search_box);
}

function projectSearch($target) {
        var re = new RegExp('.*' + $target.value + '.*$','i');
        var search_results = $('#search_results');
        var links = '';
        search_results.empty();
        project_list.each( function($index, $element) {
            if( $element.text.match(re) &amp;amp;&amp;amp; parseInt($element.value) &amp;gt; 0 ) {links += projectLink( $element.value, $element.text );}
          });
        search_results.prepend(links);
}

function updateSelection( $id, $label ) {
        project_select.val($id);
        project_select.change();
        $('#search_entry').val($label);
        $('#search_results').empty();
}

function projectLink( $id, $label ) {
        return '&amp;lt;a href=&quot;#&quot; style=&quot;display:block;clear:both;background-color:#ccc;border-bottom:1px solid #999;padding:4px 2px;&quot; onclick=&quot;updateSelection(\''+ $id + '\',\'' + $label +'\');return false;&quot;&amp;gt;' + $label + '&amp;lt;/a&amp;gt;';
}

init();
&lt;/pre&gt;</content>
  </entry>
	
  
	
  <entry>
    <title>Approaching bliss; TDD+PHP+MVC</title>
    <link href="http://junctionbox.ca/2009/12/12/approaching-bliss--tdd%2Bphp%2Bmvc/"/>
    <updated>2009-12-12T00:00:00-08:00</updated>
    <id>http://junctionbox.ca/2009/12/12/approaching-bliss--tdd+php+mvc</id>
    <content type="html">&lt;p&gt;Started getting back into CodeIgnitor, but the one thing I was really missing from Rails is a test framework.  As much as it doesn&amp;#8217;t seem to have the same ongoing support and uptake as PHPUnit, I have a certain affinity to the SimpleTest framework.  I decided to see what ramblings there were regarding &lt;span class=&quot;caps&quot;&gt;TDD&lt;/span&gt; and CodeIgnitor on the interweb. In my search I ran across the article &lt;a href=&quot;http://jamierumbelow.net/2009/08/11/setting-up-the-perfect-codeigniter-tdd-environment/&quot;&gt;Setting up the perfect CodeIgniter &amp;amp; &lt;span class=&quot;caps&quot;&gt;TDD&lt;/span&gt; Environment&lt;/a&gt;.  I downloaded the code and massaged it a little to suit my needs.  I&amp;#8217;m not fully content with the implementation of BaseTestPath, but I&amp;#8217;m sure a round of &lt;span class=&quot;caps&quot;&gt;TDD&lt;/span&gt; (which I should&amp;#8217;ve started with) will probably iron it out.  Kudos to Jamie for doing the heavy lifting!\nIt hasn&amp;#8217;t been thoroughly tested, so use at your own peril. Specifically I haven&amp;#8217;t verified the views section, but upon initial inspection unit tests work.  I&amp;#8217;m thinking generate and destroy functions that build out the skelton for models, controllers, views might be my next step.&lt;/p&gt;
&lt;pre&gt;
&amp;lt;?php
/*
SimpleTest + CodeIgniter

test.php

the test runner - loads all needed files, integrates with CodeIgniter and runs the tests 

Written by Jamie Rumbelow
http://jamierumbelow.net/

Modifications by Nathan Fisher
http://junctionbox.ca/

Notes on Directory structure; where ./ is the root of a fresh CI project.

./test.php
./system/test # symlink or similar to root of SimpleTest folder
./system/application/tests
./system/application/tests/models
./system/application/tests/views
./system/application/tests/controllers

Changes:

	* Added console writer for test suite.
	* Moved all of the file scanning into classes.
	* Fixed a bug where vim swp files are treated as test classes.
	* Fixed a bug where view files can never exclusively be processed.

Todo:

	* Unit Tests - how ironic :(
	* Fix potential problem if test folders do not exist.

License:

Free to use however you please... if it causes harm in anyway the authors are not liable.


*/
 
//Configure and load files
define('ROOT', dirname(__FILE__) . '/');
define('APP_ROOT', ROOT . 'system/application/');
 
require_once ROOT . 'system/test/unit_tester.php';
require_once ROOT . 'system/test/web_tester.php';
require_once ROOT . 'system/test/reporter.php';

class CodeIgniterUnitTestCase extends UnitTestCase {
	protected $ci;
	 
	public function __construct() {
		parent::UnitTestCase();
		$this-&amp;gt;ci =&amp;amp; get_instance();
	}
}
 
class CodeIgniterWebTestCase extends WebTestCase {
	protected $ci;
 
	public function __construct() {
		parent::WebTestCase();
		$this-&amp;gt;ci =&amp;amp; get_instance();
	}
}

function add_full_path( &amp;amp;$v, $k, $o ) {
	$o-&amp;gt;addImplementationPath($o-&amp;gt;getImplementationPath($v));
	$v = $o-&amp;gt;getTestPath() . '/' . $v;
}

function filter_hidden( $v ) {
	if( preg_match('/^\./', $v) ) {
		return FALSE;
	}

	return TRUE;
}


/**
 * BaseTestPath:
 *
 */
abstract class BaseTestPath {
	abstract function getTestPath();
	abstract function getImplementationPath($test);

	var $is_fullpath = FALSE;
	var $filenames = null;
	var $impl_filenames = array();

	function getFilenames() {
		if( $this-&amp;gt;filenames === null ) {
			$this-&amp;gt;filenames = @scandir($this-&amp;gt;getTestPath());
			$this-&amp;gt;filenames = array_filter( $this-&amp;gt;filenames, 'filter_hidden' );
		}
		return $this-&amp;gt;filenames;
	}

	function addToTestSuite( &amp;amp;$test ) {
		$this-&amp;gt;loadImplementations();
		foreach( $this-&amp;gt;getFilenamesWithFullPath() as $test_file ) {
			$test-&amp;gt;addFile( $test_file );
		}
	}

	function loadImplementations() {
		$this-&amp;gt;getFilenamesWithFullPath();
		foreach( $this-&amp;gt;impl_filenames as $impl ) {
			if( file_exists($impl) ) {
				require_once($impl);
			}
		}
	}

	function getFilenamesWithFullPath() {
		if( $this-&amp;gt;is_fullpath == FALSE ) {
			$this-&amp;gt;getFilenames();
			array_walk( $this-&amp;gt;filenames, 'add_full_path', $this );
			$this-&amp;gt;is_fullpath = TRUE;
		}

		return $this-&amp;gt;filenames;
	}

	function addImplementationPath( $impl_path ) {
		array_push($this-&amp;gt;impl_filenames, $impl_path);
	}
}


/**
 * ControllerTestPath:
 *
 */
class ControllerTestPath extends BaseTestPath {
	function getTestPath() {
		return APP_ROOT . 'tests/controllers';
	}

	function getImplementationPath( $test_filename ) {
		$controller = preg_replace( '#.*?([a-zA-Z0-9_\-]+)_controller_test.php$#', '$1.php', $test_filename );
		return APP_ROOT . 'controller/' . $controller;
	}
}


/**
 * ModelTestPath:
 *
 */
class ModelTestPath extends BaseTestPath {
	function getTestPath() {
		return APP_ROOT . 'tests/models';
	}

	function getImplementationPath($test_filename) {
		$model = preg_replace('#.*?([a-zA-Z0-9_\-]+_model)_test.php$#', '$1.php', $test_filename);
		return APP_ROOT . 'models/' . $model;
	}
}


/**
 * ViewTestPath:
 *
 */
class ViewTestPath extends BaseTestPath {
	function getTestPath() {
		return APP_ROOT . 'tests/views';
	}

	function getImplementationPath( $test_filename ) {
		$view = preg_replace('#.*?([a-zA-Z0-9_\-]+)_view_test.php$#', '$1.php', $test_filename);
		$view = implode( '/', explode('_',$view) );
		return APP_ROOT . 'views/' . $view;
	}
}


//Capture CodeIgniter output, discard and load system into $CI variable
ob_start();
include(ROOT . 'index.php');
$CI =&amp;amp; get_instance();
ob_end_clean();
 
//Setup the test suite
$test_suite =&amp;amp; new TestSuite();
$test_suite-&amp;gt;_label = 'CodeIgniter Application Test Suite';

$controller_tests = new ControllerTestPath();
$model_tests = new ModelTestPath();
$view_tests = new ViewTestPath();
$tests = array();

if( isset($_GET['controllers']) ) {
	array_push( $tests, $controller_tests );
}

if( isset($_GET['models']) ) {
	array_push( $tests, $model_tests );
}

if( isset($_GET['views']) ) {
	array_push( $tests, $view_tests );
}

if( sizeof($tests) == 0 ) {
	$tests = array( $model_tests, $view_tests, $controller_tests );
}

foreach( $tests as $test ) {
	$test-&amp;gt;addToTestSuite( &amp;amp;$test_suite );
}

//Run tests!
if (TextReporter::inCli()) {
	exit ($test_suite-&amp;gt;run(new TextReporter()) ? 0 : 1);
}
$test_suite-&amp;gt;run(new HtmlReporter());

/* End of file test.php */
/* Location: ./test.php */
&lt;/pre&gt;</content>
  </entry>
	
  
	
  <entry>
    <title>Kick dependence, here's an injection</title>
    <link href="http://junctionbox.ca/2009/11/03/kick-dependence--here-s-an-injection/"/>
    <updated>2009-11-03T00:00:00-08:00</updated>
    <id>http://junctionbox.ca/2009/11/03/kick-dependence--here-s-an-injection</id>
    <content type="html">&lt;p&gt;Recently I have been mulling the benefits of Dependency Injection in relationship to &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;.  I still question it&amp;#8217;s need, but I felt like an experiment for the fun of it.&lt;/p&gt;
&lt;p&gt;First I laid out the general interface I wanted to work with.  You may recognize it as being very similar to  &lt;a href=&quot;http://onestepback.org/index.cgi/Tech/Ruby/DependencyInjectionInRuby.rdoc&quot;&gt;this&lt;/a&gt; shamelessly &amp;#8220;php&amp;#8217;ized&amp;#8221; ruby code.&lt;/p&gt;
&lt;pre&gt;
function create_app() {
 $container = new DI_Container( );
 $container-&amp;gt;register( 'logfilename', 'logfile.log' );
 $container-&amp;gt;register( 'db_user', 'nfisher' );
 $container-&amp;gt;register( 'db_pass', 'secret' );
 $container-&amp;gt;register( 'dbi_string', 'db:host:and:stuff' );

 $container-&amp;gt;register( 'authenticator', function($c) {
  return new Authenticator( $c-&amp;gt;database, $c-&amp;gt;logger, $c-&amp;gt;error_handler );
} );

 $container-&amp;gt;register('error_handler', function($c) {
  $errh = new ErrorHandler( );
  $errh-&amp;gt;logger = $c-&amp;gt;logger;
  return $errh;
} );

 $container-&amp;gt;register('logger', function($c) {
  return new Logger( $c-&amp;gt;logfilename );
} );

 $container-&amp;gt;register('database', function($c) {
  return new DB( $c-&amp;gt;dbi_string, $c-&amp;gt;db_user, $c-&amp;gt;db_pass );
} );

 $container-&amp;gt;register('quotes', function($c) {
  return new StockQuotes( $c-&amp;gt;error_handler, $c-&amp;gt;logger );
} );

 $container-&amp;gt;register('webapp', function($c) { 
  $app = new WebApp( $c-&amp;gt;quotes, $c-&amp;gt;authenticator, $c-&amp;gt;database );
  $app-&amp;gt;logger = $c-&amp;gt;logger;
  $app-&amp;gt;set_error_handler( $c-&amp;gt;error_handler );
  return $app;
} );
}
&lt;/pre&gt;&lt;p&gt;\nNow I had a couple issues with the above implementation; string constants, and anonymous functions.&lt;/p&gt;
&lt;h3&gt;String Constants Aren&amp;#8217;t Unknown Objects&lt;/h3&gt;
&lt;p&gt;The DB/logfile config are not really dependencies.  It seems better to decouple them into a configuration class that can be initialized based on environment (ie/ dev, test, prod).&lt;/p&gt;
&lt;h3&gt;Absence of Anonymous Functions&lt;/h3&gt;
&lt;p&gt;Unfortunately my production environment is php 5.2, anonymous functions&amp;#8230;5.3 so its a simple problem of what&amp;#8217;s more important&amp;#8230; existing well tested env won out on that one.&lt;/p&gt;
&lt;p&gt;So I created a simple function binder with the following interface;&lt;/p&gt;
&lt;pre&gt;
interface Applyable {
 public function each( $o );
}

class FunctionBinder implements Applyable {
  private $_f_name;

  public function __construct( $f_name ) {
    $this-&amp;gt;_f_name;
  }

  /** each: Calls the stored function by name and passes the DI container as a reference. 
   */
  public function each( $c ) {
    return call_user_func( $this-&amp;gt;_f_name, $c );
  }
}
&lt;/pre&gt;
&lt;p&gt;The anonymous function became named;&lt;/p&gt;
&lt;pre&gt;
function create_logger( $c ) {
  return new Logger( $c-&amp;gt;logfilename );
}
&lt;/pre&gt;
&lt;p&gt;And the register became;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$container-&amp;gt;register('logger', new FunctionBinder('create_logger') );&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Code check in aisle 3&amp;#8230; code check&lt;/h3&gt;
&lt;p&gt;Trying to be a good little coder I built my tests first for the container.  I decided I would use the __get method to build the graphs the question was how!  My first naive approach was to throw exceptions from the __get method for currently incomplete objects.  As exceptions were thrown an immediate depth of dependencies would be identified through the exception handler&amp;#8230;okay it&amp;#8217;ll work, but it ain&amp;#8217;t gonna be pretty.  If your dependencies are spectacularly out of order it seems like an excessive unwinding of the call stack will occur just to keep the code down.&lt;/p&gt;
&lt;h3&gt;Testing 1.. 2&lt;/h3&gt;
&lt;p&gt;The next thought that occurred to me was why not include the dependencies with the registration process?&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$container-&amp;gt;register( 'logger', new FunctionBinder('create_logger'), 'logfilename' );&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;It seemed simple, but I didn&amp;#8217;t like it.  My dependencies were clearly defined inside of the create_logger function. Why duplicate effort, especially when it could potentially lead to an error.&lt;/p&gt;
&lt;h3&gt;Put on trial and Execute&lt;/h3&gt;
&lt;p&gt;While cooking dinner it dawned on me, why should the objects be instantiated directly? After all the goal is to minimize the usage of the new operator?  Factories to the rescue!&lt;/p&gt;
&lt;pre&gt;
function create_logger( $c ) {
 return $c-&amp;gt;build( Logger, $c-&amp;gt;logfilename );
}
&lt;/pre&gt;
&lt;p&gt;How does that change things?  Well it allows for a 2 phase process;&lt;/p&gt;
&lt;p&gt;Phase 1: Evaluate dependencies.&lt;br /&gt;
Phase 2: Instantiate objects.&lt;/p&gt;
&lt;p&gt;During Phase 1 no objects are actually built.  Instead evaluate the object requests and associate their dependencies.&lt;br /&gt;
Phase 2 is executed as soon as each objects dependencies are fulfilled. If an object has all of its dependencies fulfilled immediately then it is instantiated, otherwise it sits on the back burner waiting for it&amp;#8217;s time.&lt;/p&gt;
&lt;p&gt;I have a direction, stay tuned for the final product!&lt;/p&gt;</content>
  </entry>
	
  
	
  <entry>
    <title>Tripping over Rubies while Camping</title>
    <link href="http://junctionbox.ca/2009/06/17/tripping-over-rubies-while-camping/"/>
    <updated>2009-06-17T00:00:00-07:00</updated>
    <id>http://junctionbox.ca/2009/06/17/tripping-over-rubies-while-camping</id>
    <content type="html">&lt;p&gt;Today was another day like any other, but then I stopped and said hey &amp;#8220;GO team!!&amp;#8221;.  Okay not really, but it was a nice thought in retrospect.  Anyway I gave birth to a little app called SvnMaster&amp;#8230; the labour wasn&amp;#8217;t in the code, but rather debugging ActiveRecord 2.1.2 sqlite3 adapter and getting centos 5 up to speed. &lt;a href=&quot;http://redhanded.hobix.com/bits/campingAMicroframework.html&quot;&gt;Camping is a micro framework&lt;/a&gt; that was the perfect fit for the task. Maybe &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; was more appropriate for the problem domain.  However, much like the previous sentence it wasn&amp;#8217;t how I wanted to express myself.\nWorking with Centos 5 and ruby feels like watching a cute fuzzy thing being hunted by predators. It&amp;#8217;s painful to watch, but given my current server environment it is a necessary evil. Understand I&amp;#8217;m well familiar with the configure install shuffle (./configure &amp;amp;&amp;amp; make &amp;amp;&amp;amp; sudo make install), but it sure is a pain when it takes a couple of hours to get everything up to snuff.&lt;/p&gt;
&lt;p&gt;The first thing I did was &amp;#8220;gem update &amp;#8212;system&amp;#8221;.  Version 0.9.4, the default for Centos 5, sucks on small VPS&amp;#8217;s (mostly because it&amp;#8217;ll crash from resource constraints).  I&amp;#8217;ve been keeping up to date on Ruby so that&amp;#8217;s no worry, you may have to do the same.&lt;/p&gt;
&lt;p&gt;So I can pull gems down to my hearts content, or can I?  First up was RedCloth&amp;#8230; long story short the gem uses Ragel and Centos 5 only provides version 5.x as an &lt;span class=&quot;caps&quot;&gt;RPM&lt;/span&gt;. So a dependency hunting we will go. Building Ragel from source is pretty simple just follow the docs that are included. After Ragel was installed, RedCloth updated without any real complaints via gem install.  Next was installing camping;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;gem install camping  # nuff said, installs 1.5 with ease&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Once installed I started with some of the examples. I created the blog first just to wrap my head around the differences from Rails.  Each class is a route&amp;#8230; interesting.  Anyway I started up the app (camping blog.rb) and all seemed fine&amp;#8230; and then it hit I tried to login. Hmm curious the login doesn&amp;#8217;t work. I thought maybe there was a change with the way sessions worked so started reviewing the documentation on sessions.  Everything seemed in order so what was happening, I wrote a boiled down session test and checked the logs and opened the DB&amp;#8230; that&amp;#8217;s curious no entries or tables.  So on with the search for my apps apparent lack of state.&lt;/p&gt;
&lt;h3&gt;Active Campers lose weight when they&amp;#8217;ve got state!&lt;/h3&gt;
&lt;p&gt;So ActiveRecord 2.1.0 doesn&amp;#8217;t play nicely with camping&amp;#8217;s session model out of the box. Found in a thread that you need to turn off partial updates;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;AppName::Models::Base.partial_updates = false&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Booyah sessions work now! Well ActiveRecord in general does.  After spending the better part of a rainy Saturday updating and debugging I finally had a working blog&amp;#8230; on to my app!  The app was really simple a form to provide the name of new repositories, an output listing of existing svn repositories, and some backend processing which created the repository from a template directory structure.  The general idea was to provide an interface for the people I work with that would be quick, simple and consistent.  All in all it came together rather quickly and I&amp;#8217;m quite happy to have found a lovely new tool!&lt;/p&gt;</content>
  </entry>
	
  
	
  <entry>
    <title>REST + less weekend while Camping</title>
    <link href="http://junctionbox.ca/2008/09/23/rest-%2B-less-weekend-while-camping/"/>
    <updated>2008-09-23T00:00:00-07:00</updated>
    <id>http://junctionbox.ca/2008/09/23/rest-+-less-weekend-while-camping</id>
    <content type="html">&lt;p&gt;In the wee hours while visiting my family this weekend I decided to take a look at a few technologies;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt;&lt;/li&gt;
	&lt;li&gt;RestStop&lt;/li&gt;
	&lt;li&gt;Actionscript 3 URLStream&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I started out with RestStop&amp;#8217;s blog.rb as a starting point, and modified it as an event recorder.  It worked like a charm out of the box.  From there I wrote a quick Flash interface to &lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt; data to each controllers create method.  &lt;span class=&quot;caps&quot;&gt;BOOM&lt;/span&gt;, Ka-&lt;span class=&quot;caps&quot;&gt;POW&lt;/span&gt;, Problems&amp;#8230; I was getting a little unexpected funk from the way Flash was handling &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; status codes. IOErrorEvent&amp;#8217;s were being fired, babies cried, etc. So far my observations have shown that URLStream &amp;amp; URLLoader classes do a funky dance when they receive 3xx series status.  At a later date I would like to investigate further to see if the 3xx status is the cause of the IOErrorEvent. Ultimately the classes only report the final http status and none of the intermediary status changes.\nI decided to look around a little on Google into what I thought to be a fairly standardized protocol.  Turns out &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; is less of a protocol and more of a methodology.  Regardless of what you call it I&amp;#8217;d still like to work from a common community shared standard, at least when it comes to &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; status codes.  In that search I found the table below buried in the article &lt;a href=&quot;http://www.xml.com/pub/a/2004/12/01/restful-web.html&quot;&gt;How to Create a &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; Protocol&lt;/a&gt;. It was great my first resource that seemed to clearly define some constraints in what otherwise looked like the Wild West of RESTful web services.&lt;/p&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;strong&gt;Resource&lt;/strong&gt; &lt;/td&gt;
		&lt;td&gt; &lt;strong&gt;Method&lt;/strong&gt; &lt;/td&gt;
		&lt;td&gt; &lt;strong&gt;Representation&lt;/strong&gt; &lt;/td&gt;
		&lt;td&gt; &lt;strong&gt;Status Codes&lt;/strong&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; Employee &lt;/td&gt;
		&lt;td&gt; &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; &lt;/td&gt;
		&lt;td&gt; Employee Format &lt;/td&gt;
		&lt;td&gt; 200, 301, 410 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; Employee &lt;/td&gt;
		&lt;td&gt; &lt;span class=&quot;caps&quot;&gt;PUT&lt;/span&gt; &lt;/td&gt;
		&lt;td&gt; Employee Format &lt;/td&gt;
		&lt;td&gt; 200, 301, 400, 410 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; Employee &lt;/td&gt;
		&lt;td&gt; &lt;span class=&quot;caps&quot;&gt;DELETE&lt;/span&gt; &lt;/td&gt;
		&lt;td&gt; N/A &lt;/td&gt;
		&lt;td&gt; 200, 204 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; All Employees &lt;/td&gt;
		&lt;td&gt; &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; &lt;/td&gt;
		&lt;td&gt; Employee List Format &lt;/td&gt;
		&lt;td&gt; 200, 301 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; All Employees &lt;/td&gt;
		&lt;td&gt; &lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt; &lt;/td&gt;
		&lt;td&gt; Employee Format &lt;/td&gt;
		&lt;td&gt; 201, 400 &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;I pulled up the descriptions for each of the status codes, and made a short comment in my Camping app.&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
# Event GET			200,301,410
# Event PUT			200,301,400,410
# Event DELETE	200,204
# Events GET		200,301
# Events POST		201,400
#
# 200 - OK
# 201 - Created
# 204 - No Content
# 301 - Moved Permanently
# 400 - Bad Request
# 410 - Gone
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Now I want to take the previous table a little bit further to map out each of the states.&lt;/p&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;strong&gt;Resource&lt;/strong&gt; &lt;/td&gt;
		&lt;td&gt; &lt;strong&gt;Method&lt;/strong&gt; &lt;/td&gt;
		&lt;td&gt; &lt;strong&gt;Status&lt;/strong&gt; &lt;/td&gt;
		&lt;td&gt; &lt;strong&gt;Action&lt;/strong&gt; &lt;/td&gt;
		&lt;td&gt; &lt;strong&gt;Details&lt;/strong&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; Event &lt;/td&gt;
		&lt;td&gt; &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; &lt;/td&gt;
		&lt;td&gt; 200 &amp;#8211; OK &lt;/td&gt;
		&lt;td&gt; &lt;span class=&quot;caps&quot;&gt;READ&lt;/span&gt; =&amp;gt; Show Event &lt;/td&gt;
		&lt;td&gt; Event found, &lt;span class=&quot;caps&quot;&gt;READ&lt;/span&gt; Event. &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; . &lt;/td&gt;
		&lt;td&gt; * &lt;/td&gt;
		&lt;td&gt; 301 &amp;#8211; Moved Permanently &lt;/td&gt;
		&lt;td&gt; &lt;span class=&quot;caps&quot;&gt;READ&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;FAILED&lt;/span&gt; =&amp;gt; ?? &lt;/td&gt;
		&lt;td&gt; Event no longer available, renamed or moved. &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; . &lt;/td&gt;
		&lt;td&gt; * &lt;/td&gt;
		&lt;td&gt; 410 &amp;#8211; Gone &lt;/td&gt;
		&lt;td&gt; &lt;span class=&quot;caps&quot;&gt;READ&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;FAILED&lt;/span&gt; =&amp;gt; ?? &lt;/td&gt;
		&lt;td&gt; Event no longer available/never existed. &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; . &lt;/td&gt;
		&lt;td&gt; &lt;span class=&quot;caps&quot;&gt;PUT&lt;/span&gt; &lt;/td&gt;
		&lt;td&gt; 200 &amp;#8211; OK &lt;/td&gt;
		&lt;td&gt; &lt;span class=&quot;caps&quot;&gt;UPDATE&lt;/span&gt; =&amp;gt; Show Event w/ Updates &lt;/td&gt;
		&lt;td&gt; Event updated, &lt;span class=&quot;caps&quot;&gt;SHOW&lt;/span&gt; updated event &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;</content>
  </entry>
	
  
	
  <entry>
    <title>Sprout an AsWing</title>
    <link href="http://junctionbox.ca/2008/09/19/sprout-an-aswing/"/>
    <updated>2008-09-19T00:00:00-07:00</updated>
    <id>http://junctionbox.ca/2008/09/19/sprout-an-aswing</id>
    <content type="html">&lt;p&gt;Looking to throw together a quick app in Flash to test Sprouts I decided on working with AsWing.  Here&amp;#8217;s some of the process I followed to get the environment up and going.&lt;/p&gt;
&lt;p&gt;Install the sprouts gem;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;# sudo gem install sprouts&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Download the latest aswing package;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://code.google.com/p/aswing/downloads/list&quot;&gt;AsWing on Google Code&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Create a new project;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;# sprout -n as3 TickTock&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Copy AsWing.swc into TickTock/lib.&lt;/p&gt;
&lt;p&gt;Modify the debug task in TickTock/rakefile.rb as illustrated:&lt;/p&gt;
&lt;pre&gt;
desc 'Compile and debug the application'
debug :debug do |t|
	t.input = 'src/TickTock.as'
	t.library_path &amp;lt;&amp;lt; &quot;lib/AsWing.swc&quot;
end
&lt;/pre&gt;</content>
  </entry>
	
  
	
  <entry>
    <title>Ruby be nimble, Ruby be SWF...</title>
    <link href="http://junctionbox.ca/2008/09/04/ruby-be-nimble--ruby-be-swf---/"/>
    <updated>2008-09-04T00:00:00-07:00</updated>
    <id>http://junctionbox.ca/2008/09/04/ruby-be-nimble--ruby-be-swf---</id>
    <content type="html">&lt;p&gt;This is a quick post with notes on the &lt;a href=&quot;http://www.adobe.com/devnet/swf/pdf/swf_file_format_spec_v9.pdf&quot;&gt;&lt;span class=&quot;caps&quot;&gt;SWF&lt;/span&gt; format&lt;/a&gt;.  Well so far it&amp;#8217;s only one really, and it is in reference to compression.&lt;/p&gt;
&lt;p&gt;From page 13, 3rd paragraph in the documentation;&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;&amp;#8220;The FileLength field is the total length of the &lt;span class=&quot;caps&quot;&gt;SWF&lt;/span&gt; file, including the header. If this is an&lt;br /&gt;
uncompressed &lt;span class=&quot;caps&quot;&gt;SWF&lt;/span&gt; file (&lt;span class=&quot;caps&quot;&gt;FWS&lt;/span&gt; signature), the FileLength field should exactly match the file&lt;br /&gt;
size. If this is a compressed &lt;span class=&quot;caps&quot;&gt;SWF&lt;/span&gt; file (&lt;span class=&quot;caps&quot;&gt;CWS&lt;/span&gt; signature), the FileLength field indicates the total&lt;br /&gt;
length of the file after decompression, and thus generally does not match the file size. Having&lt;br /&gt;
the uncompressed size available can make the decompression process more efficient.&amp;#8221;&lt;br /&gt;
\nSeems pretty clear and straight forward, but it doesn&amp;#8217;t really reference where the compression starts.  I initially assumed, that it starts at the end of the &lt;span class=&quot;caps&quot;&gt;SWF&lt;/span&gt; header.  The end of the header seemed like a logical boundary to me. What I quickly found with &lt;a href=&quot;http://www.suavetech.com/0xed/0xed.html&quot;&gt;0xED&lt;/a&gt; is that compression starts immediately after the 32-bit FileLength.  Okay so now we know, and knowing is half the battle! What next?&lt;/p&gt;
&lt;h3&gt;Toes to the edge, and wait for the gun.&lt;/h3&gt;
&lt;p&gt;Okay so we know that the compression starts &lt;strong&gt;after&lt;/strong&gt; the length. How do we decompress it? Enter the standard Zlib library built-in to Ruby. It starts with a simple;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;require 'zlib'&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;And requires the compressed contents in a string buffer like so;&lt;/p&gt;
&lt;pre&gt;
def read_remaining_bytes
	pos = @file.tell
	@file.seek( 0, IO::SEEK_END )
	end_pos = @file.tell
	@file.pos = pos
	@file.read( end_pos - pos )
end
&lt;/pre&gt;
&lt;p&gt;Note: @file is a file handle using File.new( filename, &amp;#8216;r&amp;#8217; ), it is assumed the position in the file is the first byte immediately after the &lt;span class=&quot;caps&quot;&gt;SWF&lt;/span&gt; length attribute.  See SwfReader in &lt;a href=&quot;http://junctionbox.ca/projects/ruby-swfer/&quot;&gt;Ruby-Swfer&lt;/a&gt; for further details.&lt;/p&gt;
&lt;h3&gt;Inflate those water wings and kick!&lt;/h3&gt;
&lt;p&gt;Okay we have our compressed content now lets inflate it!&lt;/p&gt;
&lt;pre&gt;
def decompress( compressed_contents )
	zstream = Zlib::Inflate.new
	decompressed_contents = zstream.inflate( compressed_contents )
	zstream.finish
	zstream.close
	decompressed_contents
end
&lt;/pre&gt;
&lt;p&gt;And voila, you should have all your bytes in a nice little (big) string. All you have left is to run through each byte and decode to your hearts content.&lt;/p&gt;</content>
  </entry>
	
  
	
  <entry>
    <title>Watch for Flying Bitmaps</title>
    <link href="http://junctionbox.ca/2008/08/26/watch-for-flying-bitmaps/"/>
    <updated>2008-08-26T00:00:00-07:00</updated>
    <id>http://junctionbox.ca/2008/08/26/watch-for-flying-bitmaps</id>
    <content type="html">&lt;p&gt;Zee goal for today is to use ActionScript 3&amp;#8217;s BitmapData to slice and dice a bitmap like a fine piece of sashimi.  A few applications include;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;client-side image croppers.&lt;/li&gt;
	&lt;li&gt;runtime cropping of linked and external photos for panel backgrounds.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What I will illustrate here is just a simple sliding door effect.  As seen in the &lt;span class=&quot;caps&quot;&gt;SWF&lt;/span&gt; below. The items of greatest interest today include;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;flash.display.Bitmap&lt;/li&gt;
	&lt;li&gt;flash.display.BitmapData&lt;/li&gt;
	&lt;li&gt;flash.geom.Point&lt;/li&gt;
	&lt;li&gt;flash.geom.Rectangle\nOtay so lets layout what we need and what we generally want to do.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Halves Too #Include&lt;/h3&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;span class=&quot;caps&quot;&gt;JPG&lt;/span&gt; or &lt;span class=&quot;caps&quot;&gt;PNG&lt;/span&gt; that we want to slice up.&lt;/li&gt;
	&lt;li&gt;Flash compiler (Flex &lt;span class=&quot;caps&quot;&gt;SDK&lt;/span&gt;/Flash 9/etc).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Blueprints, get your blueprints here!!&lt;/h3&gt;
&lt;p&gt;We are planning a sliding door effect that does not use a mask, where do we start? Well like all things even vaguely cool we require a little math. First lets create an additional 99 frames on our root timeline. Next drag your photo into the Library and create a linkage with a class name of &lt;strong&gt;TestPhoto&lt;/strong&gt;. Done? Good now that we&amp;#8217;ve made some room and set the table lets eat!&lt;/p&gt;
&lt;h3&gt;What size slice of pizza would you like with your BitmapData?&lt;/h3&gt;
&lt;p&gt;For this test I decided the number of frames works well to decide my slice size. Each frame is equal to a 1% increment reveal of the bitmap because of those extra 99 frames we added earlier.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;var percentage:int = currentFrame / totalFrames;&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;I&amp;#8217;m full what next?&lt;/h3&gt;
&lt;p&gt;Remember those extra 99 frames I asked you to add? Well they come in handy when used in conjunction with a frame listener. Below you will find only what is required for the dynamic slice using the current frame to calculate the percentage of image to reveal.&lt;/p&gt;
&lt;pre&gt;
var slice_width:int = percentage * bitmap_width; 
var slice_data:BitmapData = new BitmapData( slice_width, source_bitmap.height );

// left edge is stationary
var crop_region:Rectangle = new Rectangle( 0, 0, slide_width, source_bitmap.height );
var destination_point:Point = new Point( 0, 0 );

// here's where the magic happens
slice_data.copyPixels( source_bitmap, crop_region, destination_point );
var slice_bitmap:Bitmap = new Bitmap( slice_data );

addChild( slice_bitmap );
&lt;/pre&gt;
&lt;h3&gt;Would you like a mint sir?&lt;/h3&gt;
&lt;p&gt;Okay at some point you&amp;#8217;re going to be full to the brim, or at least providing a full reveal of your image. What if you want to downsize? As &lt;a href=&quot;http://www.johnralstonsaul.com/SUM_Unconscious.html&quot;&gt;Mr. Saul&lt;/a&gt; might argue, downsizing often has a detrimental effect. While I agree, I&amp;#8217;m not here to argue corporate politics. The best way to deal with this conundrum is to clean up after yourself.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;if( numChildren &amp;gt; 1 ) removeChildAt( 0 );&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Cheque please!&lt;/h3&gt;
&lt;p&gt;Lets wrap this all up in a class for take-out.&lt;/p&gt;
&lt;pre&gt;
/**
 * Written by: Nathan Fisher
 * License: Do with this what you want just don't blame me if it blows up. 
 * 
 * For the simple test use this as your root document class.
 */
package {
 // photo linkage class name
 import SourceBitmap;

 import flash.display.Bitmap;
 import flash.display.BitmapData;
 import flash.display.MovieClip;
 import flash.display.Sprite;

 import flash.events.Event;

 import flash.geom.Point;
 import flash.geom.Rectangle;

 public class SlidingDoor extends MovieClip {
  public static const PHOTO_WIDTH:int = 720;
  public static const PHOTO_HEIGHT:int = 478;
  public static const DESTINATION_POINT:Point = new Point( 0, 0 );

  private var source_data:BitmapData;
  private var slice_container:Sprite;
  private var bitmap_width:int;


  /** SlidingDoor: Constructs a sliding door effect using the specified BitmapData.
   *
   */
  public function SlidingDoor( theSourceData:BitmapData = null )
  {
   if( theSourceData == null ) theSourceData = new TestPhoto( PHOTO_WIDTH, PHOTO_HEIGHT );
   source_data = theSourceData;
   bitmap_width = theSourceData.width;

   slice_container = new Sprite( );
   addChild( slice_container );
   addEventListener( Event.ENTER_FRAME, frameListener );
  }


  /** frameListener: Each passing frame represents a percentage of the photo to reveal.
   *
   */
  public function frameListener( e:Event ):void
  {
   var slice_width:int = percentage * bitmap_width; 
   var slice_data:BitmapData = new BitmapData( slice_width, source_bitmap.height );

   // left edge is stationary
   var crop_region:Rectangle = new Rectangle( 0, 0, slide_width, source_bitmap.height );
   var destination_point:Point = new Point( 0, 0 );

   // here's where the magic happens
   slice_data.copyPixels( source_bitmap, crop_region, destination_point );
   var slice_bitmap:Bitmap = new Bitmap( slice_data );

   // what good is art if no one see's it? Add to the slice_container so it is visible.
   slice_container.addChild( slice_bitmap );
   // remove previous slices if applicable.
   if( slice_container.numChildren &amp;gt; 1 ) slice_container.removeChildAt( 0 );
  }
 }
}
&lt;/pre&gt;
&lt;p&gt;In the example above I assumed the bitmap slice is the only element in it&amp;#8217;s parent container. As illustrated in the full class definition I suggest creating an empty MovieClip or Sprite that is reserved for such a purpose.&lt;/p&gt;
&lt;h3&gt;Flash to 2 minutes later in the lavatory&amp;#8230; &lt;span class=&quot;caps&quot;&gt;OUTPUT&lt;/span&gt;!&lt;/h3&gt;
&lt;p&gt;&lt;object type=&quot;application/x-shockwave-flash&quot; data=&quot;/images/phototest.swf&quot; width=&quot;550&quot; height=&quot;400&quot;&gt;&lt;br /&gt;
&lt;param name=&quot;movie&quot; value=&quot;/images/phototest.swf&quot; /&gt;&lt;br /&gt;
&lt;/object&gt;&lt;/p&gt;
&lt;h3&gt;Notes &amp;amp; Other Weirdness&lt;/h3&gt;
&lt;p&gt;The class can be refined much further including a setter for the bitmap data. Like all things in life there is always room for improvement.&lt;/p&gt;
&lt;p&gt;The included photo was provided by &lt;a href=&quot;http://www.tessierpools.com/&quot;&gt;Tessier Pools&lt;/a&gt; and is a &lt;a href=&quot;http://www.questarpools.com/&quot;&gt;Skip Phillips&lt;/a&gt; design.&lt;/p&gt;</content>
  </entry>
	
  
	
  <entry>
    <title>Beware the Garbage Man's Scope</title>
    <link href="http://junctionbox.ca/2008/07/25/beware-the-garbage-man-s-scope/"/>
    <updated>2008-07-25T00:00:00-07:00</updated>
    <id>http://junctionbox.ca/2008/07/25/beware-the-garbage-man-s-scope</id>
    <content type="html">&lt;p&gt;Garbage collection can be an amazing resource to the developer, except when you forget its there as I did in a recent project.  I&amp;#8217;ll be honest I started cutting my teeth on x86 assembler and C++. The mantra of the day was, don&amp;#8217;t assume anything and clean up after yourself. Unless you&amp;#8217;re trying to piss off the neighbours, which is never of any real benefit.  The simplified example of what happened is a variable initialization like so;&lt;br /&gt;
\n@new Tween( pages, &amp;#8220;rotation&amp;#8221;, Elastic.easeOut, src, dest, duration, true );@&lt;/p&gt;
&lt;p&gt;You can only guess how dirty I felt typing it, looking at it, breathing it in and digesting it.  It was wrong and I knew it. Its only reason for existence was laziness coupled with a 3am sugar buzz.  I figured, &amp;#8220;Why create a member variable? I don&amp;#8217;t care what happens to it after its done its deed.&amp;#8221;&lt;/p&gt;
&lt;p&gt;Unfortunately I didn&amp;#8217;t realize how wrong it was until seemingly at random its expected effect would get tossed like &lt;a href=&quot;http://www.foxmovies.com/fightclub/&quot;&gt;Marla&amp;#8217;s bridesmaid dress&lt;/a&gt;.  Intensely loved for a moment, and unwittingly thrown to the curbside the second the garbage collector came along. I did a whole lot of &lt;em&gt;unnecessary&lt;/em&gt; dancing around to debug why something so foolish wasn&amp;#8217;t working 20% of the time. It was random, I wanted to pull out my hair.  I think there were brief moments where I actually did.  I finally gave it a big b-tch slap and applied some brute force using a &amp;#8220;watchdog&amp;#8221; timer that snapped it into the destination angle.  The timer was jarring to the user, it was a defeat for me, but it ensured the content was accessible instead of periodically ending in a rotation somewhere between here and Timbuktu.&lt;/p&gt;
&lt;p&gt;I published the site only to shortly after find my salvation in the comments on Adobe&amp;#8217;s Flash 9 Livedocs.  I cursed myself immensely at its simplicity, and my foolishness.  The simple fact of the matter is I didn&amp;#8217;t take into account scope. I applied C++ assumptions of variable life time, whilst at the same time discarding the method for proper clean-up, a reference to the original object.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;In the future kids don&amp;#8217;t play with matches, and if you want an object to last beyond a methods or functions scope make sure it is referenced outside of that method.&lt;/p&gt;
&lt;pre&gt;
private var _rotation_tween:Tween;
public function rotatePage( dest ):void {
 _rotation_tween = new Tween( pages, &quot;rotation&quot;, Elastic.easeOut, src, dest, duration, true );
}
&lt;/pre&gt;</content>
  </entry>
	
  
	
  <entry>
    <title>Regular Expression & Parsed Elation</title>
    <link href="http://junctionbox.ca/2008/07/04/regular-expression---parsed-elation/"/>
    <updated>2008-07-04T00:00:00-07:00</updated>
    <id>http://junctionbox.ca/2008/07/04/regular-expression---parsed-elation</id>
    <content type="html">&lt;p&gt;Here&amp;#8217;s a little app I wrote during a project to test ActionScript 3&amp;#8217;s regular expressions.&lt;/p&gt;
&lt;p&gt;&lt;object type=&quot;application/x-shockwave-flash&quot; data=&quot;/images/as3regex.swf&quot; width=&quot;900&quot; height=&quot;500&quot;&gt;&lt;br /&gt;
&lt;param name=&quot;movie&quot; value=&quot;/images/as3regex.swf&quot; /&gt;&lt;br /&gt;
&lt;/object&gt;&lt;/p&gt;</content>
  </entry>
	
  
	
  <entry>
    <title>Subversive Lyrics with Subversion</title>
    <link href="http://junctionbox.ca/2008/06/26/subversive-lyrics-with-subversion/"/>
    <updated>2008-06-26T00:00:00-07:00</updated>
    <id>http://junctionbox.ca/2008/06/26/subversive-lyrics-with-subversion</id>
    <content type="html">&lt;p&gt;The plan for today is to build an automated test environment (static websites only) that updates with each commit. Now I should forewarn you if you play this article backwards the devil will steal your dog, and wife, and leave you with nothing more than a crappy country song. Should that or anything else bad happen be an adult and take responsibility for your own actions, aka I&amp;#8217;m not liable.  Also if you don&amp;#8217;t know what subversion is this article is not a good place to start.\nh3. Ingredients&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Wildcard &lt;span class=&quot;caps&quot;&gt;DNS&lt;/span&gt;&lt;/li&gt;
	&lt;li&gt;Apache 2.2&lt;/li&gt;
	&lt;li&gt;Subversion 1.4.x (&lt;span class=&quot;caps&quot;&gt;SVN&lt;/span&gt;)&lt;/li&gt;
	&lt;li&gt;Your favourite scripting language&lt;/li&gt;
	&lt;li&gt;Back-ups, back-ups, back-ups!!!!!&lt;/li&gt;
	&lt;li&gt;Couple of hours&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Okay so how is all of this going to look? Well lets say you have a client named Example and their website is located at example.com.  The goal is to achieve a test site located at http://example.com.projects.myhost.ca/, it&amp;#8217;s a doozy to type, but it&amp;#8217;ll create consistency. Besides the amount of time spent typing will be more than offset by the time it saves you once configured properly.&lt;/p&gt;
&lt;h3&gt;Initial Imports Insulate Against Insolence&lt;/h3&gt;
&lt;p&gt;Okay so lets say you&amp;#8217;ve used svnadmin and created a webdav accessible repository at http://myhost.ca/svn/example.com/, how should the initial import look?&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;branches&lt;/li&gt;
	&lt;li&gt;tags&lt;/li&gt;
	&lt;li&gt;trunk
	&lt;ul&gt;
		&lt;li&gt;site&lt;/li&gt;
		&lt;li&gt;src&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you&amp;#8217;ll note it&amp;#8217;s a pretty vanilla setup for subversion.  So moving forward we&amp;#8217;ll assume that trunk/site contains the latest and greatest of your clients website and trunk src is a dumping ground for your Illustrator, Photoshop, Actionscript and FLA&amp;#8217;s, etc.&lt;/p&gt;
&lt;h3&gt;We Hosts Da Vhosts&lt;/h3&gt;
&lt;p&gt;So what&amp;#8217;s next? Lets get ready to rumble cuz we&amp;#8217;re going to create our vhost configuration. Pick your poison, but you can either append the following setup to your httpd.conf or add a new file named vhosts.conf in your conf.d folder.&lt;/p&gt;
&lt;pre&gt;
LogFormat &quot;%V %h %l %u %t \&quot;%r\&quot; %s %b&quot; vcommon

&amp;lt;Directory /var/www/vhosts/project&amp;gt;
# adjust override as you see fit
AllowOverride All
&amp;lt;/Directory&amp;gt;

&amp;lt;virtualhost *:80&amp;gt;
ServerName *.projects.myhost.ca

VirtualDocumentRoot /var/www/vhosts/projects/%-4+

ErrorLog logs/projects.myhost.ca-error_log
CustomLog logs/projects.myhost.ca-access_log vcommon
&amp;lt;/virtualhost&amp;gt;
&lt;/pre&gt;
&lt;h3&gt;Sweet Script O&amp;#8217;Mine&lt;/h3&gt;
&lt;p&gt;Where do we go now&amp;#8230; &lt;span class=&quot;caps&quot;&gt;GNR&lt;/span&gt; flashback&amp;#8230; I think not! So we&amp;#8217;ve got a repository and vhost now what? You&amp;#8217;ve got 2 options here;&lt;br /&gt;
write a script that updates an existing checkout.&lt;br /&gt;
write a script that creates a checkout if it does not exist or updates if it does.&lt;br /&gt;
Option 1 is what I&amp;#8217;ve gone with as I&amp;#8217;ve placed the checkout in a script for the creation of my repository. The benefit to Option 2 is that it ensures you&amp;#8217;re checkout environment will have the right permissions for svn updates.&lt;/p&gt;
&lt;p&gt;My script looks a little like the following;&lt;/p&gt;
&lt;pre&gt;
#!/usr/bin/ruby -w
#
# update.rb: Takes a repository URI as a single argument and uses the 
#    last directory in the URI as part of the update path.
#

if ARGV.length != 1
 puts &quot;You must specify a repository!&quot;
end

# this folder must be owned by your webservers uid if you go with option 2
PROJECTS_PATH='/var/www/vhosts/projects/'

begin
 site_name = ARGV[0].split( /\// );
 site_name = site_name[site_name.length - 1]
 
 `svn update #{PROJECTS_PATH + site_name}`
rescue
 # pick a error notification method log it, email it wuteva you want
end
&lt;/pre&gt;
&lt;p&gt;Now add this to the end of your post-commit hook as follows;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/somepath/update.rb &quot;$REPOS&quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Everytime you commit, it will automatically update a test copy of the site located at;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;http://example.com.projects.myhost.ca/&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;This is a simple way to give the whole family access to test websites without the clutter and extra time of using &lt;span class=&quot;caps&quot;&gt;FTP&lt;/span&gt;.&lt;/p&gt;</content>
  </entry>
	
  
	
  <entry>
    <title>Scrollpane Woes to Fix the Flow</title>
    <link href="http://junctionbox.ca/2008/06/26/scrollpane-woes-to-fix-the-flow/"/>
    <updated>2008-06-26T00:00:00-07:00</updated>
    <id>http://junctionbox.ca/2008/06/26/scrollpane-woes-to-fix-the-flow</id>
    <content type="html">&lt;p&gt;Using the V2 ScrollPane component, externally loaded SWF’s may visually overflow outside of the defined ScrollPane area. Quite often the scrolling will still work, however the masking does not do its job as expected. In trying to solve the problem we have used everything from overloading the Loader class methods to simply calling invalidate briefly after the data loads.\nh3. Coming to an understanding is part of the problem.&lt;/p&gt;
&lt;p&gt;To fully understand the problem you need to go into the interaction between the Flash player, V2 components, and MovieClips. First off you will rarely, if ever, experience this problem in the Flash Developer environment. Why? The problem appears to be timing, and local files generally have no measurable load time relative to their web based counterparts. In your browser once the &lt;span class=&quot;caps&quot;&gt;SWF&lt;/span&gt; has been cached the next refresh of the page generally works fine. Wipe your cache and watch the problem return.&lt;/p&gt;
&lt;h3&gt;Where does the MovieClip class fit in?&lt;/h3&gt;
&lt;p&gt;MovieClip objects wipe their event handlers with a loadMovie, except the onClipEvent(), and variations of on(). For dynamically created clips it means you need to monitor the MovieClip outside of the MovieClip’s instance. On moderate to slow connections the ScrollPane seems to report a &lt;span class=&quot;caps&quot;&gt;SWF&lt;/span&gt; file being loaded before it is actually complete, most likely because of the way it monitors the loading process.&lt;/p&gt;
&lt;h3&gt;A Solution.&lt;/h3&gt;
&lt;p&gt;As mentioned previously we’ve tried a couple different methods to resolve this problem. While ours has its limitations it works where we need it to. The initial implementation was as follows:&lt;/p&gt;
&lt;pre&gt;
var check_loaded:Object = { _frequency: 500, 
  _intervalID: null,
  callback: null,
  pane: null,
// start
  start: function() {
    this.stop( );// clear any running instances
    this._intervalID = setInterval( this, &quot;checkPane&quot;, this._frequency );
    this.pane._visible = false;
  },  // ::start(...
// stop
  stop: function() {
    if(this._intervalID !== null) {
      clearInterval(this._intervalID);
    }  // if(...
    this._intervalID = null;
  },  // ::stop(...
// checkPane
  checkPane: function() { 
    var clip:MovieClip = this.pane.content;
    if( clip !== null ) {
      var total:Number = clip.getBytesTotal();
      var current:Number = clip.getBytesLoaded();
      // 36 is the size of a blank flash file
      if( current &amp;gt;= total &amp;amp;&amp;amp; total &amp;gt;= 36 ) {
        this.stop( );
        this.pane.refreshPane( );
        this.pane._visible = true;
        if( this.callback !== null ) {
          this.callback( );
        }  // if(...
      }// if(...
      trace( current + &quot; of &quot; + total );
    }  // if(...
  }  // ::checkPane(...
};
&lt;/pre&gt;
&lt;p&gt;Enough already here’s how you use it with your ScrollPane.&lt;/p&gt;
&lt;pre&gt;
theScrollPane.contentPath = &quot;CONTENT.swf&quot;;
check_loaded.pane = theScrollPane;
check_loaded.start( );
&lt;/pre&gt;
&lt;p&gt;It works, but isn’t a clean OO implementation. A better approach is to reorganize the code into a separate ActionScript class.  See &lt;a href=&quot;http://junctionbox.ca/images/F3MaskPane.as&quot;&gt;F3MaskPane&lt;/a&gt; for my implementation. With your new shiny class your code will look like below instead of the two blocks of code above.&lt;/p&gt;
&lt;pre&gt;
import F3MaskPane; 
var check_loaded:F3MaskPane = new F3MaskPane( theScrollPane ); 
theScrollPane.contentPath = &quot;CONTENT.swf&quot;; 
check_loaded.start( );
&lt;/pre&gt;
&lt;h3&gt;Notes and limitations on F3MaskPane.&lt;/h3&gt;
&lt;p&gt;If you depend/expect your border to be visible prior to loading content you’ll need to find another way.&lt;br /&gt;
The visibility of the ScrollPane is turned off to prevent the blink that occurs during the refreshPane call.&lt;br /&gt;
The F3MaskPane must not extend the Object class because of what appears to be a bug with calls to setInterval.&lt;br /&gt;
There is currently no upper limit on the number of iterations that checkPane will be called.&lt;br /&gt;
Audio maybe a problem because of the refreshPane.&lt;br /&gt;
That’s all for now.&lt;/p&gt;</content>
  </entry>
	
  
	
  <entry>
    <title>Rsync Daily Snapshots</title>
    <link href="http://junctionbox.ca/2006/04/17/rsync-daily-snapshots/"/>
    <updated>2006-04-17T00:00:00-07:00</updated>
    <id>http://junctionbox.ca/2006/04/17/rsync-daily-snapshots</id>
    <content type="html">&lt;p&gt;Need to backup in a hurry? Want to create daily snapshots that don&amp;#8217;t take more drive platters than Google? Here&amp;#8217;s a quick and efficient way to back-up data from your &lt;span class=&quot;caps&quot;&gt;RSYNC&lt;/span&gt; server. &lt;strong&gt;Warning&lt;/strong&gt; do not try this on the interweb kids, only on a trusted link (ie/ not the wild west that is the inter-web).&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;HOST&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;localhost.localdomain
&lt;span class=&quot;nv&quot;&gt;BASE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/home/samba/rsync
&lt;span class=&quot;nv&quot;&gt;DATEDIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;date +%Y-%m-%d-%a&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;CUR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;current
&lt;span class=&quot;nv&quot;&gt;BAK&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;HOME ETC VAR&amp;quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;CURVOL in &lt;span class=&quot;nv&quot;&gt;$BAK&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
rsync -avz --delete --force rsync://&lt;span class=&quot;nv&quot;&gt;$HOST&lt;/span&gt;/&lt;span class=&quot;nv&quot;&gt;$CURVOL&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$BASE&lt;/span&gt;/&lt;span class=&quot;nv&quot;&gt;$CUR&lt;/span&gt;/&lt;span class=&quot;nv&quot;&gt;$CURVOL&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;

mkdir &lt;span class=&quot;nv&quot;&gt;$BASE&lt;/span&gt;/&lt;span class=&quot;nv&quot;&gt;$DATEDIR&lt;/span&gt;
cp -Rl &lt;span class=&quot;nv&quot;&gt;$BASE&lt;/span&gt;/&lt;span class=&quot;nv&quot;&gt;$CUR&lt;/span&gt;/* &lt;span class=&quot;nv&quot;&gt;$BASE&lt;/span&gt;/&lt;span class=&quot;nv&quot;&gt;$DATEDIR&lt;/span&gt;/
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</content>
  </entry>
	
  
</feed>

