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

    <title type="text">digitalformula</title>
    <subtitle type="text">digitalformula:</subtitle>
    <link rel="alternate" type="text/html" href="http://digitalformula.net" />
    <link rel="self" type="application/atom+xml" href="http://digitalformula.net/df/atom" />
    <updated>2012-02-20T06:07:11Z</updated>
    <rights>Copyright (c) 2012, chris</rights>
    <generator uri="http://expressionengine.com/" version="2.5.0">ExpressionEngine</generator>
    <id>tag:digitalformula.net,2012:02:20</id>


    <entry>
      <title>HTML5 Boilerplate &#45; Quick setup script</title>
      <link rel="alternate" type="text/html" href="http://digitalformula.net/df/html5-boilerplate-quick-setup-script" />
      <id>tag:digitalformula.net,2012:digitalformula.net/1.111</id>
      <published>2012-02-20T10:42:10Z</published>
      <updated>2012-02-20T06:07:11Z</updated>
      <author>
            <name>chris</name>
            <email>chrisrnz@gmail.com</email>
                  </author>

      <category term="Design"
        scheme="http://digitalformula.net/df/category/design"
        label="Design" />
      <content type="html"><![CDATA[
        <p>
Recently I've been setting up new websites left, right and center.&nbsp;&nbsp;These have been almost exclusively for testing purposes and, since I've been basing them all off Paul Irish's HTML5 Boilerplate, I needed a quick way to get a new site template up and running.
</p>

<h2>Enter automation</h2>

<p>
I set about making a quick script to automate the process of setting up a new website template based on the boilerplate (which I'll refer to as h5bp from here on).&nbsp;&nbsp;The steps it goes through are as follows (Bash-specific but could be retro-fitted to Windows without too much trouble).
</p>

<ul>
   <li>Checks to see if git is installed.&nbsp;&nbsp;This is required as the latest h5bp version is available from github.</li>
   <li>If git isn't installed, the script will fail gracefully and provide instructions on how to install git.<li>
   <li>Checks for a single parameter.&nbsp;&nbsp;If found, the script will use this as the name of the directory to create the project in, relative to &quot;.&quot;</li>
   <li>If no parameter is specified, the destination folder is setup to a folder named after the current date and time.</li>
   <li>Checks to see if the destination folder exists (almost impossible if using the date and time method).&nbsp;&nbsp;If it's not found, it is created.</li>
   <li>Initialises a new git local repository in the new project directory.</li>
   <li>Clones the latest h5bp version into the project directory.</li>
   <li>Clones the latest h5bp ant build script into the project directory,</li>
   <li>Cleans up the directory structure a bit, e.g. renames the ant build script from &quot;ant-build-script&quot; to &quot;build&quot;&nbsp;&nbsp;I've found this to be a required step before the build script will run properly.</li>
   <li>Converts the h5bp markdown documentation to HTML, if pandoc is found on the local system.</li>
   <li>Does a bit more cleanup and moves some non-critical files into a directory called &quot;_exclude&quot;</li>
   <li>Configures some global git options, i.e. the user name and user email address.</li>
   <li>Adds all the project files to the new git repository.</li>
   <li>Does a full commit of the new files.</li>
   <li>Finishes up with a small message showing some steps that may be helpful to new users.</li>
</ul>

<h2>Care to share?</h2>

<p>
Sure.&nbsp;&nbsp;If you're interested in the script, here it is in its entirety.&nbsp;&nbsp;On my system I have it installed as an alias by putting into ~/.bash_profile inside a function called h5bp.&nbsp;&nbsp;If you want to use the script in a stand-alone way, that works fine, too.&nbsp;&nbsp;For the purposes of this article, I'll show the code in its function-based form.
</p>

<h2>The script</h2>

<pre class="brush: bash;"># function to create a new website based on the HTML5 BoilerPlate (http://h5bp.com)
function h5bp {
	if [[ -z `which git` ]]; then
		echo "   The git binaries were not found on this system and are required before this script will run properly."
		echo "   If you are sure git is installed, please investigate why the 'git' command wasn't found, then try again."
		echo "   To do this, you can try running \"echo \`which git\`\" (without the double quotes but keep the single ones!)."
		echo "   If you don't have git installed, please download and install it by following the instructions located at http://git-scm.com/download."
	else
		echo "git binary found at `which git`."
		echo "Creating new website."
		if [ -z $1 ]; then
			newFolderName=`date +%Y-%m-%d_%H-%M-%S`
			echo "No folder name specified, using current date and time: $newFolderName."
		else
			newFolderName=$1
			echo "Using '$newFolderName' as destination folder."
		fi
	        if [ ! -d $newFolderName ]; then
				echo "Destination folder not found, creating it now."
				mkdir $newFolderName
				cd $newFolderName
	        else
				cd $newFolderName
	        fi
	        echo "Initialising new git repository in `pwd`."
	        git init --quiet
	        echo "Getting latest h5bp build from github."
	        git clone https://github.com/h5bp/html5-boilerplate.git
	        echo "Getting latest h5bp build script."
	        git clone https://github.com/h5bp/ant-build-script.git
	    echo "Moving files into place."
		mv html5-boilerplate/* ./
		rm -Rf html5-boilerplate/
		mv ant-build-script/ build/
		mkdir _exclude/
		if [[ -z `which pandoc` ]]; then
			echo "Unable to convert the readme.md file to HTML for viewing.  You can fix this by installing 'pandoc' from http://johnmacfarlane.net/pandoc/."
		else
			echo "Converting markdown documentation to HTML."
			pandoc readme.md -o readme.html
			mv readme.html _exclude/
		fi
		mv readme.md _exclude/
		echo "Setting git global options."
		git config --global user.name "Put your name here" --quiet
		git config --global user.email you@yourdomain.com --quiet
		echo "Adding new files to new git repository."
		git add *
		echo "Running initial project commit."
		git commit -m "Initial h5bp project creation" --quiet
		echo ""
		echo "You should edit humans.txt in the '$newFolderName' directory before going any further."
		echo "Also, if you're not familiar with how to use the h5bp, you should go through the readme file in the _exclude/ directory (readme.md, or readme.html if you have pandoc installed)."
		echo ""
		echo "Done!"
	fi
}</pre>

<h2>Can we see it in action?</h2>

<p>
Of course you can.&nbsp;&nbsp;I've recorded the script in action and put it up on YouTube - see below.&nbsp;&nbsp;To view the video in HD so that your viewing experience doesn't suffer from small-video-itis, I'd highly recommend <a href="http://youtu.be/ey6Y6QFmd1Q" title="h5bp new website script" target="_blank">watching it on the YouTube website</a> (opens in a new window).
</p>

<p>
<iframe width="530" height="359" src="http://www.youtube.com/embed/ey6Y6QFmd1Q" frameborder="0" allowfullscreen></iframe>
</p> {extended}
      ]]></content>
    </entry>

    <entry>
      <title>Set network interface IP address with Powershell</title>
      <link rel="alternate" type="text/html" href="http://digitalformula.net/df/set-network-interface-ip-address-with-powershell" />
      <id>tag:digitalformula.net,2012:digitalformula.net/1.110</id>
      <published>2012-01-25T11:38:08Z</published>
      <updated>2012-01-25T06:51:09Z</updated>
      <author>
            <name>chris</name>
            <email>chrisrnz@gmail.com</email>
                  </author>

      <category term="Software"
        scheme="http://digitalformula.net/df/category/software"
        label="Software" />
      <content type="html"><![CDATA[
        <h2 id="theproblem">The Problem</h2>

<p>While setting up our partner technology centre recently, I found myself switching back and forth between networks so often that I was constantly having to change my laptop&#8217;s IP address.  For reasons that are outside the scope of this article I&#8217;m unable to use the option for an alternate network configuration.</p>

<h2 id="powershelltotherescue">Powershell to the rescue</h2>

<p>The solution?  Two small Powershell scripts - one to setup my network connection for our corporate LAN, the other to setup my network connection for the PTC.  The scripts are shown below - feel free to use them in any way you like.</p>

<h2 id="ptcconfigurationscript">PTC configuration script</h2>

<pre class="brush: ps;" title="PTC configuration script">$index = (gwmi Win32_NetworkAdapter | where {$_.netconnectionid -eq &#8220;Local Area Connection&#8221;}).InterfaceIndex
$NetInterface = Get-WmiObject Win32_NetworkAdapterConfiguration | where {$_.InterfaceIndex -eq $index}
$NetInterface.EnableStatic(&#8220;10.0.0.10&#8221;, &#8220;255.255.255.0&#8221;)
$NetInterface.SetDynamicDNSRegistration(&#8220;FALSE&#8221;)</pre>

<h2 id="corporatelanconfigurationscript">Corporate LAN configuration script</h2>

<p>This script just resets the network adapter back to DHCP</p>

<pre class="brush: ps;" title="Corporate LAN configuration script">$index = (gwmi Win32_NetworkAdapter | where {$_.netconnectionid -eq &#8220;Local Area Connection&#8221;}).InterfaceIndex
$NetInterface = Get-WmiObject Win32_NetworkAdapterConfiguration | where {$_.InterfaceIndex -eq $index}
$NetInterface.EnableDHCP()
$NetInterface.SetDynamicDNSRegistration(&#8220;TRUE&#8221;)</pre>

<h2 id="extrastuff">Extra stuff</h2>

<p>Although I don&#8217;t need them in my PTC environment (it&#8217;s internal only, with no internet access), you can also use the snippets below to add some extra functionality.</p>

<pre class="brush: ps;" title="Set gateway">$NetInterface.SetGateways($gateway)</pre>

<pre class="brush: ps;" title="Set DNS server search order">$NetInterface.SetDNSServerSearchOrder($dns)
# (e.g. “10.10.1.1” for single server or “10.10.1.1,10.10.1.2” for multiple servers)</pre>

<pre class="brush: ps;" title="Enable dynamic DNS registration (e.g. in AD environment)">$NetInterface.SetDynamicDNSRegistration($registerDns)</pre> {extended}
      ]]></content>
    </entry>

    <entry>
      <title>Getting Hazel for Mac to process subfolders</title>
      <link rel="alternate" type="text/html" href="http://digitalformula.net/df/getting-hazel-for-mac-to-process-subfolders" />
      <id>tag:digitalformula.net,2012:digitalformula.net/1.109</id>
      <published>2012-01-14T02:23:09Z</published>
      <updated>2012-01-13T21:50:10Z</updated>
      <author>
            <name>chris</name>
            <email>chrisrnz@gmail.com</email>
                  </author>

      <category term="Mac &amp; OS X"
        scheme="http://digitalformula.net/df/category/mac-os-x"
        label="Mac &amp; OS X" />
      <content type="html"><![CDATA[
        <p>Back in February 2011 I wrote an article called <a href="http://digitalformula.net/d/22" title="Running HandBrakeCLI from Hazel">Running HandBrakeCLI from Hazel</a> that described how to setup <a href="http://www.noodlesoft.com/hazel.php" title="Hazel for Mac">Hazel for Mac</a> to automatically run <a href="http://handbrake.fr/downloads2.php" title="Handbrake">Handbrake</a> from the command line.  The idea of this is to run Handbrake automatically when a video file appears in a specific folder and convert the video to .m4v format suitable for iTunes.</p>

<p>This is a quick update to that post that shows how to setup Hazel to also process subfolders as, up until now, the Hazel configuration I had only processed a single level of folders.</p>

<h2 id="thehazelrule">The Hazel Rule</h2>

<p>The configuration is pretty easy.  Simply add a new rule <em>at the top</em> of your Hazel rules, making 100% sure it is above the rule that runs to automatically convert the video files.</p>

<p>The rule order looks like this:</p>

<figure>
<img src="http://images.digitalformula.net/entries/2012-01-14-getting-hazel-for-mac-to-process-subfolders/hazel-rules.jpg" title="Hazel rule order" alt="Hazel rule order" />
<figcaption>Hazel rule order</figcaption>
</figure>

<p>The rule itself looks like this:</p>

<figure>
<img src="http://images.digitalformula.net/entries/2012-01-14-getting-hazel-for-mac-to-process-subfolders/hazel-folder-rule.jpg" title="Hazel rule to process subfolders" alt="Hazel rule to process subfolders" />
<figcaption>Hazel rule to process subfolders</figcaption>
</figure>

<p>Once that rule is in place and the order is correct, the following rule will run once a new subfolder is found in the appropriate location.</p> {extended}
      ]]></content>
    </entry>

    <entry>
      <title>Dynamic HTML grid with ExpressionEngine</title>
      <link rel="alternate" type="text/html" href="http://digitalformula.net/df/dynamic-html-grid-with-expressionengine" />
      <id>tag:digitalformula.net,2012:digitalformula.net/1.108</id>
      <published>2012-01-03T08:18:45Z</published>
      <updated>2012-01-04T05:43:46Z</updated>
      <author>
            <name>chris</name>
            <email>chrisrnz@gmail.com</email>
                  </author>

      <category term="ExpressionEngine"
        scheme="http://digitalformula.net/df/category/expressionengine"
        label="ExpressionEngine" />
      <content type="html"><![CDATA[
        <h2 id="introduction">Introduction</h2>

<p>This article is going to be a long one so sit back, relax (if you can) and get ready to do some EE hacking &#8230; ok, not hacking, creation.  :)</p>

<h2 id="assumptions">Assumptions</h2>

<p>I&#8217;m going to make a few assumptions for this article, as follows.</p>

<ol>
<li>You know your way around the ExpressionEngine control panel and are familiar with terms like <em>template</em>, etc.</li>
<li>You know what jQuery is have an idea of what it is used for.</li>
</ol>

<h2 id="thesituation">The Situation</h2>

<p>Recently I&#8217;ve been doing some work on the redesign of the website for <a href="http://www.erinking.com.au" title="Erin King Photographer">Erin King Photographer</a>. Part of the redesign is the requirement for Erin to do 99% of the site management herself, without the need to refer back to me.</p>

<p>I realised that I&#8217;d need absolute control over the layout, styling &amp; site architecture for this to work - that meant Wordpress wasn&#8217;t an option for this version of Erin&#8217;s site. Now, I&#8217;m not saying Wordpress couldn&#8217;t do the job (we still run <a href="http://www.erinking.com.au/Blog" title="Erin's Blog">Erin&#8217;s blog</a> part of the site on Wordpress. In my opinion, though, Wordpress forces a shift in focus from design to content management - good for some but not what I wanted.</p>

<h2 id="thedesiredlayout">The Desired Layout</h2>

<p>It looks simple (and is, when rendered), but this is the layout we&#8217;re trying to get to.  Don&#8217;t forget this must be built &amp; rendered dynamically, not hard-coded in the page&#8217;s markup.</p>

<p><figure>
<img src="http://images.digitalformula.net/entries/2012-01-04-dynamic-html-grid-with-expressionengine/multigrid.jpg" title="Dynamic HTML grid for displaying products" alt="Dynamic HTML grid for displaying products" />
<figcaption>The desired layout</figcaption>
</figure>   </p>

<h2 id="thedecision">The Decision</h2>

<p>Some time ago I decided the new site should run on <a href="http://www.expressionengine.com" title="ExpressionEngine">ExpressionEngine</a>.  The ability to control absolutely everything and yet still have the power of a full CMS made the decision pretty easy (plus, <a href="http://digitalformula.net/" title="Digital Formula">Digital Formula</a> runs on ExpressionEngine).</p>

<h2 id="theproblem">The Problem</h2>

<p>The first issue I ran into (which I knew was coming) was that ExpressionEngine&#8217;s native file module, while powerful in its simplicity, does lack a couple of what you&#8217;d expect to be standard features.  For example, it&#8217;s difficult to control the order that files are displayed, unless they all have a different date and time in the database.  It&#8217;s also impossible to manually set the file order in the control panel and have that order obeyed during page rendering.</p>

{pagebreak}

<h2 id="thesolution">The Solution</h2>

<p>So, the point of this article is to show how to create a completely dynamic grid-based product page using the following things.</p>

<ol>
<li><a href="http://www.expressionengine.com" title="ExpressionEngine">ExpressionEngine</a>.  This is the basis for the site itself.</li>
<li>The ExpressionEngine <a href="http://expressionengine.com/user_guide/modules/file/index.html" title="File Module">File Module</a>.</li>
<li>The brilliant <a href="http://pixelandtonic.com/matrix" title="Matrix by Pixel and Tonic">Matrix</a> plugin by Pixel and Tonic.</li>
<li>Zack Grossbart&#8217;s awesome <a href="http://www.zackgrossbart.com/hackito/jsgrid/" title="Dynamic Grid Layout in JavaScript and jQuery">Dynamic Grid Layout jQuery Plugin</a>.</li>
<li>The <a href="http://devot-ee.com/add-ons/image-sizer" title="Image Sizer">Image Sizer</a> plugin for ExpressionEngine.</li>
</ol>

<p>Note: Because EE isn&#8217;t free (some consider it very expensive), I&#8217;m going to make the assumption that paying USD $55 for the Matrix plugin isn&#8217;t a major problem, either.</p>

<h2 id="oksohowdoweproceed">Ok, so how do we proceed?</h2>

<p>There are a few steps to cover off first - please make sure you&#8217;ve done these before getting stuck in.</p>

<ol>
<li>Setup ExpressionEngine as per your requirements.  Because these settings are site-specific, I&#8217;m not going to cover EE configuration here.</li>
<li>Enable the EE File module.</li>
<li>Setup an upload location for the images in the product section (remember, this article is for a products page).  Don&#8217;t forget to set the appropriate permissions on the upload location &#8230;</li>
<li>Install and register the Matrix fieldtype.</li>
<li>Install and enable the Image Sizer plugin.</li>
<li>Upload some files to the products upload location.  You don&#8217;t need to add captions to the files as we&#8217;ll be using Matrix for that.</li>
<li>Upload and reference the Dynamic Grid Layout JavaScript in the relevant pages on your site.</li>
</ol>

<h2 id="matrixconfiguration">Matrix Configuration</h2>

<p>Now that all the preparatory stuff is done, we can configure Matrix. The channel that has the products info must have a custom field of type &#8216;Matrix&#8217;.  The example I&#8217;m working with is called <em>Product Images</em> and has three field options within the field:</p>

<ol>
<li>Product Image (cell type = File), called <em>product_image</em> - make sure the Allowed Directory is set to the name of your upload location if you want to guarantee the files end up in the right place.</li>
<li>Long caption (cell type = Text), called <em>caption</em>.</li>
<li>Short caption (cell type = Text), called <em>short_caption</em>.</li>
</ol>

<h2 id="channelentry">Channel Entry</h2>

<p>Create a channel entry in the relevant channel and, in the &#8220;Product Images&#8221; field, create a number of Matrix rows that reference files you uploaded earlier.  Make sure the Matrix rows have info in both the <em>Caption</em> and <em>Short Caption</em> columns.  If you want to make absolutely sure these fields are filled in, enforce it by setting those columns to required in the Matrix configuration.</p>

<p>Once the entry is live, take note of the entry ID - we&#8217;ll be using it in our template.</p>

{pagebreak}

<h2 id="templatecode">Template Code</h2>

<p>Up till this point, you&#8217;ve done the following.</p>

<ol>
<li>Upload the product images.</li>
<li>Configured Matrix.</li>
<li>Created a channel entry and assigned some of the product images to the Matrix field.</li>
</ol>

<p>Now you&#8217;re ready to create a template to show these files referenced by the entry you created a minute ago.  The template code is as follows.</p>

<pre class="brush: xml;">&#123;exp:channel:entries channel="products" entry_id="25" dynamic="no"&#125;
    &lt;h2&gt;&#123;title&#125;&lt;/h2&gt;&lt;br /&gt;
    &lt;div id="basicgrid"&gt;  
        &#123;product_images&#125;
            &lt;div class="cell"&gt;
                &lt;div class="product"&gt;
                    &lt;a href="&#123;product_image&#125;" class="fancybox" title="&#123;caption&#125;"&gt;
                        &#123;exp:imgsizer:size src="&#123;product_image&#125;" width="200"&#125;
                            &lt;img src="&#123;sized&#125;" alt="&#123;short_caption&#125;" width="&#123;width&#125;" height="&#123;height&#125;" /&gt;
                        &#123;/exp:imgsizer:size&#125;
                    &lt;/a&gt;
                    &lt;br /&gt;
                    &lt;span class="product-caption"&gt;&#123;short_caption&#125;&lt;/span&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &#123;/product_images&#125;
    &lt;/div&gt;
&#123;/exp:channel:entries&#125;</pre>

<p>Those of you with keen eyes may have noticed the reference to &#8220;FancyBox&#8221;.  This isn&#8217;t a requirement for the layout but will give your users the ability to click the images and be shown a nice popup containing the full-size image.  If you don&#8217;t want the images to be clickable, remove the anchor tag.  Likewise, if you don&#8217;t want to use FancyBox, remove the <em>class=&#8221;fancybox&#8221;</em> attribute on the anchor tag.</p>

<h2 id="line-by-lineexplanations">Line-by-line Explanations</h2>

<pre class="brush: html;">&#123;exp:channel:entries channel="products" entry_id="1" dynamic="no"&#125;</pre>

<p>This line is where we tell the EE template which channel and entry to pull from the database.  In this example, we&#8217;re using entry number 1 from the &#8220;products&#8221; channel.</p>

<pre class="brush: html;">&lt;div id="basicgrid"&gt;</pre>

<p>This is a critical line for the grid formatting that we&#8217;ll be setting up shortly.  The div id doesn&#8217;t have to be &#8220;basicgrid&#8221; but you do need to remember what you put here.</p>

<pre class="brush: html;">&#123;product_images&#125;
            &lt;div class="cell"&gt;</pre>

<p>These are the opening tags for the Matrix field (remember we called it <em>product_images</em> earlier) and opens a div that will be used by the grid script later.  Unless you edit the <em>multigrid.js</em> file, this div have a class of &#8220;cell&#8221;.</p>

<pre class="brush: html;">&lt;a href="&#123;product_image&#125;" class="fancybox" title="&#123;caption&#125;"&gt;
    &#123;exp:imgsizer:size src="&#123;product_image&#125;" width="200"&#125;
        &lt;img src="&#123;sized&#125;" alt="&#123;short_caption&#125;" width="&#123;width&#125;" height="&#123;height&#125;" /&gt;
    &#123;/exp:imgsizer:size&#125;
&lt;/a&gt;</pre>

<p>These lines create an anchor that can be clicked to show the full-sized image in a nice FancyBox popup.  Within the anchor we&#8217;re taking the <em>product_image</em> field and applying the <em>Image Sizer</em> plugin to it to create a thumbnail 200px wide.</p>

<pre class="brush: html;">&#123;/product_images&#125;
    &lt;/div&gt;
&#123;/exp:channel:entries&#125;</pre>

<p>Finally, don&#8217;t forget to close the Matrix <em>product_images</em> and channel entries tags &#8230;</p>

{pagebreak}

<h2 id="willitworkyet">Will it work, yet?</h2>

<p>Yes &#8230; sort-of.  At this point the template will pull entry number 1 from the <em>product</em> channel and display the Matrix images associated with it on the page.  However, the images will be displayed top-down without any grid formatting.  The next step is to apply the grid formatting JavaScript so that the grid layout works properly.</p>

<h2 id="reformattingtheproductimages">Reformatting the product images</h2>

<p>If you don&#8217;t have one already, your site&#8217;s pages will need to run a JavaScript file that can call jQuery functions.  I&#8217;m happy to help you if you don&#8217;t know what this means (<a href="http://digitalformula.net/pages/contact" title="Contact Me">Contact Me</a>) but, for those that do, the jQuery code is as follows.</p>

<pre class="brush: js;">$(document).ready(function() &#123;
    /* jQuery grid */
    /* parameter order: number of columns, column width, column height, cell spacing */
    /* all sizes are measured in em */
    alignGrid("basicgrid", 4, 18, 18, 0.25);
&#125;);</pre>

<p>The example above uses numbers I pulled out of thin air; you&#8217;ll need to modify them to fit your site&#8217;s design.</p>

<h2 id="nowwillitwork">NOW will it work?</h2>

<p>Yes.  If all plugins are installed &amp; configured properly and you have the correct content in your channel entry, your product images will be taken from the database, displayed on the page then formatted into a nice grid.</p>

<p>Now, I&#8217;m aware that this could be done manually by using an HTML table but remember that the point of this is for Erin to be able to upload &amp; remove product images, re-order them, edit captions and descriptions etc, all without asking for any help from the site&#8217;s designer (me).</p>

<p>Problem solved.  :)</p> {extended}
      ]]></content>
    </entry>

    <entry>
      <title>Hawthorn Cycling Club Summer Criterium &#45; Round 2</title>
      <link rel="alternate" type="text/html" href="http://digitalformula.net/df/hawthorn-cycling-club-summer-criterium-round-2" />
      <id>tag:digitalformula.net,2011:digitalformula.net/1.107</id>
      <published>2011-10-13T10:54:55Z</published>
      <updated>2011-10-13T07:04:56Z</updated>
      <author>
            <name>chris</name>
            <email>chrisrnz@gmail.com</email>
                  </author>

      <category term="Photography"
        scheme="http://digitalformula.net/df/category/photography"
        label="Photography" />
      <content type="html"><![CDATA[
        <p>
On Wednesday night I headed up to Studley Park (about 5km from Melbourne CBD) and shot round 2 of the Hawthorn Cycling Club summer criterium road cycling series.&nbsp;&nbsp;It was a perfect evening for racing, marred only by a serious crash that caused the event to be called off ahead of schedule.
</p>

<p>
The full set is available on the <a href="http://digitalformula.net/d/hccround2photos" target="_new" title="HCC Criterium Round 2 Photos">Digital Formula Flickr Pro site</a>, along with information on how high/print quality images can be ordered.&nbsp;&nbsp;Enjoy.
</p> {extended}
      ]]></content>
    </entry>

    <entry>
      <title>ExpressionEngine Plugin &#45; Entry Age</title>
      <link rel="alternate" type="text/html" href="http://digitalformula.net/df/expressionengine-plugin-entry-age" />
      <id>tag:digitalformula.net,2011:digitalformula.net/1.106</id>
      <published>2011-07-16T12:33:54Z</published>
      <updated>2011-07-16T09:06:55Z</updated>
      <author>
            <name>chris</name>
            <email>chrisrnz@gmail.com</email>
                  </author>

      <category term="ExpressionEngine"
        scheme="http://digitalformula.net/df/category/expressionengine"
        label="ExpressionEngine" />
      <content type="html"><![CDATA[
        <p>
Today I threw together a quick plugin as I couldn't find an easy way of doing what I wanted without putting JavaScript in my templates.&nbsp;&nbsp;The plugin, called 'Entry Age', allows you to specify a message that can be displayed if the entry being viewed is older than a certain age.
</p>

<h2>Why a plugin?</h2>

<p>
I'm assuming that someone else out there will find this useful.&nbsp;&nbsp;I'm sure plugins like this exist already but, if they do, I can't find them.
</p>

<p>
For an example of what the plugin looks like when it finds an outdated entry, please see this article: <a href="http://digitalformula.net/articles/move-expressionengine-to-a-different-server" title="Move ExpressionEngine to a different server" target="_blank">Move ExpressionEngine to a different server</a> (and yes, the content there is actually outdated).

<h2>Can I get it?</h2>

<p>
Of course you can.&nbsp;&nbsp;If you want to download Entry Age and try it out, you can do by clicking the following link: <a href="http://digitalformula.net/downloads/entry_age.zip" title="Download Entry Age 1.0">download Entry Age 1.0 now</a>.
</p>

<p>
Hope it helps someone.
</p> {extended}
      ]]></content>
    </entry>

    <entry>
      <title>Using PuTTY ssh keys on OS X</title>
      <link rel="alternate" type="text/html" href="http://digitalformula.net/df/using-putty-ssh-keys-on-os-x" />
      <id>tag:digitalformula.net,2011:digitalformula.net/1.105</id>
      <published>2011-06-23T12:23:07Z</published>
      <updated>2011-06-23T08:32:08Z</updated>
      <author>
            <name>chris</name>
            <email>chrisrnz@gmail.com</email>
                  </author>

      <category term="Mac &amp; OS X"
        scheme="http://digitalformula.net/df/category/mac-os-x"
        label="Mac &amp; OS X" />
      <content type="html"><![CDATA[
        <p>
As part of helping a friend with some system support soon, I was sent a set of ssh keys so that I can access their Ubuntu servers.&nbsp;&nbsp;The keys, however, are .ppk keys generated by <a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/" target="_blank" title="PuTTY">PuTTY</a>, the popular Windows SSH telnet/ssh client.
</p>

<p>
Unfortunately, the PuTTY keys don't work for me as I'm using OS X ... insert appropriate Mac-hating statement here, if you must.&nbsp;&nbsp;;-)&nbsp;&nbsp;Needless to say, I had to find a way of using those keys so I could access the servers without any problems.
</p>

<p>
Fortunately for me, I've encountered this situation before.&nbsp;&nbsp;While testing some connectivity issues recently I kept getting denied access.&nbsp;&nbsp;The problem is that the keys need to be converted to OpenSSH format before they'll work with command-line ssh in OS X.
</p>

<p>
To fix the issue, you'll need PuTTYGen from the <a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/" target="_blank" title="PuTTY">PuTTY</a> website (don't worry, it's free).&nbsp;&nbsp;If you don't have it already, grab it, and follow the simple steps below (I'll include the step to download, just in case you missed it).
</p>

<p>
<strong>Note:&nbsp;</strong>You'll need access to a Windows machine for the below steps to work.
</p>

<ol>
<li>Download PuTTYGen from the <a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/" target="_blank" title="PuTTY">PuTTY</a> website.</li>
<li>Run PuTTYGen.exe, and open the .ppk file using the open option on the File menu.</li>
<li>From the Conversions menu, export the key in OpenSSH format - it's what you need for the key to work with OS X.</li>
</ol>

<p>
Once you've done all that, you should be able to run ssh from the OS X command line and connect without any problems.
</p>

<p>
<strong>Note:&nbsp;</strong>There are a ton of people who have experienced this issue and nearly every other website will tell you that you need to set the permissions on the .ssh file to 700.&nbsp;&nbsp;In most cases 600 is enough.&nbsp;&nbsp;If you don't do this, you can receive an error like this one:
</p>

<figure>
<img src="http://images.digitalformula.net/entries/2011-03-26-using-putty-ssh-keys-on-os-x/2011-06-23-ssh.jpg" title="ssh Error" alt="ssh Error" />
<figcaption>ssh Error</figcaption>
</figure>

<p>
That's all there is to it - easy.
</p> {extended}
      ]]></content>
    </entry>

    <entry>
      <title>SQL Server 2008 Express R2 Unattended Install</title>
      <link rel="alternate" type="text/html" href="http://digitalformula.net/df/sql-server-2008-express-r2-unattended-install" />
      <id>tag:digitalformula.net,2011:digitalformula.net/1.104</id>
      <published>2011-06-15T09:57:13Z</published>
      <updated>2012-01-04T05:44:14Z</updated>
      <author>
            <name>chris</name>
            <email>chrisrnz@gmail.com</email>
                  </author>

      <category term="Software"
        scheme="http://digitalformula.net/df/category/software"
        label="Software" />
      <content type="html"><![CDATA[
        <p>
Back in March 2009 I wrote an article called &quot;<a href="http://digitalformula.net/articles/how-to-perform-an-unattended-installation-of-sql-server-2008-express" target="_blank" title="SQL Server 2008 Express Unattended Install">SQL Server 2008 Express Unattended Install</a>&quot;&nbsp;&nbsp;It turned out to be one of the most popular articles on Digital Formula (and still is) so, since SQL Server 2008 R2 Express has been released, I figured I'd write an article refresh on how to do the same thing as the original article, but with the latest version.
</p>

<p>
To make the change easy, I'll explain the main things that have changed between 2008 and 2008 R2 from an unattended install perspective.
</p>

<h2>Assumptions</h2>

<ul>
<li>You've already downloaded SQL Server 2008 R2 Express.  This article will assume you're installing the 32-bit (x86) version although I see no reason why the steps below won't work with the 64-bit (x64) version.</li>
<li>Your system meets the <a href="http://msdn.microsoft.com/en-us/library/ms143506.aspx" target="_blank" title="system requirements for SQL Server 2008 R2 Express">requirements for installing SQL Server 2008 R2 Express</a>.&nbsp;&nbsp;Note that this includes installing the <a href="http://www.microsoft.com/downloads/en/details.aspx?familyid=5a58b56f-60b6-4412-95b9-54d056d6f9f4&displaylang=en" target="_blank" title=".NET Framework 3.5 SP1">.NET Framework 3.5 SP1</a>, <a href="http://www.microsoft.com/downloads/en/details.aspx?familyid=5a58b56f-60b6-4412-95b9-54d056d6f9f4&displaylang=en" target="_blank" title="Windows Installer 4.5">Windows Installer 4.5</a> and <a href="http://www.microsoft.com/downloads/en/details.aspx?familyId=6ccb7e0d-8f1d-4b97-a397-47bcc8ba3806&hash=EKrwsUDu6w9ARqR4YGsliX3VUlsbP1CykilvWDyX1NUzHhRM4SyqnGufJbFUZfNX6%2fVhzBwwtS6H6JPBioqgOg%3d%3d" target="_blank" title="Windows Powershell for Windows XP">Windows Powershell</a>.</li>
<li>You are installing from <em>C:\Install\SQL2008</em> (you can change this as necessary but please make sure you update the paths in the examples below).</li>
<li>You'll save your configuration file as <em>C:\Install\sql-2008-express.ini</em></li>
</ul>

<h2>Extracting installation files</h2>

<p>
To get the extracted installation files, run the following command and follow the wizard - easy.&nbsp;&nbsp;Note that I've extracted mine to <em>C:\Install\SQL2008\Extracted</em>.
</p>

<pre class="brush: bat;">C:\Install\SQL2008\SQLEXPRWT_x86_ENU.exe /x</pre>

<h2>Getting the default configuration file</h2>

<p>
This is the key difference between the previous version (2008) and this one (2008 R2).&nbsp;&nbsp;Run the following command either from the command prompt or from the Start &raquo; Run dialog and then follow the steps below <em>carefully</em> - you'll see that we don't actually want to complete the install right now.
</p>

<pre class="brush: bat;">C:\Install\SQL2008\SQLEXPRWT_x86_ENU.exe /UIMODE=Normal /ACTION=INSTALL</pre>

<p>
This will start the installation with all parts of the installation visible.&nbsp;&nbsp;If you just ran the executable, you wouldn't see the screen that shows where the default configuration file is.
</p>

<p>From here, follow the wizard, do a new install and configure the options as per your requirements, making sure that the steps on the left include the item &quot;Ready to Install&quot;.&nbsp;&nbsp;Note that this will only present if you ran the command above to set the UIMODE and ACTION parameters.
</p>

<figure>
<img src="http://images.digitalformula.net/entries/2011-06-15-sql-2008-express-r2-unattended/2011-06-15-sql-install-ready.jpg" title="Ready to install option available" alt="Ready to install option available" />
<figcaption>Ready to install option available</figcaption>
</figure>

{pagebreak}

<p>
If your system is prepared properly, you'll see all items in the prerequisite checks pass successfully.
</p>

<figure>
<img src="http://images.digitalformula.net/entries/2011-06-15-sql-2008-express-r2-unattended/2011-06-15-sql-install-prereqs.jpg" title="Prerequisite checks successful" alt="Prerequisites checks successful" />
<figcaption>Prerequisite checks successful</figcaption>
</figure>

<h2>Important!</h2>

<p>
When you reach the step called &quot;Ready to Install&quot; - <strong>STOP</strong>.&nbsp;&nbsp;Near the bottom of the installation window is a box labelled &quot;Configuration file path:&quot;.&nbsp;&nbsp;Take a copy of this file - you'll need it later.
</p>

<figure>
<img src="http://images.digitalformula.net/entries/2011-06-15-sql-2008-express-r2-unattended/2011-06-15-sql-install-ready-2.jpg" title="Location of configuration file" alt="Location of configuration file" />
<figcaption>Location of configuration file</figcaption>
</figure>

<h2>Cancel the install</h2>

<p>
Click the &quot;Cancel&quot; button now - we're not actually going to complete the install at this point.&nbsp;&nbsp;You could, of course, but the whole point of this article is to install SQL Server 2008 Express R2 without any user input.
</p>

{pagebreak}

<h2>Preparing the configuration file</h2>

<p>
Make the following changes to the ConfigurationFile.ini that you took a copy of.
</p>

<ol>
<li><em>INDICATEPROGRESS=&quot;True&quot;</em> - by default this is set to &quot;False&quot;</li>
<li><em>QUIETSIMPLE=&quot;True&quot;</em> - by default this is set to &quot;False&quot;</li>
<li><strong>Remove</strong> the line that says <em>UIMODE=&quot;Normal&quot;</em>.&nbsp;&nbsp;If this line isn't removed, the installation <strong>will</strong> fail.</li>
</ol>

<p>
For your reference, I've <a href="http://digitalformula.net/downloads/sql2008expressr2-configuration-files.zip" title="Download SQL Server 2008 Express R2 installation configuration files">made the default and modified files available for download</a>.
</p>

<h2>The installation</h2>

<p>
Now that your system is ready, the installation files and configuration files are ready and the changes made, you're ready to run the installation.&nbsp;&nbsp;From above, remember that I'm assuming you're installing from <em>C:\Install\SQL2008</em> and that your configuration file is <em>C:\Install\sql-2008-express.ini</em> - now you just need to run the command below.
</p>

<pre class="brush: bat;">C:\Install\SQL2008\Extracted\setup.exe /CONFIGURATIONFILE=C:\Install\sql-2008-express.ini /IAcceptSQLServerLicenseTerms</pre>

<p>
Take note of the <em>/IAcceptSQLServerLicenseTerms</em> switch - it automatically accepts the <a href="http://en.wikipedia.org/wiki/Software_license_agreement" target="_blank" title="End User License Agreement">EULA</a>.&nbsp;&nbsp;Without this switch on the command line, the install <strong>will</strong> fail.
</p>

<h2>That's it!</h2>

<p>
If you've done everything correctly, SQL Server 2008 Express R2 will install without any user interaction.&nbsp;&nbsp;Please note that my requirements aren't for a completely silent install so this isn't a 100% silent install.&nbsp;&nbsp;You can make it that way by setting the <em>QUIET</em> parameter to &quot;True&quot;, though.
</p>

<p>
If you have any questions about this, please let me know in the comments.&nbsp;&nbsp;Thanks.
</p> {extended}
      ]]></content>
    </entry>

    <entry>
      <title>Delicious bookmarks to Evernote using AppleScript</title>
      <link rel="alternate" type="text/html" href="http://digitalformula.net/df/delicious-bookmarks-to-evernote-using-applescript" />
      <id>tag:digitalformula.net,2011:digitalformula.net/1.103</id>
      <published>2011-06-14T05:19:29Z</published>
      <updated>2011-06-15T18:26:30Z</updated>
      <author>
            <name>chris</name>
            <email>chrisrnz@gmail.com</email>
                  </author>

      <category term="Mac &amp; OS X"
        scheme="http://digitalformula.net/df/category/mac-os-x"
        label="Mac &amp; OS X" />
      <content type="html"><![CDATA[
        <p>
Over the last day or so I've been trying to find a decent alternative to Yahoo's <a href="http://www.delicious.com" target="_blank" title="Delicious">Delicious</a> online bookmarking service.&nbsp;&nbsp;It's a service I've used for many years (since 2006, in fact) and, unfortunately, <a href="http://www.delicious.com/help/transition" target="_blank" title="Delicious transition to AVOS">Yahoo has sold the service to AVOS</a>.&nbsp;&nbsp;To be fair, AVOS does plan to keep Delicious running and also implement improvements but with the purchase of an iPhone 4 it makes sense for me to transition to a service that I can synchronise between all my devices.
</p>

<h2>What is the chosen alternative?</h2>

<p>
I've been a long-time user of <a href="http://www.evernote.com" target="_blank" title="Evernote">Evernote</a> and its ability to sync between Mac (all my hardware), Windows (at work) and iPhone (in my pocket) makes it a sensible choice for the transition.&nbsp;&nbsp;However, I needed to find a way to transfer all 2628 of my bookmarks to Evernote.
</p>

<h2>First attempt</h2>

<p>
My first go was to use the web service from Dr. Palaniraja but that didn't do some of the things I needed.&nbsp;&nbsp;For example:
</p>

<ul>
<li>It didn't keep my tags, despite the website saying it would (this effectively made it useless for me)</li>
<li>It required a lot of manual input.&nbsp;&nbsp;I don't mind this so much but less technical users probably would.</li>
</ul>

<p>
I was looking for an automated way to transfer everything.&nbsp;&nbsp;My chosen method is an AppleScript that I found online at <a href="http://veritrope.com/" target="_blank" title="Veritrope">Veritrope</a>, which I then heavily modified to do more of the things I wanted.
</p>

<p>
My changes are as follows:
</p>

<ul>
<li>The original script verified every URL before adding it to Evernote.&nbsp;&nbsp;Conceptually this is fine but I wanted to offer the option of <em>not</em> doing that.</li>
<li>The original script used the bookmark's URL as the note title.&nbsp;&nbsp;To me this is a little odd so I modified it to use the bookmark's actual title as the note's title, too.</li>
<li>The original script required some manual editing to set your location i.e. Japan, U.S. or outside Japan/U.S.  I'm in Australia which meant manually changing the location.&nbsp;&nbsp;This is easy but I wanted to prompt the user for this information.</li>
<li>The original script saved the bookmark's entire page content as the content of the new note.&nbsp;&nbsp;This is a great idea but I wanted the option of <em>not</em> doing this, if necessary.&nbsp;&nbsp;The main reason for this is so that Evernote's basic account holders don't blow the cap on their monthly usage.</li>
<li>The original script, if verifying URLs, saved all the bad URLs to a single note.&nbsp;&nbsp;I modified mine to save them as individual notes in a special, local-only, notebook called &quot;Bad Bookmark List&quot;.
</ul>

<h2>The script</h2>

<p>
Here's the entire script.&nbsp;&nbsp;All you need to do is:
</p>

<ul>
<li>Export your bookmarks from Delicious using their <a href="https://secure.delicious.com/settings/bookmarks/export" target="_blank" title="Export/Download Delicious Bookmarks">export/download</a> page.</li>
<li>Copy/paste the script below into AppleScript Editor (Mac only!) and run it.</li>
</ul>

<p>
The only manual change necessary, if required, is to change the name of the destination notebooks for the good and bad bookmarks.&nbsp;&nbsp;These two settings are <em>evNotebook</em> and <em>badNotebook</em> respectively.
</p>

<p><strong>Warning:</strong> Be aware that if you run this script over a big bookmark list and select to verify URLs, it may take a <em>long</em> time to run!
</p>

<pre class="brush:applescript;">-- v1.30
-- http://veritrope.com
-- Delicious Bookmark Importer for Evernote
-- February 18, 2011
-- Status, Latest Updates, and Comments Collected at:
-- http://veritrope.com/code/delicious-bookmark-importer-for-evernote/
-- 
-- v2.0
-- June 14th, 2011
-- Chris Rasmussen, digitalformula.net
-- Changes:
-- Added prompt for verifying URL
-- Added prompt for saving notes with actual title as title or URL as title
-- Added prompt for location i.e. U.S. or Japan or everywhere else
-- Added prompt for saving the bookmark or full page as the note's content (recommended for Evernote premium users, only)
-- 		
-- Note : The above prompts would usually be too many but since this script is probably intended to be run once only,
-- more options are better than none
-- 
-- v2.1
-- June 14th, 2011
-- Chris Rasmussen, digitalformula.net
-- Changes from 2.0:
-- Bad bookmarks are now added to a notebook called 'Bad Bookmark list' (createNote method changed to allow that)

-- *** Make changes in this section, only ***

-- title for dialog prompts
property scriptTitle : "Import Delicious bookmarks into Evernote"
-- set the variable below to the name of the Evernote folder to use for imported bookmarks
property evNotebook : "Delicious Import"

-- note for bad bookmarks - local only (won't be synchronised!)
property badNotebook : "Bad Bookmark List"

-- *** Stop editing here, please :) ***

-- firstly, create the 'bad' notebook
-- we do this now because otherwise AppleScript will, by default, create a synchronised notebook (bad idea if heaps of your bookmarks are invalid)
-- also, an error will be thrown if the notebook already exists - to prevent that, we do a quick check to see if a matching notebook can be found
tell application "Evernote"
	if (not (notebook named badNotebook exists)) then
		create notebook badNotebook with type local only
	end if
end tell

-- prompt the user for their location
global formatDates
property locationOptions : {"U.S.", "Japan", "Outside Japan/U.S."}
set location to (choose from list locationOptions with prompt "Please choose your location:" with title scriptTitle) as string

if location = "U.S." then
	set formatDates to "YES"
else if (location = "Japan") then
	set formatDates to "JP"
else
	set formatDates to "NO"
end if

-- verify URLs?
-- if the user responds in the affirmative, all URLs will be verified as working before they're added as notes
-- if the users responds in the negative, URLs are not verified and will be added even if they don't work
global verify
property verifyOptions : {"Yes - Verify all URLs", "No - Just import everything"}
set verifyResult to (choose from list verifyOptions with prompt "Verify URLs before import?" with title scriptTitle) as string

if verifyResult = "Yes - Verify all URLs" then
	set verify to true
else
	set verify to false
end if

-- use bookmark title or URL as new note's title?
-- the original script added notes with the bookmark's URL as the note title
-- this will allow the user to keep this option, if they like, or have the notes' title as the bookmark title (better, in my opinion)
global titleType
property titleOptions : {"Use bookmark's URL", "Use bookmark's title"}
set titleResult to (choose from list titleOptions with prompt "Use bookmark URL or title as note title?" with title scriptTitle) as string

if titleResult = "Use bookmark's URL" then
	set titleType to "url"
else
	set titleType to "title"
end if

-- save the page's full content as the note's content?
-- if the user responds in the affirmative, the page's entire content will be scraped and saved as the note's body
-- this is recommended for Evernote premium users, only
global contentType
property pageOptions : {"Yes - Save full page", "No - Save summary only"}
set pageResult to (choose from list pageOptions with prompt "Save full page as note's content?  This is recommended for Evernote premium users or small bookmark lists, only" with title scriptTitle) as string

if pageResult = "Yes - Save full page" then
	set contentType to "full"
else
	set contentType to "summary"
end if

property linkList : {}
property theTags : {}
property linkExists : ""
property badList : {}

-- Main program begins

-- reset items
set AppleScript's text item delimiters to ""
set linkList to {}
set badList to {}

-- select the Delicious export file
set deliciousFile to (choose file with prompt "Choose Delicious Bookmark Export File")

-- open the Delicious export file
set deliciousData to read deliciousFile
set deliciousBody to my extractBetween(deliciousData, "<dl>", "</dl>")

-- get a list of all the links
set delDelimiter to "<dt>"
set deliciousRAW to read deliciousFile using delimiter delDelimiter
my processLinks(deliciousRAW, linkList)

-- process each link into a seperate webclipped note in Evernote, keeping tags and dates intact
my evernoteImport(linkList, theTags)

-- add bad links to a note containing all the bad URLs
if badList is not {} then
	
	set old_delim to AppleScript's text item delimiters
	set AppleScript's text item delimiters to return
	set badList to badList as text
	set AppleScript's text item delimiters to old_delim
	set badLinks to "List of URLs Returning Errors: " & return & (current date) & return & return & badList as Unicode text
	
	tell application "Evernote"
		create note with text badLinks title "List of URLs Returning Errors" notebook evNotebook
	end tell
end if

-- child methods

-- get the anchor href info
on processLinks(deliciousRAW, linkList)
	repeat with i from 1 to (length of deliciousRAW)
		set theItem to item i of deliciousRAW
		if theItem contains "A HREF" then
			set end of linkList to theItem
		end if
	end repeat
end processLinks

-- process each link
on evernoteImport(linkList, theTags)
	repeat with i from 1 to (length of linkList)
		set theItem to item i of linkList
		set theURL to my extractBetween(theItem, "A HREF=\"", "\"")
		set linkExists to "true" as boolean
		set epochseconds to my extractBetween(theItem, "ADD_DATE=\"", "\"")
		set deliciousTags to my extractBetween(theItem, "TAGS=\"", "\"")
		set itemTitle to my extractBetween(theItem, "\"&gt;", "&lt;/A&gt;")
		-- change the delimiters to parse tags
		set oldDelims to AppleScript's text item delimiters
		set AppleScript's text item delimiters to ","
		set theTags to text items of deliciousTags as list
		-- change the delimiters back to what they were before
		set AppleScript's text item delimiters to oldDelims
		
		-- if the user selected to verify all URLs, the URL will be verified here
		if verify then
			my verify_Link(theURL)
		else
			set linkExists to true
		end if
		
		if linkExists is not false then
			-- add the bookmark to the good list
			if titleType = "title" then
				my createNote(itemTitle, theURL, theTags, epochseconds, evNotebook)
			else
				my createNote(theURL, theURL, theTags, epochseconds, evNotebook)
			end if
			set theTags to {}
		else
			-- add the bookmark to the bad list
			if titleType = "title" then
				my createNote(itemTitle, theURL, theTags, epochseconds, badNotebook)
			else
				my createNote(theURL, theURL, theTags, epochseconds, badNotebook)
			end if
			set theTags to {}
		end if
		
		if verify then
			-- delay is only required if we're verifying all links
			delay 3
		end if
		
	end repeat
end evernoteImport

-- verify working URL, if required
on verify_Link(theURL)
	try
		set the_page to do shell script "curl -siL \"" & theURL & "\""
		set the_code to items 10 thru 12 of the_page as string
		if the_code is greater than 400 then
			set linkExists to "false" as boolean
			copy theURL to the end of badList
		end if
	end try
end verify_Link

-- create the note
on createNote(itemTitle, theURL, theTags, epochseconds, notebookName)
	tell application "Evernote"
		try
			set createDate to my epoch2datetime(epochseconds)
			-- create the note based on user's choice of summary or entire page content
			if contentType = "full" then
				-- save entire page (this is the original script)
				set n to create note from url theURL created createDate notebook notebookName tags theTags
				set source URL of n to theURL
			else
				-- save summary only (new option, good for Evernote basic account holders)
				set n to create note title itemTitle with text theURL created createDate tags theTags notebook notebookName
				set source URL of n to theURL
			end if
		end try
	end tell
end createNote

-- convert UNIX epoch time
on epoch2datetime(epochseconds)
	-- adapted from script found at Erik's Lab (http://erikslab.com/2006/09/05/how-to-convert-an-epoch-time-to-a-meaningful-date-and-time/)
	set myshell1 to "date -r "
	if formatDates is "YES" then
		-- formatted for U.S.
		set myshell2 to " \"+%m/%d/%Y %l:%M %p\"" -- Formatted for U.S.
	else if formatDates is "JP" then
		-- formatted for Japan
		set myshell2 to " \"+%Y/%m/%d %l:%M %p\""
	else
		-- formatted for everyone outside Japan/U.S.
		set myshell2 to " \"+%d/%m/%Y %l:%M %p\""
	end if
	set theDatetime to do shell script (myshell1 & epochseconds & myshell2)
	return date theDatetime
end epoch2datetime

-- extract text between specified delimiters
on extractBetween(SearchText, startText, endText)
	set tid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to startText
	set endItems to text of text item -1 of SearchText
	set AppleScript's text item delimiters to endText
	set beginningToEnd to text of text item 1 of endItems
	set AppleScript's text item delimiters to tid
	return beginningToEnd
end extractBetween</pre>

<p>
Thanks to Justin from Veritrope for the original idea.
</p> {extended}
      ]]></content>
    </entry>

    <entry>
      <title>Pimp My Desktop using GeekTool</title>
      <link rel="alternate" type="text/html" href="http://digitalformula.net/df/pimp-my-desktop-using-geektool" />
      <id>tag:digitalformula.net,2011:digitalformula.net/1.102</id>
      <published>2011-05-21T06:33:29Z</published>
      <updated>2011-05-21T04:18:30Z</updated>
      <author>
            <name>chris</name>
            <email>chrisrnz@gmail.com</email>
                  </author>

      <category term="Mac &amp; OS X"
        scheme="http://digitalformula.net/df/category/mac-os-x"
        label="Mac &amp; OS X" />
      <content type="html"><![CDATA[
        <p>
Continuing with the theme of pimping various aspects of the OS X system configuration, today's article covers how to use <a href="http://projects.tynsoe.org/en/geektool/" target="_blank" title="GeekTool">GeekTool 3</a> to display useful info on your OS X desktop.&nbsp;&nbsp;For those that missed it, one of my recent articles, &quot;<a href="http://digitalformula.net/articles/pimp-my-prompt-like-paul-irish" title="Pimp My Prompt ... like Paul Irish">Pimp My Prompt ... like Paul Irish</a> covered using the <em>.bash_profile</em> script to add some geek bling to your bash prompt - check it out.
</p>

<p>
The idea of GeekTool is to use the often under-utilised desktop area of OS X to display useful info.&nbsp;&nbsp;Some people use it to display images but most use it to run Bash shell commands to interrogate and display various system-level statistics.&nbsp;&nbsp;For example, my desktop looks like this (click for larger version):
</p>

<figure>
<a href="http://images.digitalformula.net/entries/2011-05-21-geektool-desktop/2011-05-21-desktop-large.jpg" class="lightbox"><img src="http://images.digitalformula.net/entries/2011-05-21-geektool-desktop/2011-05-21-desktop.jpg" title="My GeekTool Desktop" alt="My GeekTool Desktop" /></a>
<figcaption>My GeekTool Desktop</figcaption>
</figure>

<p>
Before you ask, the desktop background is an InterfaceLift image called <a href="http://interfacelift.com/wallpaper/details/2455/the_solutionist.html" target="_blank" title="The Solutionist">The Solutionist</a>.&nbsp;&nbsp;:)
</p>

<p>
Now, I’m going to assume that you’ve already downloaded and installed GeekTool 3 from the <a href="http://projects.tynsoe.org/en/geektool/" target="_blank" title="GeekTool">GeekTool homepage</a>.&nbsp;&nbsp;If you haven’t done that already, do it now, please.
</p>

<p>
Once you’ve got it installed, open System Preferences and click the GeekTool preference pane that should now be available.&nbsp;&nbsp;For this article, please drag a &quot;Shell&quot; Geeklet onto your desktop.&nbsp;&nbsp;Configure it any way you’d like in terms of position - for the sake of comparison, the screenshot below shows the settings for my date and weather Geeklet.
</p>

<figure>
<a href="http://images.digitalformula.net/entries/2011-05-21-geektool-desktop/2011-05-21-desktop-labelled-large.jpg" class="lightbox"><img src="http://images.digitalformula.net/entries/2011-05-21-geektool-desktop/2011-05-21-geeklet-config.jpg" title="Date and weather Geeklet settings" alt="Date and weather Geeklet settings" /></a>
<figcaption>Date and weather Geeklet settings</figcaption>
</figure>

{pagebreak}

<p>
Because there are so many sites out there that try and teach Bash scripting and how to do all the stuff inside it, I’m only going to continue from here by showing what each of my scripts looks like.&nbsp;&nbsp;The processes, network traffic and uptime scripts were borrowed in their original form from the <a href="http://www.macosxtips.co.uk/geeklets/" target="_blank" title="Geeklets list">Geeklets list on Mac OS X tips</a>.&nbsp;&nbsp;Credit for those must go to the original authors.&nbsp;&nbsp;Here are the scripts:
</p>

<pre class="brush: bash;" title="System time">date ‘+%H:%M’</pre>

<pre class="brush: bash;" title="CPU Usage">top -l 1 | awk '/CPU usage/ {print "u:", $3, "s:", $5, "i:", $7}’</pre>

<pre class="brush: bash;" title="Day, date, temperature  and humidity"># day
_day=`date +%a | tr '[:lower:]' '[:upper:]'`

# degrees symbol: ˚

# get the temperature and humidity and write them to a temporary file
~/_Applications/lynx/lynx -dump http://www.bom.gov.au/vic/observations/melbourne.shtml | awk '/\[36\]Melbourne/ { print $3 }; /\[36\]Melbourne/ { print $6, "%"; };' > /tmp/weather-temp

_temp=`sed -n 1p /tmp/weather-temp`
_humidity=`sed -n 2p /tmp/weather-temp`

# month
_month=`date +%b`
_date=`date +%d`

# do some checks to make sure data returned for the checks that require an internet connection
if [[ -z $_temp ]]; then
	_temp="-"
fi
if [[ -z $_humidity ]]; then
	_humidity="-"
fi

echo "$_day\t\t\t`echo $_temp | tr -d " "` C"
echo "$_month $_date\t`echo $_humidity | tr -d " "` HUMIDITY" | tr '[:lower:]' ‘[:upper:]’</pre>

<pre class="brush: bash;" title="Disk space">df -hl | grep 'disk0s2' | awk '{print "t:", $2, "f:", $4, "p:", $5; }'</pre>

<pre class="brush: bash;" title="Memory usage">top -l 1 | awk '/PhysMem/ {print "u:", $8, "f:", $10}'</pre>

<p>
The &quot;Start Teh Music ...&quot; widget you see next to the dock is created by <a href="http://bowtieapp.com/" target="_blank" title="Bowtie">Bowtie</a>, definitely the best iTunes notification/info widget app out there.&nbsp;&nbsp;It will change to show the title and artist of the track that’s currently playing, once one starts.&nbsp;&nbsp;I’ve got the Aussie V8 Supercars on the T.V. right now ... no music needed.&nbsp;&nbsp;:)
</p>

<p>
Here’s the same desktop again, this time labelled so that you know where each script is (click for larger version).
</p>

<figure>
<a href="http://images.digitalformula.net/entries/2011-05-21-geektool-desktop/2011-05-21-desktop-labelled-large.jpg" class="lightbox"><img src="http://images.digitalformula.net/entries/2011-05-21-geektool-desktop/2011-05-21-desktop-labelled.jpg" title="My GeekTool Desktop - Labelled" alt="My GeekTool Desktop - Labelled" /></a>
<figcaption>My GeekTool Desktop - Labelled</figcaption>
</figure>

<p>
Granted, my choice of system info, fonts, colours etc is fairly boring and minimal compared to some but they give me what I need without destroying what I reckon is one of the best desktop background images I’ve ever found.
</p> {extended}
      ]]></content>
    </entry>

    <entry>
      <title>A couple more BASH prompt examples</title>
      <link rel="alternate" type="text/html" href="http://digitalformula.net/df/a-couple-more-bash-prompt-examples" />
      <id>tag:digitalformula.net,2011:digitalformula.net/1.101</id>
      <published>2011-05-09T11:41:24Z</published>
      <updated>2011-05-09T07:57:25Z</updated>
      <author>
            <name>chris</name>
            <email>chrisrnz@gmail.com</email>
                  </author>

      <category term="Linux"
        scheme="http://digitalformula.net/df/category/linux"
        label="Linux" />
      <category term="Mac &amp; OS X"
        scheme="http://digitalformula.net/df/category/mac-os-x"
        label="Mac &amp; OS X" />
      <content type="html"><![CDATA[
        <p>
Yesterday I published an article called <a href="http://digitalformula.net/articles/pimp-my-prompt-like-paul-irish" target="_blank" title="Pimp My Prompt ... like Paul Irish">&quot;Pimp My Prompt ... like Paul Irish&quot;</a> in which I showed how to make your BASH prompt similar to the one used by <a href="http://www.paulirish.com/" target="_blank" title="Paul Irish">Paul Irish</a>.
</p>

<p>
I also included a couple of sample prompts that you could use for reference so I figured I’d write a follow-up article that shows what they look like.&nbsp;&nbsp;So, without any further ado, here they are.
</p>

<pre class="brush: bash;" title="Example 1: Green username, blue host, magenta working directory, white git branch">PS1='${GREEN}\u${BLACK}@${CYAN}\h:${MAGENTA}\w${WHITE}`__git_ps1 " (%s)"`\$ ‘</pre>

<p>
The example above uses the short colour codes outlined in the original article and looks like the screenshot below.
</p>

<figure>
<img src="http://images.digitalformula.net/entries/2011-05-09-a-couple-more-bash-prompt-examples/2011-05-09-prompt-green.jpg" title="Green username, blue host, magenta working directory" alt="Green username, blue host, magenta working directory" />
<figcaption>Green username, blue host, magenta working directory</figcaption>
</figure>

<pre class="brush: bash;" title="Example 2: Blue user and host, magenta working directory, white git branch">PS1='\[\033[0;36m\]\u@\h\[\033[01m\]:\[\033[0;35m\]\w\[\033[00m\]\[\033[1;30m\]\[\033[0;37m\]`__git_ps1 " (%s)"`\[\033[00m\]\[\033[0;37m\]\$ '</pre>

<p>
The example above uses the built-in colour codes but can be harder to read.&nbsp;&nbsp;It looks like the screenshot below.
</p>

<figure>
<img src="http://images.digitalformula.net/entries/2011-05-09-a-couple-more-bash-prompt-examples/2011-05-09-prompt-cyan.jpg" title="Blue user and host, magenta working directory, white git branch" alt="Blue user and host, magenta working directory, white git branch" />
<figcaption>Blue user and host, magenta working directory, white git branch</figcaption>
</figure>

<p>
Don’t forget to read the original article, <a href="http://digitalformula.net/articles/pimp-my-prompt-like-paul-irish" target="_blank" title="Pimp My Prompt ... like Paul Irish">&quot;Pimp My Prompt ... like Paul Irish&quot;</a>, if you’re unsure about how to enable the <em>__git_ps1</em> and short colour code commands. 
</p> {extended}
      ]]></content>
    </entry>

    <entry>
      <title>Pimp My Prompt ... like Paul Irish</title>
      <link rel="alternate" type="text/html" href="http://digitalformula.net/df/pimp-my-prompt-like-paul-irish" />
      <id>tag:digitalformula.net,2011:digitalformula.net/1.100</id>
      <published>2011-05-08T11:41:43Z</published>
      <updated>2012-01-04T05:42:44Z</updated>
      <author>
            <name>chris</name>
            <email>chrisrnz@gmail.com</email>
                  </author>

      <category term="Linux"
        scheme="http://digitalformula.net/df/category/linux"
        label="Linux" />
      <category term="Mac &amp; OS X"
        scheme="http://digitalformula.net/df/category/mac-os-x"
        label="Mac &amp; OS X" />
      <content type="html"><![CDATA[
        <p>
There’s been a lot of talk lately about those cool colours that <a href="http://www.paulirish.com/" target="_blank" title="Paul Irish">Paul Irish</a> uses in his videos.&nbsp;&nbsp;If you don't know who Paul Irish is and you dabble in a bit of web design ... well ... shame on you!&nbsp;&nbsp;;-)&nbsp;&nbsp;The things referenced in this article, including the prompt, can be found in Paul's YouTube video entitled <a href="http://www.youtube.com/watch?v=OXpCB3U_4Ig" target="_blank" title="The Build Script of HTML5 Boilerplate: An Introduction">&quot;The Build Script of HTML5 Boilerplate: An Introduction&quot;</a>.&nbsp;&nbsp;Anyway, I think the prompt colours are pretty useful, especially if you’re speedy at navigating your way around the CLI/shell in Linux or OS X and want to see where you are very quickly..&nbsp;&nbsp;They help identify where you are in the file system, whether or not your current working directory is a git branch and, depending on what options you set, whether or not there are untracked files present etc.
</p>

<p>
Here’s what Paul’s prompt looks like (screenshot from the video linked above).
</p>

<figure>
<img src="http://images.digitalformula.net/entries/2011-05-08-pimp-my-prompt-like-paul-irish/2011-05-08-paul-irish-prompt.jpg" title=“Paul Irish’s OS X prompt” alt="Paul Irish’s OS X prompt" />
<figcaption>Paul Irish’s OS X prompt</figcaption>
</figure>

<p>
I believe Paul is using <a href="http://iterm.sourceforge.net/" target="_blank" title="iTerm">iTerm</a>, as am I.&nbsp;&nbsp;Combined with the stuff below, my iTerm configuration looks like this:
</p>

<figure>
<img src="http://images.digitalformula.net/entries/2011-05-08-pimp-my-prompt-like-paul-irish/2011-05-08-iterm.jpg" title=“iTerm Configuration” alt="iTerm Configuration" />
<figcaption>iTerm Configuration</figcaption>
</figure>

<h2>Pimp my prompt!</h2>

<p>
Ok, so you want your prompt to look like that?&nbsp;&nbsp;It’s not that hard, actually.&nbsp;&nbsp;You have to grant me a little latitude, though, as I’m guessing what Paul uses the various CLI prefix symbols for.&nbsp;&nbsp;In this example I’m using an &quot;o&quot; to indicate a working outside a git branch and a <span style="text-decoration: underline;">+</span> to indicate that the current working directory is a git branch.
</p>

<p>
This only works if you’re running an OS X or Linux shell - I’m sure you can do it with Windows but I’m not going to cover that here.
</p>

<h2>Step 1</h2>

<p>
If you haven’t got one already, open or create a file called <em>.bash_profile</em> in your home (~) folder.&nbsp;&nbsp;You might be asking why not use <em>.bashrc</em>?&nbsp;&nbsp;We want the command we’re adding to apply to interactive login shells - <em>.bashrc</em> only applies to interactive non-login shells.&nbsp;&nbsp;There is an exception to this if you're using OS X (like me) - <em>.bash_profile</em> is run for each new Terminal.app window, by default.
</p>

<p>
If a file with that name already exists, make sure you don’t remove anything from it that you want to keep.&nbsp;&nbsp;From here I’m going to explain what each part of my <em>.bash_profile</em> does.&nbsp;&nbsp;The complete file will be shown at the end, including a couple of extra bits.
</p>

<p><strong>Note:</strong>&nbsp;If you’re going to include the git parts, you’ll need to <a href="http://git-scm.com/download" target="_blank" title="Download git source">download the git source</a> and put the file <em>.git-completion</em> somewhere (mine is in my home directory).
</p>

{pagebreak}

<h2>~/.bash_profile Contents</h2>

<p>Run the git completion script so that commands like <em>__git_ps1</em> are available:
</p>

<pre class="brush: bash;"># enable the git bash completion commands
source ~/.git-completion</pre>

<p>Turn on a couple of options for use with the <em>__git_ps1</em> script.&nbsp;&nbsp;Please see the comments in <em>.git-completion</em> for an explanation on what each one does (I don’t want to duplicate their documentation here):
</p>

<pre class="brush: bash;"># enable git unstaged indicators - set to a non-empty value
GIT_PS1_SHOWDIRTYSTATE="."

# enable showing of untracked files - set to a non-empty value
GIT_PS1_SHOWUNTRACKEDFILES="."

# enable stash checking - set to a non-empty value
GIT_PS1_SHOWSTASHSTATE="."

# enable showing of HEAD vs its upstream
GIT_PS1_SHOWUPSTREAM="auto"</pre>

<p>
Set some variables that will be called as shell commands later - these ones are for changing the text colour.&nbsp;&nbsp;I'm not using all these colours in this script but they're useful to know.&nbsp;&nbsp;Note that I found these colours on a Stack Overflow question titled <a href="http://stackoverflow.com/questions/5505302/how-do-i-get-my-iterm-prompt-to-display-differently-when-im-in-a-git-branch" target="_blank" title="How do I get my iTerm prompt to display differently when I'm in a Git branch?">&quot;How do I get my iTerm prompt to display differently when I'm in a Git branch?&quot;</a> - thanks SiegeX.
</p>

<pre class="brush: bash;">BLACK=$(tput setaf 0)
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
YELLOW=$(tput setaf 3)
LIME_YELLOW=$(tput setaf 190)
POWDER_BLUE=$(tput setaf 153)
BLUE=$(tput setaf 4)
MAGENTA=$(tput setaf 5)
CYAN=$(tput setaf 6)
WHITE=$(tput setaf 7)
BRIGHT=$(tput bold)
NORMAL=$(tput sgr0)
BLINK=$(tput blink)
REVERSE=$(tput smso)
UNDERLINE=$(tput smul)</pre>

<p>
Add a function that figures out whether or not you’re in a git branch (for showing the prompt prefix):
</p>

<pre class="brush: bash;"># return the prompt prefix for the second line
function set_prefix {
	BRANCH=`__git_ps1`
	if [[ -z $BRANCH ]]; then
		echo "${NORMAL}o"
	else
		echo "${UNDERLINE}+"
	fi
}</pre>

<p>
Set the prompt itself.&nbsp;&nbsp;Please remember that I’m guessing at Paul’s actual usage but this is pretty close:
</p>

<pre class="brush: bash;"># and here's one similar to Paul Irish's famous prompt ... not sure if this is the way he does it, but it works  :)
# \033[s = save cursor position
# \033[u = restore cursor position

PS1='${MAGENTA}\u${WHITE} in ${GREEN}\w${WHITE}${MAGENTA}`__git_ps1 " on %s"`${WHITE}\r\n`set_prefix`${NORMAL}${CYAN}\033[s\033[60C (`date "+%a, %b %d"`)\033[u${WHITE} '</pre>

{pagebreak}

<p>
An explanation of some of the parts - see the snippet title for a description of what each one does.
</p>

<pre class="brush: bash;" title="Set the text to colour to MAGENTA and show the logged in username">${MAGENTA}\u</pre>

<pre class="brush: bash;" title="Show the current working directory, in GREEN">${GREEN}\w</pre>

<pre class="brush: bash;" title="Show the git branch, if one exists, including enabled options">`__git_ps1 " on %s"`</pre>

<pre class="brush: bash;" title="Rest to WHITE, carriage-return plus line-feed, run prefix function">${WHITE}\r\n`set_prefix`</pre>

<pre class="brush: bash;" title="Change font colour to CYAN">${CYAN}</pre>

<pre class="brush: bash;" title="Save the current cursor position">\033[s</pre>

<pre class="brush: bash;" title="Move the cursor 60 columns to the right and display today's date in parentheses">\033[60C (`date "+%a, %b %d"`)</pre>

<pre class="brush: bash;" title="Restore the cursor position and reset colour to WHITE">\033[u${WHITE}</pre>

<h2>How do I use it?</h2>

<p>
You don’t have to do anything other than have the <em>.bash_profile</em> script in your home directory.&nbsp;&nbsp;BASH will automatically execute it when a BASH shell starts and set everything up for you.
</p>

<h2>And it looks like this ...</h2>

<figure>
<img src="http://images.digitalformula.net/entries/2011-05-08-pimp-my-prompt-like-paul-irish/2011-05-08-chris-prompt.jpg" title=“Chris's version of Paul Irish’s OS X prompt” alt="Chris's version of Paul Irish’s OS X prompt" />
<figcaption>Chris's version of Paul Irish’s OS X prompt</figcaption>
</figure>

<p>
Before you say anything, yes, I'm aware I used a slightly different colour for the date.&nbsp;&nbsp;;-)

<p>
The complete script is available on the last page of this article.
</p>

{pagebreak}

<h2>The complete .bash_profile file</h2>

<p>
Here’s what my complete <em>.bash_profile</em> file looks like.&nbsp;&nbsp;It’s got all the stuff above plus a couple of extra things e.g. setting my PATH, a couple of aliases for common commands I use and two extra PS1 prompt settings that you can use as reference, if you wish.
</p>

<p>
If you use any of the info in this post, please let me know by leaving a comment or using <a href="http://digitalformula.net/pages/contact" title="Contact Me">the contact form</a>.&nbsp;&nbsp;Thanks!

<pre class="brush: bash;">PATH=$PATH:~/Data/Scripts:~/Data/Utils/rar:~/_Applications:~/_Applications/lynx

# alias to quickly show if any Handbrake processes are running
alias hb='sudo ps -aef | grep HandBrakeCLI'

# alias for quick DNS cache flushing
alias fc='sudo dscacheutil -flushcache'

# enable the git bash completion commands
source ~/.git-completion

# enable git unstaged indicators - set to a non-empty value
GIT_PS1_SHOWDIRTYSTATE="."

# enable showing of untracked files - set to a non-empty value
GIT_PS1_SHOWUNTRACKEDFILES="."

# enable stash checking - set to a non-empty value
GIT_PS1_SHOWSTASHSTATE="."

# enable showing of HEAD vs its upstream
GIT_PS1_SHOWUPSTREAM="auto"

BLACK=$(tput setaf 0)
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
YELLOW=$(tput setaf 3)
LIME_YELLOW=$(tput setaf 190)
POWDER_BLUE=$(tput setaf 153)
BLUE=$(tput setaf 4)
MAGENTA=$(tput setaf 5)
CYAN=$(tput setaf 6)
WHITE=$(tput setaf 7)
BRIGHT=$(tput bold)
NORMAL=$(tput sgr0)
BLINK=$(tput blink)
REVERSE=$(tput smso)
UNDERLINE=$(tput smul)

# set the prompt to show current working directory and git branch name, if it exists

# this prompt is a green username, black @ symbol, cyan host, magenta current working directory and white git branch (only shows if you're in a git branch)
# unstaged and untracked symbols are shown, too (see above)
# this prompt uses the short colour codes defined above
# PS1='${GREEN}\u${BLACK}@${CYAN}\h:${MAGENTA}\w${WHITE}`__git_ps1 " (%s)"`\$ '

# this is a cyan username, @ symbol and host, magenta current working directory and white git branch
# it uses the shorter , but visibly more complex, codes for text colours (shorter because the colour code definitions aren't needed)
# PS1='\[\033[0;36m\]\u@\h\[\033[01m\]:\[\033[0;35m\]\w\[\033[00m\]\[\033[1;30m\]\[\033[0;37m\]`__git_ps1 " (%s)"`\[\033[00m\]\[\033[0;37m\]\$ '

# return the prompt prefix for the second line
function set_prefix {
	BRANCH=`__git_ps1`
	if [[ -z $BRANCH ]]; then
		echo "${NORMAL}o"
	else
		echo "${UNDERLINE}+"
	fi
}

# and here's one similar to Paul Irish's famous prompt ... not sure if this is the way he does it, but it works  :)
# \033[s = save cursor position
# \033[u = restore cursor position

PS1='${MAGENTA}\u${WHITE} in ${GREEN}\w${WHITE}${MAGENTA}`__git_ps1 " on %s"`${WHITE}\r\n`set_prefix`${NORMAL}${CYAN}\033[s\033[60C (`date "+%a, %b %d"`)\033[u${WHITE} '

</pre> {extended}
      ]]></content>
    </entry>

    <entry>
      <title>Scheduling AppleScript using iCal</title>
      <link rel="alternate" type="text/html" href="http://digitalformula.net/df/scheduling-applescript-using-ical" />
      <id>tag:digitalformula.net,2011:digitalformula.net/1.98</id>
      <published>2011-04-30T06:30:38Z</published>
      <updated>2011-05-07T02:49:39Z</updated>
      <author>
            <name>chris</name>
            <email>chrisrnz@gmail.com</email>
                  </author>

      <category term="Mac &amp; OS X"
        scheme="http://digitalformula.net/df/category/mac-os-x"
        label="Mac &amp; OS X" />
      <content type="html"><![CDATA[
        <p>
A few days ago I published an article that made my <a href=“http://digitalformula.net/articles/applescript-backup-system” title=“AppleScript backup system”>AppleScript backup ‘system’</a> available for download.&nbsp;&nbsp;One of the things missing from that article was how to schedule the script so it runs backups automatically - I'm going to address that today.
</p>

<p>
There are a ton of ways to accomplish the scheduling a script to run.&nbsp;&nbsp;If you're hardcore you can use <a href="http://en.wikipedia.org/wiki/Cron" title="Cron" target="_blank">Cron</a> (I won't cover that here), you can purchase some scheduling software for OS X or you can do what I do - use iCal.
</p>

<h2>
But iCal is a calendar ... isn't it?
</h2>

<p>
Yes, it is.&nbsp;&nbsp;However, because it's a calendar, you can add events and set reminders for them.&nbsp;&nbsp;See where I’m going with this?&nbsp;&nbsp;Correct - you can run an AppleScript as part of an iCal event’s alarm.&nbsp;&nbsp;If you read the article about my AppleScript backups, you’ll remember that I said that the idea was to do things with built-in apps, if possible.&nbsp;&nbsp;Every OS X installation includes iCal by default so it just makes sense to use it here.
</p>

<h2>
Won’t my calendar get messy?
</h2>

<p>
iCal allows you to setup separate calendars for different types of events so no, it won’t get messy if you don’t want it to.&nbsp;&nbsp;For example, I have a calendar called ‘Backups’ and it holds ... wait for it ... backups.&nbsp;&nbsp;:-)&nbsp;&nbsp;My backup script runs each day at 8:00 p.m. without me having to do anything manually.
</p>

<p>
Here’s an example of what one of my backup events looks like.&nbsp;&nbsp;Note that the event is set to happen <em>15 minutes after</em> the actual backup starts, with the reminder event triggering 15 minutes before that, i.e. at the actual time the backup is to start.
</p>

<figure>
<img src="http://images.digitalformula.net/entries/2011-04-30-scheduling-applescript-using-ical/2011-04-30-ical.jpg" title=“iCal event to run the backup script” alt="iCal event to run the backup script" />
<figcaption>iCal event to run the backup script</figcaption>
</figure>

<p>
It really is that simple.&nbsp;&nbsp;You don’t need anything other than what comes with your OS X installation to do any of this either - that makes it completely free.
</p>

<p>
If you end up using any of this, I’d love to hear about it.&nbsp;&nbsp;Thanks for reading!
</p> {extended}
      ]]></content>
    </entry>

    <entry>
      <title>AppleScript &#8216;Backup System&#8217;</title>
      <link rel="alternate" type="text/html" href="http://digitalformula.net/df/applescript-backup-system" />
      <id>tag:digitalformula.net,2011:digitalformula.net/1.97</id>
      <published>2011-04-28T08:45:04Z</published>
      <updated>2011-04-28T05:04:05Z</updated>
      <author>
            <name>chris</name>
            <email>chrisrnz@gmail.com</email>
                  </author>

      <category term="Mac &amp; OS X"
        scheme="http://digitalformula.net/df/category/mac-os-x"
        label="Mac &amp; OS X" />
      <content type="html"><![CDATA[
        <h2>
Why?
</h2>

<p>
Because I’m in I.T. I’m quite paranoid about my data and its safety.&nbsp;&nbsp;This is partly due to being responsible for the data for companies that would seriously lose hundreds of millions in capital without that data and partly due to losing all my own data many years ago.&nbsp;&nbsp;At the time I was working on a website editor that, after some semi-public testing, I had been informed was better than the best commercial website editor at the time.&nbsp;&nbsp;I lost the code, all the files that related to the project and all my backups ... my backup software had a bug that killed my ability to restore from tape.&nbsp;&nbsp;Sigh.
</p>

<p>
So anyway, I’ve used many methods of backing up my data but I’m overly paranoid about backup software not doing what I want when I *really* want it to and I therefore do my own backups, ‘on the side’, so to speak.
</p>

<h2>
How?
</h2>

<p>
I’m a big fan of doing things as simply as possible and in this case the simplest solution is to take the data I want to backup, archive it in a widely-used format (ZIP) and put it somewhere I can easily get it back.&nbsp;&nbsp;Naturally this means offsite, outside my house, and in today’s world that means in ‘the cloud’.&nbsp;&nbsp;Dropbox, in this case.
</p>

<p>
Now, if you’ve used Dropbox and have given it a bit of a thrashing,  you’ll know that as soon as you throw a LOT of files at it, the indexing process really starts to take over, chewing CPU and disk I/O cycles.&nbsp;&nbsp;For that reason, my solution involving archiving the data into a ZIP file before giving it to Dropbox works nicely.
</p>

<h2>
No, really, how?
</h2>

<p>
My current hardware platform is Mac.&nbsp;&nbsp;For that reason I figured the best way to back things up without installing anything extra was to write an AppleScript to handle things.&nbsp;&nbsp;You might argue that I should’ve written it using standard Unix .sh or Bash script so that I could use it on Linux but that’s not a requirement.&nbsp;&nbsp;Plus, although I wrote this primarily for my own use, I had always planned on making this script publicly available and AppleScript is very easy to understand, even if you’re not a tech-head, like me.&nbsp;&nbsp;Don’t expect a production-quality script as I’m not trying to sell it so please be aware that there are no warranties provided with anything you download from here.
</p>

<h2>
Is it configurable?
</h2>

<p>
A lot of the settings are, yes.&nbsp;&nbsp;However, this is a backup script and I therefore chose to keep a number of things ‘set in concrete’, if that makes any sense.&nbsp;&nbsp;However, being an editable script means that you can just change stuff, if you want.&nbsp;&nbsp;Here’s what you can change.
</p>

<ul>
	<li>Prompt on overwrite, if a destination archive already exists</li>
	<li>The ‘base’ path of your backup destination, by default Dropbox</li>
	<li>The list of paths that need backing up</li>
</ul>

<p>
In my opinion, you don’t really need to change much more than that.&nbsp;&nbsp;:)
</p>
{pagebreak}

<h2>
Can we see the script, now?
</h2>

<p>
Well, OK.&nbsp;&nbsp;Since we’re up to that part, I want to point out a few things.
</p>

<ul>
	<li>If Dropbox isn’t running, a warning will appear.&nbsp;&nbsp;This is simply because I truly believe you should be backing up to an offsite location.</li>
	<li>Old backups are <strong>never</strong>.&nbsp;&nbsp;Did you read that?&nbsp;&nbsp;Make sure you do as the potential for filling up your free 2GB Dropbox is quite real if you choose to backup a LOT of data each time.</li>
	<li>Destination folders are created, if they don’t exist.</li>
	<li>Growl notifications are shown for everything important.</li>
</ul>

<h2>
The Script
</h2>

<p>
One last thing - you can <a href="http://digitalformula.net/downloads/backup.zip" title="Download the backup script">download the script</a>, if you want to read it offline.
</p>

<pre class="brush: applescript;">-- Backup.scpt
--
-- April 2011, Chris Rasmussen
-- http://digitalformula.net | http://twitter.com/digitalformula
--
-- Used to archive specified files to relevant backup folders to a specified folder, preferably Dropbox or some other cloud-based sync service
--
-- The backup is done by archiving source folders so that indexing doesn't take too long (a known issue with Dropbox)

-- set some variables for machine-specific information
-- get the username of the current logged in user
global computerName
set computerName to (computer name of (system info))
global userHome
set userHome to (home directory of (system info))

-- ***
-- *** Makes changes in this section only
-- ***

-- options
global PromptForOverwrite
-- set this to true if you want to prompted before overwriting any existing archived backups in the destination folder
-- since we're using destination folder names based on date *and* time, existing backups shouldn't ever really exist
set PromptForOverwrite to false

-- set this to the parent path of where backups will go
-- unless you change this below, the default is your Dropbox
-- IMPORTANT : if you set this to anything but 'userHome' you MUST make sure a colon (:) is added to the end of the path
global BasePath
set BasePath to userHome & "Dropbox" & ":"

-- create the list of items to backup
-- for readability the list definition has been split onto multiple lines using the 'continuation character' (Option + lower-case L)
-- the first parameter is the name of the application, the second parameter is the full Apple path its files are in
-- please don't put spaces in the application name for now ... sorry
-- this is the same as:
-- set TheBackupList to {{"SnippetsApp", "Snippets"}, {"HazelApp", "Hazel"}}
-- for the downloadable version, the data to be backed up is specified one item per line
--
-- to add a new item to the list, copy the last item onto a new line - make sure the curly braces, commas and carriage returns match!

set TheBackupList to {¬
	{"SnippetsApp", " HD:Users:chris:Library:Application Support:Snippets"}, ¬
	{"HazelApp", " HD:Users:chris:Library:Application Support:Hazel"}, ¬
	{"KeePass", " HD:Users:chris:Data:KeePass"}, ¬
	{"AppleScripts", " HD:Users:chris:Library:Scripts"}, ¬
	{"PrefsFolder", " HD:Users:chris:Library:Preferences"} ¬
		}

-- ***
-- *** That's it - stop editing!
-- ***

-- see if Growl is available on this system
-- this variable is global so that the newBackup class has access to it
global GrowlAvailable
tell application "System Events" to set GrowlAvailable to exists application process "GrowlHelperApp"

if GrowlAvailable then
	-- enable the script to send Growl notifications
	tell application "GrowlHelperApp"
		set the allNotificationsList to {"removed", "success", "aborted", "no_existing", "created"}
		set the enabledNotificationsList to {"removed", "success", "aborted", "no_existing", "created"}
		register as application "Backup Database" all notifications allNotificationsList default notifications enabledNotificationsList icon of application "Script Editor"
	end tell
end if

-- see if Dropbox is available
global DropboxAvailable
tell application "System Events" to set DropboxAvailable to exists application process "Dropbox"

-- see if Dropbox is available
if not DropboxAvailable then
	display dialog "Oops!  Dropbox is either not installed or not running on this computer.  Dropbox is highly recommended as the backup destination so that backup archives are created 'offsite'.\n\nPlease download and install Dropbox from http://www.dropbox.com or, if you've already got it, look into why Dropbox can't be accessed ...k?  :)" buttons {"Ok"} with icon stop with title "Oh no!"
end if

-- class to store settings relating to the objects to be backed up
-- by using a class we can do multiple backups by simple accessing the class and 'running' it
on BackupObject(appName, folderName)
	
	script backupObjectDetails
		
		-- get the current date and format it nicely
		property CurrentDate : (year of (current date)) & "-" & (month of (current date) as integer) & "-" & (day of (current date)) as string
		property CurrentTime : (hours of (current date)) & (minutes of (current date)) & (seconds of (current date)) as string
		
		-- although it's not an explicitly specified configuration option, you can uncomment the following line if you don't want to use destination folders that are named based on date & time
		-- property ApplicationName : appName
		-- if you uncommented the line above, make sure you comment the one below or your changes won't take effect
		property ApplicationName : CurrentDate & "-" & CurrentTime & "-" & appName
		property ApplicationNameShort : appName
		
		property SourceParent : userHome & "Library:Application Support:" as string
		property DestParent : BasePath & "Backups:" & computerName & ":" as string
		
		property SourcePath : folderName
		property DestPath : DestParent & ApplicationName
		
		property AppFolder : folderName
		
		property DestDB : DestPath & ":" & ApplicationName & ".zip"
		property FileCount : 0
		
		-- flag variable to tell the script if it should continue once all conditions are evaluated
		property GoodToGo : false
		
		-- method to copy the master database to the backup folder
		to copyDatabase to destinationFolder
			
			-- try and create the master Backups directory
			try
				tell application "Finder" to set destResults to make new folder at (BasePath as string) with properties {name:"Backups"}
			end try
			
			-- try and create the machine-specific backup directory
			try
				tell application "Finder" to set destResults to make new folder at (BasePath & "Backups" as string) with properties {name:computerName}
			end try
			
			-- first check if the folder containing the source files exists
			-- if it doesn't, we've got nowhere to copy files from
			tell application "Finder" to if exists SourcePath then
				
				-- then check if the destination folder exists
				-- if it doesn't, the script will create it
				tell application "Finder" to if exists DestPath then
					
					-- check if a backup copy of the database file already exists
					-- if it doesn't, the database will be copied immediately
					tell application "Finder" to if exists DestDB then
						
						if PromptForOverwrite then
							
							-- an existing backup does exist
							-- ask the user if they want to remove it first
							set continueResult to display dialog "Archived backup of " & ApplicationName & " database already exists in " & DestPath & ".  Delete existing backup and continue?" buttons {"Yes", "No"} with icon caution with title "Backup already exists"
							if button returned of continueResult is "No" then
								if GrowlAvailable then tell application "GrowlHelperApp" to notify with name "aborted" title "Backup " & ApplicationName & " Database" description ApplicationName & " database backup aborted." application name "Backup Database"
								
								-- don't continue
								set GoodToGo to false
								
							else
								
								-- user specified to remove the existing backup first
								delete file DestDB
								if GrowlAvailable then tell application "GrowlHelperApp" to notify with name "removed" title "Backup " & ApplicationName & " Database" description "Old " & ApplicationName & " database backups removed." application name "Backup Database"
								
								-- ok to continue
								set GoodToGo to true
								
							end if
						else
							-- ok to continue
							set GoodToGo to true
							
						end if
					else
						-- an existing backup doesn't exist so just do the backup now
						if GrowlAvailable then tell application "GrowlHelperApp" to notify with name "no_existing" title "Backup " & ApplicationName & " Database" description "No existing " & ApplicationName & " database backups found." application name "Backup Database"
						
						-- ok to continue
						set GoodToGo to true
						
					end if
				else
					-- destination directory doesn't exist
					-- try and create it then do the copy
					try
						tell application "Finder" to set destResults to make new folder at (BasePath & "Backups:" & computerName as string) with properties {name:ApplicationName}
					on error
						display dialog "Oops!  The destination folder, " & DestPath & ", could not be created.  Please try again later." buttons {"Ok"} with icon stop with title "Oh no!"
						return
					end try
					
					-- ok to continue
					set GoodToGo to true
					
				end if
				
			else
				display dialog "Oops!  The source folder you selected, " & SourcePath & ", ain't there!  Please check it and try again." buttons {"Ok"} with icon stop with title "Oh no!"
				
			end if
			
			if GoodToGo then
				
				-- see if there is more than 1 file in the selected folder
				-- we need to do this so the notifications show the correct file counts when archiving is finished
				tell application "Finder"
					-- create the ZIP file
					do shell script "zip -r " & POSIX path of DestDB & " -9 \"" & POSIX path of SourcePath & "\""
					try
						set SourceData to every item in entire contents of folder SourcePath
						if class of SourceData is list then
							-- the resulting object will be a list if there is more than 1 file
							set FileCount to (count of items in SourceData)
						else
							-- only 1 file exists
							set FileCount to 1
						end if
					on error
						display dialog "No files found in selected folder!"
					end try
				end tell
				
				-- backup successful - time to display some stats
				if GrowlAvailable then tell application "GrowlHelperApp" to notify with name "success" title ApplicationNameShort & " backup successful" description (FileCount as string) & " " & ApplicationNameShort & " files archived successfully" application name "Backup Database"
				
			else
				-- GoodToGo is false
				display dialog "Hmmm you either aborted the backup or something broke while the backup was running.  If you didn't abort, please make sure file permissions are correct and that there aren't any locked files in the source or destination folders then try running the script again ... k?  :)" buttons {"Ok"} with icon stop with title "Oh no!"
				
			end if
			
		end copyDatabase
		
	end script
	
end BackupObject

-- go through the list and backup everything up
-- excessive comments for readability

-- get the number of objects we're backing up
set NumberOfObjects to count of TheBackupList

-- set the list pointer to the first object MINUS 1
-- AppleScripts are 1-based, not 0-based!
set CurrentObject to 0
-- go through the list and do the actual backup part
repeat until CurrentObject is equal to (NumberOfObjects)
	
	-- move the list pointer to the first object
	-- this is done here because of AppleScript's 1-based lists
	set CurrentObject to CurrentObject + 1
	
	-- get the current object containing the name of the app and the path to be backed up
	set TempObject to item CurrentObject of TheBackupList
	
	-- create the backup object that contains all information about what to backup ...
	set TheBackupObject to BackupObject(item 1 of TempObject, item 2 of TempObject)
	-- ... then back it up!
	tell TheBackupObject to copyDatabase to (DestPath of TheBackupObject)
	
	-- rinse and repeat until there's nothing else to wash ... err ... backup
	
end repeat</pre>

<p>
It’s a decent-sized script, huh?&nbsp;&nbsp;There are a boat load of comments so in reality I’d say the script itself isn’t too bad.&nbsp;&nbsp;It really does work, though, I promise.&nbsp;&nbsp;I use it every day to backup the data that’s in this particular script already i.e. my Snippets database, my Hazel configuration, KeePass database, all my AppleScripts and my account preferences.
</p>

<p>
If you do download the script or use it yourself, I’d like to hear about it.&nbsp;&nbsp;Even if you grab it, tear it to shreds, change everything except the idea etc, still let me know.&nbsp;&nbsp;Thanks!
</p> {extended}
      ]]></content>
    </entry>

    <entry>
      <title>Brunswick to Sassafras</title>
      <link rel="alternate" type="text/html" href="http://digitalformula.net/df/brunswick-to-sassafras" />
      <id>tag:digitalformula.net,2011:digitalformula.net/1.96</id>
      <published>2011-04-27T02:14:10Z</published>
      <updated>2011-04-27T21:06:11Z</updated>
      <author>
            <name>chris</name>
            <email>chrisrnz@gmail.com</email>
                  </author>

      <category term="Evolution"
        scheme="http://digitalformula.net/df/category/evolution"
        label="Evolution" />
      <category term="Training"
        scheme="http://digitalformula.net/df/category/training"
        label="Training" />
      <content type="html"><![CDATA[
        <p>
On Saturday Erin &amp; I went for a drive from our place in Brunswick to Sassafras, a small mountain village up in the Dandenong Ranges near Melbourne.&nbsp;&nbsp;Sassafras is a place I had ridden to before, back when I was living in Hawthorn.&nbsp;&nbsp;Back then it was a 75k round trip - not bad for the bike I was on at the time (bone-charring aluminium, for those in the know).
</p>

<p>
After spending the day in the hills I was reminded of how nice the area is up there, and also of the beautiful road conditions.&nbsp;&nbsp;They're smooth, flowing, relatively low-traffic and, on the Mountain Highway side, really not very steep at all.&nbsp;&nbsp;Needless to say, this was enough to get me thinking about biking up there the following day.&nbsp;&nbsp;I knew it'd be close to 100km return but hey, if you don't go, you'll never know what you're missing, right?
</p>

<p>
A good dinner and what seemed to be a pretty good sleep that night prepared me for the 7:30 a.m. start on Sunday morning.&nbsp;&nbsp;The conditions were like nothing I've seen in Melbourne before.&nbsp;&nbsp;It was pretty cold (around 8 degrees Celcius) and completely calm but man ... the mist and fog?&nbsp;&nbsp;Nuts!&nbsp;&nbsp;Visibility at sea level was no more than about 50 metres at any time during the first 2 hours of the ride, making the use of my usual cycling glasses completely redundant.&nbsp;&nbsp;The fog and mist was so thick, in fact, that I just took my glasses off and rode without any until about 45 minutes before arriving home.
</p>

<p>
Riding up Mountain Highway from The Basin to Sassafras really was something else.&nbsp;&nbsp;It’s an easy climb by any standards despite its profile (see below) but the mist caused the sun to be heavily diffused and to cast those amazing shadowy rays that happen when bright sunlight is filtered through trees.&nbsp;&nbsp;Simply awesome and I found myself wishing I had a camera with me.
</p>

<h2>
The Climb
</h2>

<figure>
<img src="http://images.digitalformula.net/entries/2011-04-27-brunswick-to-sassafras/climb.jpg" title="The climb from The Basin to Sassafras" alt="The climb from The Basin to Sassafras" />
<figcaption>The climb from The Basin to Sassafras</figcaption>
</figure>

<p>
Re the ride itself?&nbsp;&nbsp;In all honesty I was half expecting to get some of the way back and hit the wall since 100km is a long ride for me right now.&nbsp;&nbsp;Maybe it was the decent rest but I felt pretty damn good throughout the whole thing.&nbsp;&nbsp;The route from my house to Sassafras is technically uphill the whole way but does roll a lot; that allows for some recovery during the ride.&nbsp;&nbsp;The climb was no problem and I found myself cranking through the middle section at a pretty easy pace.
</p>

<p>
I’ll definitely be doing this ride again very soon and plan to try and make it a regular weekend thing.&nbsp;&nbsp;If you’re in Melbourne and want to join me, fire me an email and I’ll be more than happy to ride with you.&nbsp;&nbsp;:-)
</p>

<p>
<strong>NB:</strong> After posting this and having heard of a hill climb called the &quot;1 in 20&quot; near Melbourne, I realised that the road climb from The Basin shops to Sassafras <strong>is</strong> the &quot;1 in 20&quot; ride ... lol.&nbsp;&nbsp;Next time I go out there I'll have to try it under 20 mins - this time was around 21 mins through the 'official' timed section, I think.
</p>

<h2>
The Ride
</h2>

<p>
Here’s the ride itself from Garmin Connect.&nbsp;&nbsp;The climb from The Basin to Sassafras is pretty obvious, huh?&nbsp;&nbsp;Cool.
</p>

<p>
<iframe width='465' height='548' frameborder='0' src='http://connect.garmin.com:80/activity/embed/81359868'></iframe>
</p> {extended}
      ]]></content>
    </entry>


</feed>
