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

  <title><![CDATA[Hamish Rickerby]]></title>
  <link href="http://hamishrickerby.com/atom.xml" rel="self"/>
  <link href="http://hamishrickerby.com/"/>
  <updated>2012-01-27T15:13:48+11:00</updated>
  <id>http://hamishrickerby.com/</id>
  <author>
    <name><![CDATA[Hamish Rickerby]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Continuous Integration and iOS]]></title>
    <link href="http://hamishrickerby.com/2012/01/27/continuous-integration-and-ios/"/>
    <updated>2012-01-27T14:00:00+11:00</updated>
    <id>http://hamishrickerby.com/2012/01/27/continuous-integration-and-ios</id>
    <content type="html"><![CDATA[<p>The client project I&#8217;m currently working on is quite large. There are over 90 different screens required in the application, and regression testing all of these, with the different data variants and scenarios is not something I&#8217;d like to attempt by hand, and is not something I would expect my client to pay for me (or anyone for that matter) to do. Both unit and application tests can be automated, and I figured that this was something that I should do for this project to ensure changes I introduce don&#8217;t break existing functionality, and any bugs found won&#8217;t be introduced.</p>

<p>To solve this challenge I have introduced a Continuous Integration (CI) server to my workflow. My goals were to have unit and application tests automatically executed when an commit is made to a specific branch in a (local) git repository, and if both of these phases are successful, have the application packaged up, ready for distribution. I also wanted this successful build to be deployed on a daily basis to TestFlight so my client (and any other human testers in the future) could pick it up on their devices. I also wanted code coverage reporting, for both the unit and application tests, so I can see what parts of the application logic and screen flows are actually being tested to give me a level of confidence that the right stuff is getting the attention. The application tests also needed to be executed in a headless manner - I don&#8217;t have a physically separate machine (or VM) to run the CI server in, so I don&#8217;t want the simulator popping up and distracting me.</p>

<p><em>Warning - this is long and involved. I&#8217;ve also written this after the fact. I hope I&#8217;ve captured all the steps but if something doesn&#8217;t work for you please let me know and I&#8217;ll try to help and update this guide.</em></p>

<h2>Toolkit</h2>

<p>I used a set of existing tools to help with this</p>

<ol>
<li>CI Server - Jenkins</li>
<li>Unit Tests - SenTest/OCUnit - it&#8217;s baked right into Xcode and meets my needs. It&#8217;s hard for me to justify using something else like GHUnit because of the pre-integration.</li>
<li>Application (UI) Tests - Frank - I wanted to use a behaviour driven approach to UI testing, as well as something my client could actually specify tests in. Frank is cucumber based, so uses an english language syntax, making it easy for non-developers to specify and understand tests.</li>
<li>Deployment - Curl - low tech, but the TestFlight API is simple to use, so nothing more complex is really required here. It could be wrapped in a Jenkins plugin, but I&#8217;m not the guy to create that&#8230;</li>
</ol>


<p>And this is how I did it. I cobbled together all the tools I needed with help from various blogs, stack overflow answers, and vendor documentation. I&#8217;ve referenced the sources where I can. Hat tips to all.</p>

<h2>Installation of Prerequisites</h2>

<h3>Install rvm</h3>

<p>You&#8217;ll need ruby for compiling Frank, and I recommend you use <a href="http://beginrescueend.com/">rvm</a> for this. Paste the following into a shell and follow the instructions.</p>

<p><code>bash -s stable &lt; &lt;(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)</code></p>

<p>Extra install instructions (head builds, multi-user etc) are available at <a href="http://beginrescueend.com/rvm/install/">http://beginrescueend.com/rvm/install/</a></p>

<p>You&#8217;ll need to close and open shell after following the instructions (including modification of your <code>.bash_profile</code>). You&#8217;ll also need to install your favourite ruby. I recommend installing 1.9.2 with <code>rvm install 1.9.2</code></p>

<p>You&#8217;ll also need rake (for managing Frank&#8217;s build process), so you can get that with <code>gem install rake</code></p>

<h3>Install homebrew</h3>

<p>I used <a href="http://mxcl.github.com/homebrew/">homebrew</a> to install Jenkins. It&#8217;s a good package manager for OSX, and well maintained. Instructions are at <a href="https://github.com/mxcl/homebrew/wiki/installation">https://github.com/mxcl/homebrew/wiki/installation</a> but you can just paste the following into a shell and it&#8217;ll install.</p>

<p><code>/usr/bin/ruby -e "$(curl -fsSL https://raw.github.com/gist/323731)"</code></p>

<h3>Install Python and gcovr</h3>

<p>gcovr (and python) are needed to generate the coverage files from the unit and application test output. <em>If you already have a modern python installation (2.7) then skip the python installation step and just install gcovr with your own copy of easy_install</em></p>

<p>You can use homebrew to install python. Do so with:</p>

<p><code>brew install python</code></p>

<p>Then you will need easy_install (or the distribute tools)</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>curl -O http://peak.telecommunity.com/dist/ez_setup.py
</span><span class='line'>/usr/local/bin/python ez_setup.py</span></code></pre></td></tr></table></div></figure>


<p>You will then need to get gcovr.</p>

<p><code>/usr/local/share/python/easy_install gcovr</code></p>

<h2>Install and configure Jenkins</h2>

<p>Thanks to homebrew, the installation step is very easy. Just paste the following into the shell and it&#8217;ll install.</p>

<p><code>homebrew install jenkins</code></p>

<p>There are a couple of configuration steps that are required as well. Thanks to <a href="http://mattonrails.wordpress.com/2011/06/08/jenkins-homebrew-mac-daemo/">http://mattonrails.wordpress.com/2011/06/08/jenkins-homebrew-mac-daemo/</a> for the configuration required.</p>

<h3>Create a service account</h3>

<p>First of all find an ID that is free on your system. <code>dscl . -search /Users uid 600</code> searches for users with ID 600, and <code>dscl . -search /Groups gid 600</code> looks for groups with ID 600. Change the number until you find an empty ID. Then (with appropriate ID changes)&#8230;</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>sudo mkdir /var/jenkins
</span><span class='line'>sudo /usr/sbin/dseditgroup -o create -r 'Jenkins CI Group' -i 600 _jenkins
</span><span class='line'>sudo dscl . -append /Groups/_jenkins passwd "*"
</span><span class='line'>sudo dscl . -create /Users/_jenkins
</span><span class='line'>sudo dscl . -append /Users/_jenkins RecordName jenkins
</span><span class='line'>sudo dscl . -append /Users/_jenkins RealName "Jenkins CI Server"
</span><span class='line'>sudo dscl . -append /Users/_jenkins uid 600
</span><span class='line'>sudo dscl . -append /Users/_jenkins gid 600
</span><span class='line'>sudo dscl . -append /Users/_jenkins shell /usr/bin/false
</span><span class='line'>sudo dscl . -append /Users/_jenkins home /var/jenkins
</span><span class='line'>sudo dscl . -append /Users/_jenkins passwd "*"
</span><span class='line'>sudo dscl . -append /Groups/_jenkins GroupMembership _jenkins
</span><span class='line'>sudo chown -R jenkins /var/jenkins</span></code></pre></td></tr></table></div></figure>


<h3>Starting up Jenkins</h3>

<p>Create a file at <code>/Library/LaunchDaemons/org.jenkins-ci.plist</code> with the following contents (check the version number in directory for Jenkins!). This will ensure Jenkins starts when the system boots.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
</span><span class='line'>&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
</span><span class='line'>&lt;plist version="1.0"&gt;
</span><span class='line'>&lt;dict&gt;
</span><span class='line'>    &lt;key&gt;Label&lt;/key&gt;
</span><span class='line'>    &lt;string&gt;Jenkins&lt;/string&gt;
</span><span class='line'>    &lt;key&gt;ProgramArguments&lt;/key&gt;
</span><span class='line'>    &lt;array&gt;
</span><span class='line'>    &lt;string&gt;/usr/bin/java&lt;/string&gt;
</span><span class='line'>    &lt;string&gt;-jar&lt;/string&gt;
</span><span class='line'>    &lt;string&gt;/usr/local/Cellar/jenkins/1.428/lib/jenkins.war&lt;/string&gt;
</span><span class='line'>    &lt;/array&gt;
</span><span class='line'>    &lt;key&gt;OnDemand&lt;/key&gt;
</span><span class='line'>    &lt;false/&gt;
</span><span class='line'>    &lt;key&gt;RunAtLoad&lt;/key&gt;
</span><span class='line'>    &lt;true/&gt;
</span><span class='line'>    &lt;key&gt;UserName&lt;/key&gt;
</span><span class='line'>    &lt;string&gt;jenkins&lt;/string&gt;
</span><span class='line'>&lt;/dict&gt;
</span><span class='line'>&lt;/plist&gt;</span></code></pre></td></tr></table></div></figure>


<p>and load it with <code>sudo launchctl load /Library/LaunchDaemons/org.jenkins-ci.plist</code></p>

<p>At this point, Jenkins should be installed and running. Head to <a href="http://localhost:8080">http://localhost:8080</a> and it should be running.</p>

<h3>Configuring Jenkins</h3>

<p>In the Jenkins menu, click on Manage Jenkins, Manage Plugins, and then Available. Install the following plugins and make sure the &#8220;Restart Jenkins when installation is complete and no jobs are running&#8221; checkbox (on the screen after the &#8220;Install&#8221; button) is checked.</p>

<ul>
<li>Jenkins Cobertura Plugin - <em>for code coverage report processing</em></li>
<li>Jenkins GIT plugin - <em>for integration with git</em></li>
<li>Xcode Integration - <em>for execution and understanding of Xcode files</em></li>
</ul>


<p>Install the github plugins if your project is on github. I won&#8217;t be covering configuration of this here, but it should be relatively simple.</p>

<p>Once these are installed and Jenkins has restarted, you&#8217;ll need to configure the plugins. In the Jenkins menu, click on Manage Jenkins, Configure System and fill in the parameters for your git installation(s) and Xcode Builder paths.  Click Save and we&#8217;re ready to go.</p>

<h2>Configure your Xcode project</h2>

<p>We&#8217;re going to take a little departure from Jenkins for the moment to prep Xcode for integration. We are going to setup our project for unit tests and Frank.</p>

<h3>Unit Tests</h3>

<p>If you don&#8217;t have one already, you&#8217;ll need to set up a new target for Unit Tests in your Xcode project. Select your top level project in the in Project Navigator, and then &#8220;Add Target&#8221;. Under iOS -> Other choose the &#8220;Cocoa Touch Unit Testing Bundle&#8221;. Give it a name and then write some tests.</p>

<p>The other thing we&#8217;ll need to do here is set up Code Coverage. In the Build Phases area of your new Target, under Link Binary With Libraries, hit the + and select Add Other. Then navigate to <code>/Developer/usr/lib</code> and select <code>libprofile_rt.dylib</code>. This is the library that enables the profiling goodness. After this, select the Build Settings area, and set &#8220;Generate Test Coverage Files&#8221; and &#8220;Instrument Program Flow&#8221; both to Yes in the column for your Unit Test target. Ensure that &#8220;Library Search Paths&#8221; includes <code>$(DEVELOPER_DIR)/usr/lib</code>, but this should be there already.</p>

<p>You should be set up for code coverage now. If you want to check this is working, ensure your build target (up the top on the right on the Run &amp; Stop buttons) is set to your Unit Test target and iPhone Simulator, then build and test your unit test target. Then, open Organizer, choose the Projects item from the toolbar, select your project, and then click the little arrow next to the Derived Data directory. This will open the build location in Finder. In here, open the selected directory, then navigate to <code>Build/Intermediates/&lt;Your Project&gt;.build/Debug-iphonesimulator/&lt;Your Unit Test Target&gt;.build/Objects-normal/i386/</code> and in there there should be a set of <code>.gcno</code> (generated at build) and <code>.gcda</code> (generated when your test target executed and finished) files. These are the code coverage files. If you&#8217;d like to have a look at them before we integrate back into Jenkins, get <a href="http://code.google.com/p/coverstory/">CoverStory</a> and open them up.</p>

<h3>Application (UI) Tests with Frank</h3>

<p>Now we&#8217;ll set up the application test target with <a href="https://github.com/moredip/Frank">Frank</a>. First of all, we need to install Frank and cucumber.</p>

<p>We will need to use a customised version of Frank to enable the iOS Simulator to exit after execution of the tests. The standard build does not include a method to terminate an application so we&#8217;ll need to build this in. Thanks to Martin Hauner at <a href="http://softnoise.wordpress.com/2010/11/14/ios-running-cucumberfrank-with-code-coverage-in-hudson/">http://softnoise.wordpress.com/2010/11/14/ios-running-cucumberfrank-with-code-coverage-in-hudson/</a> for the tip on this. I&#8217;ve forked frank and included this exit method, and you can get it from <a href="https://github.com/rickerbh/Frank/tree/exitCommand">https://github.com/rickerbh/Frank/tree/exitCommand</a> with the command <code>git clone git@github.com:rickerbh/Frank.git</code> and then switch to the exitCommand branch. You&#8217;ll also need to <code>git submodule init</code> and <code>git submodule update</code>, and then check the submodules that are pulled in as I recall the submodules have submodules :-/</p>

<p>Once all that is done, you&#8217;ll need to be in the root directory of Frank that you cloned, and compile my branch of Frank with the following command.</p>

<p><code>rake build_lib</code></p>

<p>After this is finished, there should be a file at <code>dist/libFrank.a</code>. This is the customised library that we&#8217;ll need to use with the exit command built in.</p>

<p>(Full Frank installation instructions available at <a href="http://www.testingwithfrank.com/installing.html">http://www.testingwithfrank.com/installing.html</a> - I&#8217;ll paraphrase here with a couple of sightly different steps for the custom library and code coverage inclusion) For convenience of installation, I actually installed the proper Frank gem rather than my customised build. You can do this with <code>gem install frank-cucumber</code>. Then, <code>cd</code> to your project directory, and run <code>frank-skeleton</code>. This installs Frank in your project directory. It also copies a version of the official <code>libFrank.a</code> file into <code>Frank/</code>. You&#8217;ll need to replace that with the version that we built.</p>

<p>To add Frank to your Xcode project, you&#8217;ll need a new target (you don&#8217;t want the Frank server installed in the Release version of your application). Duplicate your main application target by right clicking on it and selecting Duplicate. Rename the new target &#8220;&lt;Your app name> Frankified&#8221;. Then, add the Frank directory (that was created when you ran <code>frank-skeleton</code>) to your Xcode project. Ensure that it&#8217;s only added to your frankified target, not your main application target. Add <code>CFNetwork.framework</code> to the Frankified &#8220;Link Binary With Libraries&#8221; section of the Build Phases. Then, add <code>-all_load</code> and <code>-ObjC</code> to the &#8220;Other Linker Flags&#8221; Build Setting.</p>

<p>To enable code coverage for Frank,  add <code>--coverage</code> to the &#8220;Other Linker Flags&#8221; Build Setting, and set &#8220;Generate Test Coverage Files&#8221; and &#8220;Instrument Program Flow&#8221; both to Yes in the column for your Frankified target.</p>

<p>If you build and run the Frankified target for the iPhone simulator of your application, it should build OK and start the simulator. Head to <a href="http://localhost:37265"> http://localhost:37265</a> and you should see the Symbiote browser of your iPhone application.</p>

<p>If you want to see if the coverage is working, head to <code>Build/Intermediates/&lt;Your Project&gt;.build/Debug-iphonesimulator/&lt;Your Frankified Target&gt;.build/Objects-normal/i386/</code> just like with the Unit Tests area above.</p>

<p>You should then write some tests in cucumber and make sure they work.</p>

<h4>Troubleshooting Frank and Code Coverage</h4>

<p>I had a lot of trial and error (mostly <em>error</em> actually) getting coverage working with Frank. I had to play a bit with the &#8220;Library Search Paths&#8221; Build Setting so it could find the correct coverage library to include. I have <code>$(Developer)/Platforms/iPhoneOS.platform/Developer/usr/lib</code> added in the setting, but can&#8217;t recall if this is required or not - apologies for this.</p>

<p>If you are getting the <code>.gcno</code> created but not the <code>.gcda</code> files, it could be an issue of your application not exiting correctly when the simulator terminates (as the <code>.gcda</code> files are only written when the application terminates). If this is the case, head into the Info area for your Frankified build target. Add/Set the &#8220;Application does not run in background&#8221; property to the application, and set it to YES. This will ensure the app terminates when the home button is pressed, and the <code>.gcda</code> files are created.</p>

<p>I also had an issue when the application was attempting to write the <code>.gcda</code> files. It was complaining that <code>fopen$UNIX2003 called from function llvm_gcda_start_file</code>. I found <a href="http://stackoverflow.com/questions/8732393/code-coverage-with-xcode-4-2-missing-files">this entry in stackoverflow</a> and created the c methods in my main.m file and it enabled the application to write the files correctly.</p>

<p>You may also need to enable the Accessibility inspector in the iPhone Simulators Settings app under General > Accessibility - instructions from <a href="http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/iPhoneAccessibility/Testing_Accessibility/Testing_Accessibility.html">Apple</a>.</p>

<p>If you are getting a message that says <code>Couldn't register XXXX with the bootstrap server. Error: unknown error code. This generally means that another instance of this process was already running or is hung in the debugger.</code> this means that either the Simulator is already running (it must be quit for the headless build to run) or that there is a previous version of the headless test exection that has hung. You can find these with <code>ps -ef | grep Fran</code> (Fran for frankified). Kill them with the <code>kill</code> command.</p>

<h3>Configuring Frank for Headless Tests under Jenkins</h3>

<p>There will be a file in your Xcode project under the Frank directory at <code>support/env.rb</code> - this will contain some environmental settings that are used for executing the cucumber tests. Replace the content with the below with the appropriate text replacements. You will need different settings for manual command line based test execution, and the Jenkins based tests, so there is an environment based conditional in the file. Default is for command line based testing.</p>

<p><em>For the replacement text for </em><Your UI Testing Jenkins Job Name><em>, just type in what you&#8217;ll call your Jenkins UI test job, and remember this for later.</em></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>require 'frank-cucumber'
</span><span class='line'>
</span><span class='line'>ENV['TESTING_ENV'] ||= 'command_line'
</span><span class='line'>environment = ENV['TESTING_ENV']
</span><span class='line'>
</span><span class='line'>if environment == 'command_line'
</span><span class='line'> BASE_DIR = "&lt;Your home directory&gt;/Library/Developer/Xcode/DerivedData/&lt;Your long and random derived data dir from Xcodes project organizer&gt;/"
</span><span class='line'> APP_BUNDLE_PATH =  "#{BASE_DIR}Build/Products/Debug-iphonesimulator/&lt;Your frankified target&gt;.app"
</span><span class='line'> APP_DIR = "#{BASE_DIR}Build/Intermediates/&lt;Your project name&gt;.build/Debug-iphonesimulator/&lt;Your frankified target&gt;.build"
</span><span class='line'>elsif environment == 'jenkins'
</span><span class='line'> BASE_DIR = "&lt;Your Jenkins install location&gt;/jobs/&lt;Your UI Testing Jenkins Job Name&gt;/workspace/"
</span><span class='line'> APP_BUNDLE_PATH =  "#{BASE_DIR}build/Debug-iphonesimulator/&lt;Your frankified target&gt;.app"
</span><span class='line'> APP_DIR = "#{BASE_DIR}build/&lt;Your project name&gt;.build/Debug-iphonesimulator/&lt;Your frankified target&gt;.build"
</span><span class='line'>end
</span><span class='line'>
</span><span class='line'>#### Common ####
</span><span class='line'>SDK_DIR = "/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk"
</span><span class='line'>APP_BINARY = "#{APP_BUNDLE_PATH}/&lt;Your frankified target&gt;"
</span><span class='line'>USER_DIR = "iPhone Simulator/User"
</span><span class='line'>PREF_DIR = "#{USER_DIR}/Library/Preferences"</span></code></pre></td></tr></table></div></figure>


<p>In your Xcode project under the Frank directory, there will be another directory named <code>step_definitions</code>. This should contain a .rb file that has some ruby and cucumber/frank definitions it it. We need to add a couple of things to that file. <em>Again thanks to <a href="http://softnoise.wordpress.com/2010/11/14/ios-running-cucumberfrank-with-code-coverage-in-hudson">Martin Hauner</a> here.</em></p>

<p>Add the following lines to the top of the ruby file in the step_definitions directory. I&#8217;ll explain what these are&#8230;</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>require 'fileutils'
</span><span class='line'>
</span><span class='line'>ACCESIBILITY_PLIST   = "com.apple.Accessibility.plist"
</span><span class='line'>ACCESIBILITY_CONTENT = &lt;&lt;PLIST
</span><span class='line'>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
</span><span class='line'>&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
</span><span class='line'>&lt;plist version="1.0"&gt;
</span><span class='line'>&lt;dict&gt;
</span><span class='line'>&lt;key&gt;ApplicationAccessibilityEnabled&lt;/key&gt;
</span><span class='line'>&lt;true/&gt;
</span><span class='line'>&lt;/dict&gt;
</span><span class='line'>&lt;/plist&gt;
</span><span class='line'>PLIST
</span><span class='line'>
</span><span class='line'>Before do
</span><span class='line'>  # check that pwd contains the "build" dir as we are creating
</span><span class='line'>  # items relative to it.
</span><span class='line'>  #Dir["build"].length.should == 1
</span><span class='line'>  
</span><span class='line'>  # make sure we do start with a clean environment
</span><span class='line'>  FileUtils.remove_dir("#{USER_DIR}",true)
</span><span class='line'>  
</span><span class='line'>  pwd     = "#{Dir.pwd}"
</span><span class='line'>  prefdir = "#{PREF_DIR}"
</span><span class='line'>  FileUtils.mkdir_p prefdir
</span><span class='line'>  
</span><span class='line'>  File.open("#{PREF_DIR}/#{ACCESIBILITY_PLIST}", 'w') do |f|
</span><span class='line'>    f &lt;&lt;ACCESIBILITY_CONTENT
</span><span class='line'>  end
</span><span class='line'>  
</span><span class='line'>  ENV['SDKROOT']               = "#{SDK_DIR}"
</span><span class='line'>  ENV['DYLD_ROOT_PATH']        = "#{SDK_DIR}"
</span><span class='line'>  ENV['IPHONE_SIMULATOR_ROOT'] = "#{SDK_DIR}"
</span><span class='line'>  ENV['TEMP_FILES_DIR']        = "#{APP_DIR}"
</span><span class='line'>  ENV['CFFIXED_USER_HOME']     = "#{pwd}/#{USER_DIR}"
</span><span class='line'>end
</span><span class='line'>
</span><span class='line'>After do
</span><span class='line'>  frankly_exit
</span><span class='line'>end
</span><span class='line'>
</span><span class='line'>def launch_app_headless
</span><span class='line'>  @apppid = fork do
</span><span class='line'>    exec(APP_BINARY, "-RegisterForSystemEvents")
</span><span class='line'>  end
</span><span class='line'>  wait_for_frank_to_come_up
</span><span class='line'>end
</span><span class='line'>
</span><span class='line'>def frankly_exit
</span><span class='line'>  get_to_uispec_server('exit')
</span><span class='line'>  # calling exit in the app will not return any response
</span><span class='line'>  # so we simply catch the error caused by exiting.
</span><span class='line'>  rescue EOFError
</span><span class='line'>end
</span><span class='line'>
</span><span class='line'>Given /^I launch the headless app$/ do
</span><span class='line'>  launch_app_headless
</span><span class='line'>end</span></code></pre></td></tr></table></div></figure>


<p>The <code>Before</code> block gets executed before any tests are run. The accessibility plist/content section sets up a file that enables the accessibility settings for the simulator. This is created every time the cucumber tests are run to ensure accessibility is in the correct state. The <code>SDKROOT</code>, <code>DYLD_ROOT_PATH</code>, <code>IPHONE_SIMULATOR_ROOT</code>, <code>TEMP_FILES_DIR</code>, and <code>CFFIXED_USER_HOME</code> are all directories for the simulator to function correctly. Thanks to <a href="http://cocoawithlove.com/2008/11/automated-user-interface-testing-on.html">Matt Gallagher&#8217;s blog entry</a> for aiding my understanding of these.</p>

<p>The <code>launch_app_headless</code> method adds a flag when launching the application so it launches headlessly. If you wanted, you could actually add a conditional so that the headless method is only used when launching under jenkins.</p>

<p>The <code>frankly_exit</code> method will call the new exit method that we built into <code>libFrank.a</code>. This is called from the <code>After</code> block, which gets called after the tests are executed.</p>

<p>That should be all the configuration you need. If you alter your frank/cucumber tests to use the &#8220;Given I launch the headless app&#8221; call to start the application, you should now be able to run it in a headless manner. Execute <code>cucumber</code> in your Frank directory inside your Xcode project dir to test it out.</p>

<h2>Setting up the jobs in Jenkins</h2>

<p>The way I have structured my tasks in jenkins is that I have 4 different jobs. I have a unit test execution job that triggers off a git push. If this is successful, I have the UI test job that executes. If this is successful, I then package and archive the binary that was generated from that push. The last job that is configured is a daily distribution of the last successfully tested application to a group on TestFlight.</p>

<h3>Setting up the unit test job in Jenkins</h3>

<p>Navigate to <a href="http://localhost:8080">Jenkins</a> and click on &#8220;New Job&#8221;. Give it a name (I called mine &#8220;Project Unit Tests&#8221;), and select the &#8220;Build a free-style software project&#8221; radio button, then click OK.</p>

<p>You should now be in a screen to configure the build settings for your unit test target. In the source code management area, choose git. Enter your repo name (something like <code>git@localhost:my-project.git</code>). If you have a specific branch you want to build from put it in the &#8220;Branches to build&#8221; box (mine is <code>*/develop</code>). In the &#8220;Build Triggers&#8221; area below, select &#8220;Poll SCM&#8221;. I&#8217;ve set my schedule to <code>* * * * *</code> meaning it&#8217;ll look every minute for a new push.</p>

<p>Navigate down the screen until you find the &#8220;Add build step&#8221; button. Click it and select Xcode. Then, fill in the following boxes.</p>

<ul>
<li>Clean before build - check this box. I like clean builds before testing.</li>
<li>Target - set this to the unit test target name from Xcode (no escaping of spaces required)</li>
<li>SDK - set this to the SDK you want to build for. Mine is <code>/Developer/Platform/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk/</code></li>
<li>Configuration - set this to <code>DEBUG</code></li>
<li>Keychain path - this should already be set to <code>${HOME}/Library/Keychains/login.keychain</code></li>
</ul>


<p>That&#8217;s all the Xcode build information set up. Now, to generate the coverage test files. Add an &#8220;Execute Shell&#8221; build step with the &#8220;Add build step&#8221; button. In the &#8220;Command&#8221; box, call gcovr (<code>which gcovr</code> to find your own install location) with <code>/usr/local/share/python/gcovr -r "&lt;Your Jenkins install location&gt;/jobs/Project Unit Tests/workspace" --exclude '.*UnitTests.*' --xml &gt; "&lt;Your Jenkins install location&gt;/jobs/Project Unit Tests/workspace/coverage.xml"</code></p>

<p>In the Post-build Actions section, check the &#8220;Archive the artifacts&#8221; box and set the &#8220;Files to archive&#8221; field to <code>build/Debug-iphoneos/*.ipa</code></p>

<p>Check the &#8220;Publish Cobertura Coverage Report&#8221; box and set the &#8220;Cobertura xml report pattern&#8221; to <code>**/coverage.xml</code>.</p>

<p>Also check the &#8220;Publish JUnit test result report&#8221; box and set the &#8220;Test report XMLs&#8221; to <code>test-reports/*.xml</code>.</p>

<p>Click the Save button down the bottom, and then attempt to run your unit tests manually. The code should be checked out from your git repo, build the unit test target, run the tests and produce the unit test reports and coverage results.</p>

<h3>Setting up the application test job in Jenkins</h3>

<p>Navigate to <a href="http://localhost:8080">Jenkins</a> and click on &#8220;New Job&#8221;. Give it a name (I called mine &#8220;Project UI Tests&#8221;), and select the radio button to copy the unit test job that was previously set up. In the Configuration screen for the new job, alter the following fields.</p>

<ul>
<li>Build Triggers - set this to be &#8220;Build after other projects are built&#8221; and type in the name of your unit test job.</li>
<li>Build Triggers - uncheck poll scm</li>
<li>Target - Set this to your Frankified target name from Xcode</li>
</ul>


<p>Change the existing &#8220;Execute shell&#8221; step to use your UI Test build job name rather than the unit test job name. <code>/usr/local/share/python/gcovr -r "&lt;Your Jenkins install location&gt;/jobs/Project UI Tests/workspace" --exclude '.*UnitTests.*' --xml &gt; "&lt;Your Jenkins install location&gt;/jobs/Project UI Tests/workspace/coverage.xml"</code></p>

<p>Create a new &#8220;Execute shell build step&#8221;, and click and drag it (with the little 4x4 set of boxes on the right of the &#8220;Execute shell&#8221; label on screen) to move it inbetween the Xcode step and the gcovr step. Insert the following commands in the shell box.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>source &lt;Your home dir&gt;/.rvm/environments/&lt;your ruby version&gt;
</span><span class='line'>export TESTING_ENV="jenkins"
</span><span class='line'>cd "&lt;Your Jenkins install location&gt;/jobs/Project UI Tests/workspace/Frank"
</span><span class='line'>cucumber -f junit --out ../test-reports</span></code></pre></td></tr></table></div></figure>


<p><em>The source line sets up the environment for rvm so the frank gem is included correctly - set it to the appropriate ruby version in the ~/.rvm/environments directory. Mine is ~/.rvm/environments/ruby-1.9.2-p290</em></p>

<p>Uncheck the &#8220;Archive the artifacts&#8221; option, and click save. You can now attempt to run your application tests via Frank. This will check out the code, build the Frankified target, execute the tests and then process the unit test and coverage reports.</p>

<p><em>FYI - my unit test reports for this step are empty. If someone figures out how to get cucumber to put something useful in them please let me know!</em></p>

<h3>Setting up the archive job</h3>

<p>Similar to the application test job, create a new job that copies the Unit Test job. I called mine Project Developer Build. In the Configuration screen for the new job, alter the following fields.</p>

<ul>
<li>Build Triggers - set this to be &#8220;Build after other projects are built&#8221; and type in the name of your application/UI test job.</li>
<li>Build Triggers - uncheck poll scm</li>
<li>Target - Set this to your application target name from Xcode (mine is Project TestFlight - I have a specific target that includes the TestFlight SDK)</li>
<li>Configuration - I have this set to release. Be sure to setup and test the signing identities correctly in Xcode for this. You must use the adhoc profile that should be used in TestFlight.</li>
<li>Build IPA - check this.</li>
</ul>


<p>Remove the execute shell build step with the Delete button.</p>

<p>Uncheck the Cobertura and Unit test report generation Post-build actions. Change the Archive files location to <code>build/Release-iphoneos/*.ipa</code></p>

<p>Click save, and now whenever both your unit and application test steps pass, you&#8217;ll have a version of the application built and archived ready to go to TestFlight.</p>

<h3>Distributing to TestFlight</h3>

<p><em>Thanks to the Shine Technologies team for their <a href="http://blog.shinetech.com/2011/06/23/ci-with-jenkins-for-ios-apps-build-distribution-via-testflightapp-tutorial/">blog entry</a> that helped here.</em></p>

<p>Create another free-style software project job (last one, I promise!) in Jenkins - I&#8217;ve called mine Project TestFlight Deployment. Set the build triggers to &#8220;Build periodically&#8221; and set the schedule to whatever time you want to upload the application to TestFlight. Mine is set to 10pm (<code>0 22 * * *</code>).</p>

<p>Add an Execute shell build step. This will call curl to upload the application to TestFlight. You will need your API token and Team token from Testflight. Set the Command to the following</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>cd ../..
</span><span class='line'>curl http://testflightapp.com/api/builds.json -F file=@Project\ TestFlight/lastSuccessful/archive/build/Release-iphoneos/Project\ TestFlight-Release.ipa -F api_token=’&lt;api token&gt;’ -F team_token=’&lt;team token&gt;’ -F notes=’This is an auto deploy build of the develop branch with Release configuration’ -F notify=True -F distribution_lists=’&lt;name of test distribution list&gt;’</span></code></pre></td></tr></table></div></figure>


<p>The ipa that&#8217;s being uploaded there is the version that was saved in the last build job. For the name, just look inside the Project TestFlight job and it&#8217;ll have the name of the &#8220;Last Successful Artifact&#8221; - this is what you need to upload.</p>

<p>That should be it.</p>

<h2>End - finally</h2>

<p>If you experience issues with this, have corrections or useful troubleshooting steps then please let me know. This process was a bit of a pain to get working correctly so I hope this guide is useful for someone. You should also <a href="http://twitter.com/rickerbh">follow me</a> on twitter <a href="http://twitter.com/rickerbh">@rickerbh</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[On hold...temporarily]]></title>
    <link href="http://hamishrickerby.com/2012/01/19/on-hold-dot-dot-dot-temporarily/"/>
    <updated>2012-01-19T17:15:00+11:00</updated>
    <id>http://hamishrickerby.com/2012/01/19/on-hold-dot-dot-dot-temporarily</id>
    <content type="html"><![CDATA[<p>I had some great news last week. A previous client asked me to submit a quote for the full version of a prototype iOS app I had created for him last year. I submitted the proposal, but had assumed he was using it to benchmark other application development companies against. To my surprise, he accepted my proposal, and awarded me the work. It&#8217;s a substantial piece of work, and technically quite challenging. It also has the potential to be a big innovation on the space it&#8217;s in, so is exciting from that aspect too.</p>

<p>So, I accepted. The issue for me is that this puts my other project on hold for a few months. However, income is good, and this will let me work for longer on my project after I&#8217;m done, so it&#8217;s a positive move.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[User Experience Books]]></title>
    <link href="http://hamishrickerby.com/2011/12/29/user-experience-books/"/>
    <updated>2011-12-29T16:44:00+11:00</updated>
    <id>http://hamishrickerby.com/2011/12/29/user-experience-books</id>
    <content type="html"><![CDATA[<p>As I alluded to in a <a href="http://hamishrickerby.com/2011/10/24/work-plans/">previous post</a>, things like User Experience, Human Computer Interaction, and Graphic Design are not my fortes. All my professional software experience until I started iOS development was either in developing (~2 years) or designing/architecting (9+ years) large scale telecommunications software systems (specifically <a href="http://en.wikipedia.org/wiki/Business_support_system">BSS</a> and <a href="http://en.wikipedia.org/wiki/Operations_support_system">OSS</a> systems if you&#8217;re interested). These sorts of systems do not have pretty user interfaces - there is no need to provide them. In fact, the majority of systems I have designed only have human interactions with back-office operators who are Unix system administrators - the main &#8220;user&#8221; of the system would typically be another system.</p>

<p>The users of my new software will be proper &#8220;end-users&#8221;. People who do not use computers for a job. People who are unsure, or even wary about computers for fear of breaking them. People who do not know commands like <code>kill -9</code> when something isn&#8217;t working, or even how to drive a CLI.</p>

<p>It would be delinquent of me to not take some advice from well respected professionals in this space. So, I read some books. (<em>I will take some advice from actual people later, but as a first step I think education is always a good step.</em>)</p>

<h2>Designing Interactions by Bill Moggridge</h2>

<p><a href="http://www.amazon.co.uk/gp/product/0262134748?ie=UTF8&amp;tag=hamishrickerb-21&amp;linkCode=shr&amp;camp=3194&amp;creative=21330&amp;creativeASIN=0262134748&amp;ref_=sr_1_1&amp;qid=1325142051&amp;sr=8-1">Amazon UK</a>, <a href="http://www.amazon.com/gp/product/0262134748/ref=as_li_tf_tl?ie=UTF8&amp;tag=hamricsblo-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0262134748">Amazon US</a></p>

<p>I actually got this book expecting it to have practical advice on how to design software products, and was (pleasantly) surprised when it didn&#8217;t. It&#8217;s a collection of interviews (and then analysis and commentary on the interviews) with a set of influential product designers. There is a strong bias towards IDEO, but I guess that&#8217;s to do with the authors familiarity with the organisation. The book gives insight into the interaction design processes used to create some very popular products, as well as covering some things that haven&#8217;t worked. It gives you a good idea of how the designers <em>think</em> about problems - which is great to understand as an outsider to this world.</p>

<p>The two parts of this book that stick with me are Terry Winograd&#8217;s discussion on Mark Weiser&#8217;s <em>ubiquitous computing</em> - the idea that people don&#8217;t want to interact with computers - they want to get something done. The computer is an instrument to be used to get something done - the purpose is not to interact with the computer, but to achieve a goal. The other part was John Maeda&#8217;s Laws of Simplicity. These eight laws are about making complex systems simpler for users, either by relating functions, using knowledge that users already have, and recognising when materials (technology in my case) is inappropriate for a task, either by it being too hard to use, or breaking &#8220;laws&#8221;.</p>

<h2>TOG on Interface by Bruce &#8220;TOG&#8221; Tognazzini</h2>

<p><a href="http://www.amazon.co.uk/gp/product/0201608421?ie=UTF8&amp;tag=hamishrickerb-21&amp;linkCode=shr&amp;camp=3194&amp;creative=21330&amp;creativeASIN=0201608421&amp;ref_=sr_1_1&amp;qid=1325143254&amp;sr=8-1">Amazon UK</a>, <a href="http://www.amazon.com/gp/product/0201608421/ref=as_li_tf_tl?ie=UTF8&amp;tag=hamricsblo-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0201608421">Amazon US</a></p>

<p>I got this book because of the Apple Macintosh legacy the author has. Bruce Tognazzini developed the first set of Human Interface Guidelines for Apple in the late 70&#8217;s, and was involved with the Macintosh UI which still has a significant influence on the modern interface we use on OSX. The book is a collection of his writing for the Apple Direct publication as well as other text gathered or produced for this book. The book was written in 1992 (updated in 1996 - 15 years ago!) but remains relevant. The principles are as relevant today as they were way back in the 90&#8217;s.</p>

<p>Three things made this book useful to me. The first are all Bruce&#8217;s Principles and Guidelines (which are outstanding) and the collection of them in the appendix. This gives you an overview (and shortcut to relevant places in the book) for each item he discusses in the book. The second is (and this may sound odd given I&#8217;ve used a mac now for 5 years) he describes what the ellipsis means in a Mac menu or on some buttons. I remember seeing it, but I never thought about why it is there. It means that a window or pane will pop up asking for more information before the action you have requested will be executed. This is all about letting users know they can experiment with the system and be assured they can get out again without making any changes. This was a little UI thing I just hadn&#8217;t consciously grasped the meaning of, and it&#8217;s just nice to understand why it&#8217;s there and what it means. The third thing was the in-depth discussion about the Conceptual Model a user generates when they interact with a system. This was like a lightbulb going off for me. This is such a fundamental part of any system and user interface design. It&#8217;s obvious it happens (users have a view of what systems do, which may or may not be correct), and designers need to cater for this - exposing elements to users that influence that conceptual model, to make it easier for users to understand and interact with the system. I&#8217;ve got a lot of thoughts on this so may write another entry on it.</p>

<p>Anyway, I would definitely recommend both books to anyone involved with software product design - I&#8217;m not sure how much new information there will be for experienced UE practitioners, but I&#8217;m sure there are some useful nuggets in both for all.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Sandboxing]]></title>
    <link href="http://hamishrickerby.com/2011/12/22/sandboxing/"/>
    <updated>2011-12-22T15:20:00+11:00</updated>
    <id>http://hamishrickerby.com/2011/12/22/sandboxing</id>
    <content type="html"><![CDATA[<p>Since the last post and this one, we&#8217;ve moved 10500 miles (that&#8217;s nearly 17,000 kilometres!) and only yesterday got all our utilities sorted out, meaning that I&#8217;ve basically been offline (bar mobile phone for the past 3 weeks). Melbourne is fantastic. I really like it here.</p>

<p>Anyway, I&#8217;ve been doing a little bit of work on my application, mostly completion of the requirements, data model, and competitor analysis, as well as reading up a bit on UX and Mac way of doing things (I&#8217;ll probably cover this in another entry), and most recently have been prototyping some code that I thought would be particularly tricky.</p>

<p>What this code does is synchronise data across other applications on your mac, with my (intended) application. The reason behind this was to make the act of populating my application with data, and keeping the data fresh over time, simpler for users - or as John Maeda states in his Second Law of Simplicity:</p>

<blockquote><p>The positive emotional response derived from a simplicity experience has less to do with utility, and more to do with saving time.</p></blockquote>

<p>I&#8217;m into saving time for my (future) happy users, and reusing data that is already on their Mac helps with this - they don&#8217;t need to double key or manually join-the-dots between the applications.</p>

<p>The prototyping I was creating was using ScriptingBridge to access data that&#8217;s available in other applications that a user may use. The prototype was going well - I had managed to get some queries and filtering down from 5 minutes to 90 seconds to 6 seconds which was a nice level optimisation, and although there are some issues with ScriptingBridge, it was going to let me do what I wanted to do.</p>

<p>One of the key things with the distribution of this application for me is to have it in the Mac App Store. New mac users are a growth market (look <a href="http://mashable.com/2011/09/12/apple-set-to-break-record-for-mac-sales-this-fall-report/">at</a> <a href="http://www.appleinsider.com/articles/11/11/14/apple_on_pace_to_sell_record_5_3m_macs_in_holiday_quarter.html">the</a> <a href="http://www.appleinsider.com/articles/11/12/12/quarterly_us_mac_sales_up_13_expected_to_grow_in_december.html">stats</a>), and Apple is pushing them down the Mac App Store route to discover and purchase applications. Not having the app in the Mac App Store would be foolish from my perspective.</p>

<p>Today, I was seeing how I could get the application working under sandboxing - as this is now a requirement for new Mac Apps. It&#8217;s all about making applications safer for users in terms of the resources they can use in terms of network, disk access etc (<em>although some <a href="http://blog.wilshipley.com/2011/11/real-security-in-mac-os-x-requires.html">prominent developers</a> aren&#8217;t convinced</em>).</p>

<p>I was sad to discover that ScriptingBridge is precisely one of the technologies that is hit hard by the sandboxing. Basically, applications can receive AppleEvents, send AppleEvents to themselves, and respond to AppleEvents they receive (<a href="http://developer.apple.com/library/mac/#documentation/Miscellaneous/Reference/EntitlementKeyReference/AppSandboxTemporaryExceptionEntitlements/AppSandboxTemporaryExceptionEntitlements.html#//apple_ref/doc/uid/TP40011195-CH5-SW1">source</a>). The upshot of this is that AppleEvents are pretty useless in a environment of sandboxed applications, as you can only send them to yourself (and no-one else can send them to you).</p>

<p>There may be a way around this - Temporary Exceptions to the AppleEvent sending issue. You can obtain a temporary exception to send AppleEvents to other applications through the <code>com.apple.security.temporary-exception.apple-events</code> key-value pair in your Entitlements file. The main issues I see with this are:</p>

<ol>
<li>They are likely to attract more attention in the review cycle - this in general is a good thing as it&#8217;s important that Apple check what your application is doing to ensure that it&#8217;s being a good citizen. However, this is likely to slow down the review process and I suspect guidance on what&#8217;s acceptable is not consistently applied.</li>
<li>They are <em>temporary</em> - Apple could disallow/reject them in the app updates, or just remove the function. The clue is in the name, people.</li>
<li>The intent behind the exception - I suspect that the intention behind the temporary exception is to allow pre-existing applications to migrate to a 100% compliant sandboxing world over time, not for new applications. Approval is at risk here, and I don&#8217;t want to sink significant effort into getting rock solid sync only to be told it&#8217;s not allowed.</li>
<li>The overall future of AppleEvents - this (in my mind) is a clear intention that AppleEvents will not have a strategic future at Apple, and that existing applications may drop support for them as no sandboxing compliant applications can actually use the functions. It seems to me risky to use a technology that seems to have a limited future.</li>
</ol>


<p>This leaves me with two options. I can either remove the synchronisation functionality from the application, or I can distribute it outside the Mac App Store. My wife actually suggested a third - do both. I think that&#8217;s what I&#8217;ll do. Mac App Store is first priority, and depending on the markets response, I&#8217;ll look at options for data synchronisation.</p>

<p>Still, it&#8217;s a massive PITA.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[I'm on a list]]></title>
    <link href="http://hamishrickerby.com/2011/11/27/im-on-a-list/"/>
    <updated>2011-11-27T13:33:00+11:00</updated>
    <id>http://hamishrickerby.com/2011/11/27/im-on-a-list</id>
    <content type="html"><![CDATA[<p>Yesterday I attended <a href="http://www.onedotzero.com/">onedotzero</a> at the British Film Institute. I was invited by <a href="http://alphalabs.cc">alphalabs.cc</a> to their launch event, in conjunction with Microsoft and Nokia.</p>

<p>It was pitched as &#8220;an experiment that merges technology and the arts&#8221; - and this blend (to me at least) is intriguing. Since I discovered &#8220;creative coding&#8221; I have been fascinated by the experimental applications that fit in this space, so didn&#8217;t want to miss out on this event. <em>I have no idea how I got an invite&#8230; I wonder if it was because I&#8217;m a Nokia dev member, or because I have previously been active on the oF forums, or maybe I was just very lucky.</em></p>

<p>Some marketing and community/dev evangelist type people talked for a bit, and they weren&#8217;t over the top with pushing WP7.5 - which was good. There was a lot of talk about the lineage of the Metro design (that I found very interesting) - Metro is a relatively unique looking interface, and has some new ideas and interactions in it - so it was nice to hear how it was conceived.</p>

<p>Then, they pulled up 3 teams of developers and designers to talk about the applications they had made over the last two weeks - essentially showcasing the WP7.5 development environment (ease of use, speed, different technologies etc). This was the most interesting part for me. The applications were</p>

<ol>
<li>a music app that collaboratively generated music across 4 synchronised phones - <a href="http://www.alphalabs.cc/project/69-vequencer">Vequencer</a></li>
<li>a music video/game in which you take the form of a 3D shape and can shift gravity and change shapes to navigate through the levels - <a href="http://www.alphalabs.cc/project/70-redshift">Redshift</a></li>
<li>a kaleidoscope app merging video and generative art that changes based on environmental factors such as motion and sound - <a href="http://www.alphalabs.cc/project/68-kaleidobooth">Kaleidobooth</a></li>
</ol>


<p>The applications themselves were quite impressive, but what impressed me more is that the team that did the second app (<a href="http://www.field.io/">Field</a>, <a href="http://teamtreehouse.com/">Treehouse</a>, and <a href="http://xna-uk.net/blogs/braindump/default.aspx">Ed</a> from the XNA Users Group) had no experience with the WP7 <del>or XNA</del> development environments previously, and managed to create a 3D game in 2 weeks, with excellent graphics and sound. Very impressed.</p>

<p>And to top it all off, I got a free phone :-) Nokia Lumia 800 - it&#8217;s actually really nice. Screen is brilliant.</p>

<p>AND alphalabs are running a little competition too - app development - cash prizes. Doesn&#8217;t appear to be on their website yet, but I recall it closes in early Jan-2012.</p>

<hr />

<p>(Update 20111128 - Ed from XNA User Group was also part of team two - thanks for the update Tristan!)</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CASE and Requirements Management]]></title>
    <link href="http://hamishrickerby.com/2011/11/07/case-and-requirements-management/"/>
    <updated>2011-11-07T09:09:00+11:00</updated>
    <id>http://hamishrickerby.com/2011/11/07/case-and-requirements-management</id>
    <content type="html"><![CDATA[<p>I&#8217;ve started the feature &amp; function planning for my application - or really, I&#8217;ve started to identify the requirements for it. I&#8217;m starting by evaluating existing applications in the marketplace, considering the functions they support, the data they collect, and how the user navigates through the application. So far, I have about 300 screenshots from various applications,  strewn all over the floor of my office, and 4 coloured pens for me to mark up the screenshots. The colours refer to the following areas of requirements or commentary.</p>

<ol>
<li>Brick red - bad UI</li>
<li>Blue - data to collect</li>
<li>Green - good UI</li>
<li>Pink - application function, feature, or derived data</li>
</ol>


<p>The functions are further classified into &#8220;things that should be there for a first release&#8221; and &#8220;things that can wait until later&#8221;.</p>

<p>What I&#8217;m looking for now is a sensible way to capture and manage all this information. Carrying around 300 pages of screenshots is just silly. I could have electronically marked up the Keynote presentation rather than do this on paper, but I don&#8217;t see myself reusing the information if it&#8217;s stored in that format.</p>

<p>As part of a contract my company has right now, I&#8217;m using a <a href="http://en.wikipedia.org/wiki/Computer-aided_software_engineering">CASE</a> tool for a project with a client. The business analysts on this project are tracking all requirements, use cases and UI modules within a tool called Enterprise Architect by Sparx Systems. I&#8217;m currently leading the technical workstream and we are also using it to produce our technical application design. It seems like a very comprehensive tool, but it&#8217;s Windows only. I&#8217;d love for a tool like that to be native on the Mac.</p>

<p>Other CASE and UML tools I&#8217;ve used in the past are:</p>

<ul>
<li>Popkin System Architect (became Telelogic, then IBM and consumed into the Rational suite)</li>
<li>Rational Rose</li>
<li>ArgoUML</li>
<li>Troux Architect</li>
<li>Various Eclipse plugins</li>
</ul>


<p>The issue I have with all of these is that it seems they will be disconnected from the development workflow if you use a mac, or are working on a non-Java project. These tools are supposed to help with the development process, but I can&#8217;t see how that will work if they aren&#8217;t connected to it. Yes, I understand the value in the whole planning and design side, but the disconnect to development seems large. If I didn&#8217;t care about having the process connected, I&#8217;d just use OmniOutliner as I have in the past for other personal projects - it can track requirements, feature/release planning, data model elements etc. But because of the potential size of this application, I feel I should be using something more structured.</p>

<p>Maybe the project should change to creating a decent CASE tool for the Mac :-)</p>

<p>At the moment the plan is to use Enterprise Architect, and we&#8217;ll see how that goes. One good thing is that I can export data out of it if the process doesn&#8217;t work out, so there will be little wasted effort.</p>

<p>If anyone has used CASE tools on the mac for Objective-C based projects, I&#8217;d love to hear what was used, and how the experience was - good or bad.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[6 < 36]]></title>
    <link href="http://hamishrickerby.com/2011/10/28/6-%3C-36/"/>
    <updated>2011-10-28T17:18:00+11:00</updated>
    <id>http://hamishrickerby.com/2011/10/28/6-<-36</id>
    <content type="html"><![CDATA[<p><a href="http://jacquesmattheij.com/It+takes+three+years+to+build+a+business">Three years</a> eh? I&#8217;m planning 6 months.</p>

<p>I guess the key difference here is that I&#8217;m not planning on having any employees at 6 months. I don&#8217;t plan on being able to replace the lucrative contracting I&#8217;ve been doing either. In fact, I don&#8217;t really expect any sales at 6 months.</p>

<p>What I am aiming for is to have a software product that I believe has a future. If, 6 months in, I have something that I can start to sell and get feedback on, I&#8217;ll be a very happy man.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Start With the End in Mind]]></title>
    <link href="http://hamishrickerby.com/2011/10/27/start-with-the-end-in-mind/"/>
    <updated>2011-10-27T20:27:00+11:00</updated>
    <id>http://hamishrickerby.com/2011/10/27/start-with-the-end-in-mind</id>
    <content type="html"><![CDATA[<p>The product I&#8217;m going to make could be very large. There are loads of features it could support, but one of the first jobs I need to do is decide what it must do for a first release, that delivers value to customers. I&#8217;ve started getting in touch with small business people that I know to understand what they would value in such a product, but there are just so many diverse suggestions, even when I&#8217;ve given them initial scope for what I think the first release could do. I find myself thinking &#8220;that&#8217;s easy, that&#8217;ll only add a day or two&#8221; to certain features, but I&#8217;m fairly confident when it comes time to design these things, the duration and complexity will explode.</p>

<p>One thing that is common in pharmaceuticals (<a href="http://twitter.com/mrsrickerby">@mrsrickerby</a> works in that industry, so I have a little understanding of how things work there) is that a &#8220;Core Data Sheet&#8221; - aka a core product specification - is written before and during development and testing of the product . This document specifies <em>needs</em> and <em>wants</em> which at the end of each phase of development are used as the yardstick to make go/no-go decisions. For example, if you want to show a 5% improvement in some disease state but your phase 2 study doesn&#8217;t achieve this, you stop development. It is a living document which, as data is collected, the actual product profile is documented which ultimately becomes the package insert (the bit of paper in the box).</p>

<p>This made me think about how I can manage my scope. The main marketing materials for me will be (1) a web site and (2) the Mac App Store description. I figure that writing the app store description will be the most effortless way to describe the product, the problem it solves, and how it solves that problem for the customers. If I can&#8217;t write down the very simple things like what problem this solves, and how it does it, then I should stop right now.</p>

<p>I think this also aligns with something I read recently (<em>although I swear I&#8217;ve read this before months and months ago&#8230;</em>) from the world&#8217;s toughest programmer, <a href="http://twitter.com/bmf">Mike Lee</a>. <a href="http://www.readwriteweb.com/enterprise/2011/09/app-genius-mike-lee-talks-prod.php">App Genius Mike Lee Talks Product Engineering</a> mentions that you should produce some marketing materials (he suggests a video) to explain why people should buy your product. I don&#8217;t plan on making a video, but the app store description fulfils the same purpose, and I&#8217;d argue that it&#8217;s more valuable, as it saves on a job later as it will be refined over time.</p>

<p>This is the approach I&#8217;ll be taking to my scoping.</p>

<ol>
<li>Define the problem my customers are experiencing</li>
<li>Describe how my software solves those problems for them</li>
<li>Scope the software to solve those problems, and eliminate unnecessary features (and <em>keep</em> them out!)</li>
</ol>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Work Plans]]></title>
    <link href="http://hamishrickerby.com/2011/10/24/work-plans/"/>
    <updated>2011-10-24T17:48:00+11:00</updated>
    <id>http://hamishrickerby.com/2011/10/24/work-plans</id>
    <content type="html"><![CDATA[<p>As part of moving to Melbourne, I need to decide what I&#8217;m going to do to generate income. Traditionally I would either take a Senior Solutions Architect or Enterprise Architect job in a telco, or look for an equivalent role contracting. I think that&#8217;s not going to be the case quite yet.</p>

<p>After talking to <a href="http://twitter.com/mrsrickerby">@mrsrickerby</a> at the pub about this (all our big decisions are made at the pub), we collectively decided that I am going to continue to work for myself. Not as a contractor though, but trying to create a sustainable software company, that is more than a 1 man band.</p>

<p>Ever since I attended university, I have wanted to make software products for small businesses. I really believe the small business segment is underserved by existing products in the marketplace, and given the size of these organisations (1-10 people is the company/customer size I&#8217;d want to target), software and computers need to get out of the way and let the people run their businesses, rather than manage and maintain software. This is also probably the last opportunity I&#8217;ll ever have to give a project of this magnitude a go. I expect we&#8217;ll be looking to settle down soon, get a family home, big mortgage etc and I can&#8217;t take risks like this when I&#8217;d have all that to lose. It&#8217;d be unfair on everyone involved.</p>

<p>So, I&#8217;ll be working for 6 months when we arrive in Australia, at home, by myself, trying to create a product to help small business people run their businesses, as unobtrusively as possible.</p>

<p>I&#8217;ll also be enlisting the help of some friends. I can design software and systems very well, but user experience, graphic design, copywriting and the like are not my forte. Luckily I know some people in these areas, and I&#8217;ll be drawing on their knowledge and skills too.</p>

<p>So, the 6 months starts in the New Year (2012) and if by June 2012 and it looks like I could have something to replace the contracting work I&#8217;d alternatively be doing, I&#8217;ll be continuing on with the product. The alternative isn&#8217;t bad - it&#8217;s just not my dream.</p>

<p>Luckily I&#8217;ve managed to save up a runway of cash from working in the UK, and my wife is getting a good salary too, so we won&#8217;t be eating pot noodles to make the $$$&#8217;s stretch. My wife is very supportive.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Big Changes]]></title>
    <link href="http://hamishrickerby.com/2011/10/22/big-changes/"/>
    <updated>2011-10-22T08:20:00+11:00</updated>
    <id>http://hamishrickerby.com/2011/10/22/big-changes</id>
    <content type="html"><![CDATA[<p>Big changes are taking place. My wife <a href="http://twitter.com/mrsrickerby">@mrsrickerby</a> and I have decided that we are going to move to Australia. Well, not so much that we are going to move to Australia, more like we <em>are</em> moving. At the start of December 2011. To a city I have never been to before. <a href="http://g.co/maps/2k9vr">Melbourne</a>.</p>

<p>The rationale behind the move is that we would both like to be closer to our families. We&#8217;re both from New Zealand, and the UK for us was only ever temporary. We&#8217;ve been here 5 years, and it&#8217;s time to move on. We&#8217;ve had a good time here. <a href="http://g.co/maps/knxa2">Reading</a> is the place I&#8217;ve spent the 3rd most time in, only being beaten by <a href="http://g.co/maps/kyvuq">Auckland</a> (if you count living in a hotel in <a href="http://g.co/maps/wbjmb">Sydney</a> for 9 months as living in Auckland), and <a href="http://g.co/maps/yrk8s">Christchurch</a> where I spent just over 21 years.</p>

<p>My wife has a job organised there, but I don&#8217;t. I&#8217;m a telco consultant, and have worked for myself for the past 18 months or so doing this, as well as developing iOS applications for myself and the occasional client. I really like software product development, and would like to do more of this. Melbourne isn&#8217;t the best city in Australia for what I do (Sydney would be a more sensible choice for my work), but it&#8217;s probably time for a change, or at least, a commitment to try something I&#8217;ve wanted to do for a long time.</p>

<p>More soon.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[iPhone & iPad (iOS) Localizations and Regions ]]></title>
    <link href="http://hamishrickerby.com/2010/07/23/iphone-ipad-localizations-regions/"/>
    <updated>2010-07-23T07:45:12+10:00</updated>
    <id>http://hamishrickerby.com/2010/07/23/iphone-ipad-localizations-regions</id>
    <content type="html"><![CDATA[<p>Recently I have been doing some localizations of an iOS app from English (US) to English (UK). The iPhone development guides from Apple describe how to support multiple languages (such as English, German, Japanese), but fail to describe how to support multiple variants of a single language. By this I mean support support for US English, English, NZ English, AU English. The word I needed to regionalize was Behavior (or Behaviour, depending where you come from).</p>

<p>In the Apple Developer Library, it explicitly states that for MacOS applications take both the Language and Regional preferences of the user into account, but only look at the preferred <em>language</em> on iOS - <a href="http://developer.apple.com/iphone/library/documentation/MacOSX/Conceptual/BPInternational/Articles/InternatSupport.html">Support for Internationalization</a>.  This means that a single variant <em>per language</em> is supported.</p>

<p>However, these is a way around this. I&#8217;m not sure if this is a <em>good</em> thing to do, but it works for me and I haven&#8217;t noticed any ill side effects yet.</p>

<p>To support both US English and British English in your iOS application, create 2x Localization.strings files just as you would for multiple language. Put the US English translation file Localization.strings in a directory in your iPhone app called English.lproj (Apple defaults) and the British English translation in a directory named en_GB.lproj (just in case they decide to support regions in the future).</p>

<p>Then, you&#8217;ll need to create some code to manually set the preferred localization. In your main.m file (yup, main.m is being edited) alter it so it performs some logic similar to below.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='objective-c'><span class='line'><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span> <span class="p">{</span>
</span><span class='line'>  <span class="n">NSAutoreleasePool</span> <span class="o">*</span> <span class="n">pool</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSAutoreleasePool</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span>
</span><span class='line'>  <span class="n">NSString</span> <span class="o">*</span><span class="n">language</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSLocale</span> <span class="n">preferredLanguages</span><span class="p">]</span> <span class="nl">objectAtIndex:</span><span class="mi">0</span><span class="p">];</span>
</span><span class='line'>  <span class="n">NSString</span> <span class="o">*</span><span class="n">locale</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSLocale</span> <span class="n">currentLocale</span><span class="p">]</span> <span class="nl">objectForKey:</span> <span class="n">NSLocaleCountryCode</span><span class="p">];</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">([</span><span class="n">language</span> <span class="nl">isEqualToString:</span><span class="s">@&quot;en&quot;</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="p">[</span><span class="n">locale</span> <span class="nl">isEqualToString:</span><span class="s">@&quot;GB&quot;</span><span class="p">])</span> <span class="p">{</span>
</span><span class='line'>      <span class="p">[[</span><span class="n">NSUserDefaults</span> <span class="n">standardUserDefaults</span><span class="p">]</span> <span class="nl">setObject:</span><span class="p">[</span><span class="n">NSArray</span> <span class="nl">arrayWithObjects:</span><span class="s">@&quot;en_GB&quot;</span><span class="p">,</span> <span class="s">@&quot;en&quot;</span><span class="p">,</span> <span class="nb">nil</span><span class="p">]</span> <span class="nl">forKey:</span><span class="s">@&quot;AppleLanguages&quot;</span><span class="p">];</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>  <span class="kt">int</span> <span class="n">retVal</span> <span class="o">=</span> <span class="n">UIApplicationMain</span><span class="p">(</span><span class="n">argc</span><span class="p">,</span> <span class="n">argv</span><span class="p">,</span> <span class="nb">nil</span><span class="p">,</span> <span class="nb">nil</span><span class="p">);</span>
</span><span class='line'>  <span class="p">[</span><span class="n">pool</span> <span class="n">release</span><span class="p">];</span>
</span><span class='line'>  <span class="k">return</span> <span class="n">retVal</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>When the line</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='objective-c'><span class='line'><span class="kt">int</span> <span class="n">retVal</span> <span class="o">=</span> <span class="n">UIApplicationMain</span><span class="p">(</span><span class="n">argc</span><span class="p">,</span> <span class="n">argv</span><span class="p">,</span> <span class="nb">nil</span><span class="p">,</span> <span class="nb">nil</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p>gets executed, it seems to set up all the Localization bundles before calling the application:didFinishLaunchingWithOptions method on your app delegate, so putting Localization code in the app delegate is too late. So, what the code above does is retrieve the users current language and region, and compares those against pre-determined values - en for the language and gb for the region. If these match, then I force a new setting in the NSUserDefaults to overwrite the users preferred language. Then, when the UIApplicationManager function gets called, it appears to retrieve the users preferred language setting, and look up the Localization for that - which in my case I&#8217;ve forced to be en_GB.</p>

<p>One thing you need to be careful about is persistence of this NSUserDefault setting.  It is saved once it&#8217;s set, and persists through multiple application executions. To get around this (lets say the user changes their region back to US), you need to remove the setting after the bundle initialization has taken place.  In you app delegates application:didFinishLaunchingWithOptions method, just execute the following code.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='objective-c'><span class='line'><span class="p">[[</span><span class="n">NSUserDefaults</span> <span class="n">standardUserDefaults</span><span class="p">]</span> <span class="nl">removeObjectForKey:</span><span class="s">@&quot;AppleLanguages&quot;</span><span class="p">];</span>
</span></code></pre></td></tr></table></div></figure>


<p>This wipes out the NSUserDefault setting that the app made in the main.m file.</p>

<p>If anyone knows of issues with this approach (apart from being a dirty hack), or faults with my code please let me know in the comments below. I wish Apple supported different regions per language natively in iOS but they don&#8217;t. This is the only way I&#8217;ve found to do this, and continue to use localization functions such as NSLocalizedString.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Moving Van]]></title>
    <link href="http://hamishrickerby.com/2010/03/04/moving-van/"/>
    <updated>2010-03-04T07:35:59+11:00</updated>
    <id>http://hamishrickerby.com/2010/03/04/moving-van</id>
    <content type="html"><![CDATA[<p>Yesterday when I came home <a href="http://is.gd/93SaG">Moving Van&#8217;s</a> sales were up. I was a bit surprised as I hadn&#8217;t done any specific marketing for the app, and what was really odd is that they were only up for the UK.  A little investigation and I discover that <a href="http://is.gd/93SaG">Moving Van</a> has been featured as &#8220;New and Noteworthy&#8221; in the iTunes Store UK.</p>

<p><a href="http://hamishrickerby.com/wp-content/uploads/2010/03/Screen-shot-2010-03-03-at-17.52.49.png"><img src="http://hamishrickerby.com/wp-content/uploads/2010/03/Screen-shot-2010-03-03-at-17.52.49-300x142.png" alt="Moving Van in the iTunes Store" title="Moving Van as New and Noteworthy" width="300" height="142" class="aligncenter size-medium wp-image-444" /></a></p>

<p>How frickin&#8217; exciting!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Ad from Digg]]></title>
    <link href="http://hamishrickerby.com/2010/02/08/ad-from-digg/"/>
    <updated>2010-02-08T12:19:39+11:00</updated>
    <id>http://hamishrickerby.com/2010/02/08/ad-from-digg</id>
    <content type="html"><![CDATA[<p><a href="http://hamishrickerby.com/wp-content/uploads/2010/02/Screen-shot-2010-02-08-at-12.17.12.png"><img src="http://hamishrickerby.com/wp-content/uploads/2010/02/Screen-shot-2010-02-08-at-12.17.12.png" alt="" title="NEW LIVER?" width="638" height="134" class="aligncenter size-full wp-image-440" /></a></p>

<p>Seriously, WTF?  I assume it&#8217;s some sort of movie tie-in&#8230;</p>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Calculate age in objective-c ]]></title>
    <link href="http://hamishrickerby.com/2010/01/07/calculate-age-in-objective-c/"/>
    <updated>2010-01-07T19:30:13+11:00</updated>
    <id>http://hamishrickerby.com/2010/01/07/calculate-age-in-objective-c</id>
    <content type="html"><![CDATA[<p>For an iPhone application I&#8217;m developing for a client I need to capture the birthdate of a user, and then show their age on a profile screen. I went looking for a function to help with this simple and tedious task, but couldn&#8217;t find any example code that could be lifted to help me, so I rolled my own.  Here is what I made, steal as you see fit.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='objective-c'><span class='line'><span class="o">-</span> <span class="p">(</span><span class="n">NSInteger</span><span class="p">)</span><span class="nl">age:</span><span class="p">(</span><span class="n">NSDate</span> <span class="o">*</span><span class="p">)</span><span class="n">dateOfBirth</span> <span class="p">{</span>
</span><span class='line'>  <span class="n">NSCalendar</span> <span class="o">*</span><span class="n">calendar</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSCalendar</span> <span class="n">currentCalendar</span><span class="p">];</span>
</span><span class='line'>  <span class="kt">unsigned</span> <span class="n">unitFlags</span> <span class="o">=</span> <span class="n">NSYearCalendarUnit</span> <span class="o">|</span> <span class="n">NSMonthCalendarUnit</span> <span class="o">|</span> <span class="n">NSDayCalendarUnit</span><span class="p">;</span>
</span><span class='line'>  <span class="n">NSDateComponents</span> <span class="o">*</span><span class="n">dateComponentsNow</span> <span class="o">=</span> <span class="p">[</span><span class="n">calendar</span> <span class="nl">components:</span><span class="n">unitFlags</span> <span class="nl">fromDate:</span><span class="p">[</span><span class="n">NSDate</span> <span class="n">date</span><span class="p">]];</span>
</span><span class='line'>  <span class="n">NSDateComponents</span> <span class="o">*</span><span class="n">dateComponentsBirth</span> <span class="o">=</span> <span class="p">[</span><span class="n">calendar</span> <span class="nl">components:</span><span class="n">unitFlags</span> <span class="nl">fromDate:</span><span class="n">dateOfBirth</span><span class="p">];</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">if</span> <span class="p">(([</span><span class="n">dateComponentsNow</span> <span class="n">month</span><span class="p">]</span> <span class="o">&lt;</span> <span class="p">[</span><span class="n">dateComponentsBirth</span> <span class="n">month</span><span class="p">])</span> <span class="o">||</span>
</span><span class='line'>      <span class="p">(([</span><span class="n">dateComponentsNow</span> <span class="n">month</span><span class="p">]</span> <span class="o">==</span> <span class="p">[</span><span class="n">dateComponentsBirth</span> <span class="n">month</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="p">([</span><span class="n">dateComponentsNow</span> <span class="n">day</span><span class="p">]</span> <span class="o">&lt;</span> <span class="p">[</span><span class="n">dateComponentsBirth</span> <span class="n">day</span><span class="p">])))</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">return</span> <span class="p">[</span><span class="n">dateComponentsNow</span> <span class="n">year</span><span class="p">]</span> <span class="o">-</span> <span class="p">[</span><span class="n">dateComponentsBirth</span> <span class="n">year</span><span class="p">]</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
</span><span class='line'>  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">return</span> <span class="p">[</span><span class="n">dateComponentsNow</span> <span class="n">year</span><span class="p">]</span> <span class="o">-</span> <span class="p">[</span><span class="n">dateComponentsBirth</span> <span class="n">year</span><span class="p">];</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[iPhone Camera Overlays + iphonearkit]]></title>
    <link href="http://hamishrickerby.com/2009/09/20/iphone-camera-overlays-iphonearkit/"/>
    <updated>2009-09-20T16:58:33+10:00</updated>
    <id>http://hamishrickerby.com/2009/09/20/iphone-camera-overlays-iphonearkit</id>
    <content type="html"><![CDATA[<p>Today I have been hacking away on the <a href="http://github.com/zac/iphonearkit" target="_self">iphonearkit source</a> available at github and have incorporated the ARGeoViewController as an overlay over a ImagePickerController with the camera as the source (which was introduced with iPhone OS 3.1).  Results below.</p>

<p><img class="size-medium wp-image-425" title="ARGeoViewController overlay" src="http://hamishrickerby.com/wp-content/uploads/2009/09/IMG_0337-300x200.PNG" alt="ARGeoViewController as the overlay on a ImagePickerController on iPhone" width="300" height="200" /></p>


<p>I want to tidy up some of the code before I check it back into <a href="http://github.com/rickerbh/iphonearkit" target="_blank">my clone of the source</a>, but this is a really good basis for some smart location and direction aware augmented reality apps on iPhone.  Wonder what the iphonearkit license is - it&#8217;s unclear&#8230;</p>

<p>&#8212; EDIT &#8212;</p>

<p>Bugger.  It appears that <a href="http://github.com/zac/" target="_blank">zac</a> has implemented similar functionality to me already :-(  Bloody github and it&#8217;s slow (never!) updates to fork queues and network graphs.  Oh well, maybe I won&#8217;t bother tidying my code.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Augmented Reality - Hello World]]></title>
    <link href="http://hamishrickerby.com/2009/09/20/augmented-reality-hello-world/"/>
    <updated>2009-09-20T16:07:09+10:00</updated>
    <id>http://hamishrickerby.com/2009/09/20/augmented-reality-hello-world</id>
    <content type="html"><![CDATA[<p>I&#8217;ve recently discovered augmented reality. After I saw my first &#8220;virtual business card&#8221; application I was hooked.  I&#8217;ve been doing a lot of reading and experimenting with software over the past 2 days, and have got <a href="http://www.hitl.washington.edu/artoolkit/" target="_blank">ARToolkit</a> working here.  Here are some shots of the obligitory &#8220;cube over marker&#8221; demo.  I would post a video, but my screen capture software and AR software = a really poor frame rate and substandard video :-(</p>

<p><a href="http://hamishrickerby.com/wp-content/uploads/2009/09/Screen-shot-2009-09-20-at-16.57.47.png"><img class="size-medium wp-image-418" title="AR Marker" src="http://hamishrickerby.com/wp-content/uploads/2009/09/Screen-shot-2009-09-20-at-16.57.47-300x239.png" alt="Marker with no overlaid image" width="300" height="239" /></a></p>

<p><a href="http://hamishrickerby.com/wp-content/uploads/2009/09/Screen-shot-2009-09-20-at-16.58.01.png"><img class="size-medium wp-image-419" title="Cube over marker" src="http://hamishrickerby.com/wp-content/uploads/2009/09/Screen-shot-2009-09-20-at-16.58.01-300x242.png" alt="Blue cube over the Hiro marker" width="300" height="242" /></a></p>

<p>Next up, something more substantial.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[No, I don't agree]]></title>
    <link href="http://hamishrickerby.com/2009/09/17/no-i-dont-agree/"/>
    <updated>2009-09-17T17:17:02+10:00</updated>
    <id>http://hamishrickerby.com/2009/09/17/no-i-dont-agree</id>
    <content type="html"><![CDATA[<p>Tough luck - the box is un-uncheckable.<a href="http://hamishrickerby.com/wp-content/uploads/2009/09/Screen-shot-2009-09-17-at-18.13.53.png"><img class="aligncenter size-full wp-image-413" title="Screen shot 2009-09-17 at 18.13.53" src="http://hamishrickerby.com/wp-content/uploads/2009/09/Screen-shot-2009-09-17-at-18.13.53.png" alt="Screen shot 2009-09-17 at 18.13.53" width="234" height="37" /></a>I guess it&#8217;s one way to make sure that people accept your terms &amp; conditions - force them to.  One less click.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Kit Quiz: UK]]></title>
    <link href="http://hamishrickerby.com/2009/09/11/kit-quiz-uk/"/>
    <updated>2009-09-11T08:00:50+10:00</updated>
    <id>http://hamishrickerby.com/2009/09/11/kit-quiz-uk</id>
    <content type="html"><![CDATA[<p>&lt;shameless self promotion&gt;</p>

<p>My 4th iPhone application was approved yesterday by Apple, and it launches in the <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=329199029" target="_blank">iTunes store</a> today.  It&#8217;s called <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=329199029" target="_blank">Kit Quiz: UK</a> and is a UK team based football (soccer) shirt quiz game.  It features over 130 shirts from UK football teams, and will have more added shortly.  There are 3 modes of gameplay, from the practise model &#8220;Friendly&#8221; to a time challenge &#8220;Blitz&#8221;.</p>

<p>It&#8217;s integrated with Twitter and Facebook so you can check out your friends scores and find out once and for all who can recognise the most football shirts.</p>

<p>Couple of screenshots below for anyone interested.  <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=329199029" target="_blank">Download it now!</a></p>

<p><a href="http://hamishrickerby.com/wp-content/uploads/2009/09/kit-quiz-start.png"><img class="size-medium wp-image-404" title="Kit Quiz: UK Menu" src="http://hamishrickerby.com/wp-content/uploads/2009/09/kit-quiz-start-300x200.png" alt="Kit Quiz: UK menu screen" width="300" height="200" /></a></p>

<p><a href="http://hamishrickerby.com/wp-content/uploads/2009/09/kit-quiz-game.png"><img class="size-medium wp-image-403" title="Kit Quiz: UK - Blitz" src="http://hamishrickerby.com/wp-content/uploads/2009/09/kit-quiz-game-300x200.png" alt="Kit Quiz: UK - Blitz screen" width="300" height="200" /></a></p>

<p>&lt;/shameless self promotion&gt;</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Passenger (Ruby on Rails) + PHP on OSX]]></title>
    <link href="http://hamishrickerby.com/2009/08/15/passenger-ruby-on-rails-php-on-osx/"/>
    <updated>2009-08-15T10:06:53+10:00</updated>
    <id>http://hamishrickerby.com/2009/08/15/passenger-ruby-on-rails-php-on-osx</id>
    <content type="html"><![CDATA[<p>I&#8217;ve spent the last hour or so trying various things out to get passenger and PHP to play nicely together on my mac under OS X (Leopard) and apache2.</p>

<p>The situation I was finding was that PHP apps would run, but only if you explicitly call the script (ie <tt>index.php</tt>) rather than just the directory.  If you called the directory, passenger would take over and give me a rails routing error.</p>

<p>The issue was to do with the passenger vhosts configuration.  On my machine I have an number of ruby on rails apps configured with the passenger preferences pane (creating vhost entries within <tt>/private/etc/apache2/passenger_pane_vhosts/</tt>.  I have enabled user_dirs, so that the users of my machine&#8217;s pages (and other apps) are served from their <tt>~username/Sites</tt> directory.</p>

<p>My users configuration info for apache is installed in <tt>/private/etc/apache2/users/</tt>, and the instructions to load the configuration from that directory is stored within <tt>/private/etc/apache2/extra/httpd-userdir.conf</tt> (content below).</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># Settings for user home directories
</span><span class='line'>#
</span><span class='line'># Required module: mod_userdir
</span><span class='line'>#
</span><span class='line'># UserDir: The name of the directory that is appended onto a user's home
</span><span class='line'># directory if a ~user request is received.  Note that you must also set
</span><span class='line'># the default access control for these directories, as in the example below.
</span><span class='line'>#
</span><span class='line'>UserDir Sites
</span><span class='line'>#
</span><span class='line'># Users might not be in /Users/*/Sites, so use user-specific config files.
</span><span class='line'>#
</span><span class='line'>Include /private/etc/apache2/users/*.conf</span></code></pre></td></tr></table></div></figure>


<p>To get everything working together nicely, I merely wrapped this inside a vhosts configuration directive, and gave it a ServerName of localhost - so that this vhost would be the one that responds to requests for localhost, rather than some random passenger vhost assuming it was the boss of everything.  New <tt>/private/etc/apache2/extra/httpd-userdir.conf</tt> below.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>&lt;VirtualHost *:80&gt;
</span><span class='line'>  ServerName localhost
</span><span class='line'>  UserDir Sites
</span><span class='line'>  Include /private/etc/apache2/users/*.conf
</span><span class='line'>&lt;/VirtualHost&gt;</span></code></pre></td></tr></table></div></figure>


<p>Thanks to this, all of my rails apps are served under passenger, and I can have static HTML, PHP and camping apps (previously configured - nothing to do with the above) all served from within my <tt>~username/Sites</tt> directory.</p>

<p>Hope this helps someone.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[123456789]]></title>
    <link href="http://hamishrickerby.com/2009/08/07/123456789/"/>
    <updated>2009-08-07T11:40:26+10:00</updated>
    <id>http://hamishrickerby.com/2009/08/07/123456789</id>
    <content type="html"><![CDATA[<p>Today in the UK the time hit 12:34:56 7/8/9.  Not exciting for everyone I guess, but it won&#8217;t happen again for another 100 years.</p>

<p><a href="http://hamishrickerby.com/wp-content/uploads/2009/08/123456789.PNG"><img src="http://hamishrickerby.com/wp-content/uploads/2009/08/123456789-300x252.PNG" alt="123456789" title="123456789" width="300" height="252" class="aligncenter size-medium wp-image-385" /></a></p>
]]></content>
  </entry>
  
</feed>

