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

 <title>Craig Russell</title>
 <link href="http://craig-russell.co.uk/atom.xml" rel="self"/>
 <link href="http://craig-russell.co.uk/"/>
 <updated>2015-01-27T13:32:21+00:00</updated>
 <id>http://craig552uk.github.com</id>
 <author>
   <name>Craig Russell</name>
   <email>craig@craig-russell.co.uk</email>
 </author>

 
 <entry>
   <title>How to Use Outlook Web Access in Google Chrome on Linux</title>
   <link href="http://craig-russell.co.uk/2015/01/27/outlook-web-access-on-chrome-linux.html"/>
   <updated>2015-01-27T00:00:00+00:00</updated>
   <id>http://craig552uk.github.com/2015/01/27/outlook-web-access-on-chrome-linux.html</id>
   <content type="html">&lt;p&gt;If, like me, you work at an organisation that uses MS Exchange for their internal email you&#39;re probably familiar with the Outlook Web App (OWA), the web interface to your email account. Users of Chrome on Linux will probably be aware that &lt;a href=&quot;http://help.outlook.com/en-us/140/bb899685.aspx&quot;&gt;OWA doesn&#39;t support that browser/device combination&lt;/a&gt; and are forced to use the crappy &quot;light version&quot; of Outlook.&lt;/p&gt;

&lt;p&gt;However, it is possible to get the fully featured OWA on Chrome, with a few extensions.&lt;/p&gt;

&lt;p&gt;First off install the &lt;a href=&quot;https://chrome.google.com/webstore/detail/user-agent-switcher-for-c/djflhoibgkdhkhhcedjiklpkjnoahfmg&quot;&gt;User-Agent Switcher for Chrome&lt;/a&gt;. This tool will let you make Chrome lie to OWA, making it think your using Chrome on Windows, which is supported.&lt;/p&gt;

&lt;p&gt;After installing, go to the Options for the extension.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;Custom User Agents&lt;/strong&gt; from the left-hand menu&lt;/li&gt;
&lt;li&gt;Create a new User Agent config like this:

&lt;ul&gt;
&lt;li&gt;New User-agent name: &lt;strong&gt;on Windows&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;New User-Agent String: &lt;a href=&quot;http://www.useragentstring.com/pages/Chrome/&quot;&gt;any Chrome UA string for &quot;Windows&quot;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Group: &lt;strong&gt;Chrome&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Append? &lt;strong&gt;Append&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Indicator Flag: &lt;strong&gt;Win&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;You should see your new option listed under &lt;strong&gt;Chrome&lt;/strong&gt;. Next we&#39;ll make Chrome always use this User Agent string when we use OWA.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;Permanent Spoof list&lt;/strong&gt; from the left-hand menu&lt;/li&gt;
&lt;li&gt;Create a new rule like this:

&lt;ul&gt;
&lt;li&gt;Domain: Your OWA domain e.g. &lt;code&gt;email.example.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;User-Agent String: &lt;strong&gt;on Windows&lt;/strong&gt; (the one we just created)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Now if you go to your OWA, the login page shouldn&#39;t force you to use the light version any more.&lt;/p&gt;

&lt;p&gt;But wait, we&#39;re not quite done yet...&lt;/p&gt;

&lt;p&gt;Everything about your email experience in OWA should work fine, unless you try to add an attachment to an email. This is becaue OWA uses a deprecated JavaScript function, &lt;code&gt;showModalDialog&lt;/code&gt;, which &lt;a href=&quot;http://blog.chromium.org/2014/07/disabling-showmodaldialog.html&quot;&gt;Chrome dropped support for last year&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is kinda annoying, but easy to sort out.&lt;/p&gt;

&lt;p&gt;Just install the &lt;a href=&quot;https://chrome.google.com/webstore/detail/showmodaldialog-shim/nmpaogfdjncgofndedhcimbdmnlbpnlg&quot;&gt;showModalDialog shim&lt;/a&gt; extension and problem solved!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Google Analytics Reports in Google Sheets</title>
   <link href="http://craig-russell.co.uk/2014/03/21/google-analytics-in-google-sheets.html"/>
   <updated>2014-03-21T00:00:00+00:00</updated>
   <id>http://craig552uk.github.com/2014/03/21/google-analytics-in-google-sheets.html</id>
   <content type="html">&lt;p&gt;The &lt;a href=&quot;http://googledrive.blogspot.co.uk/2014/03/add-ons.html&quot;&gt;new Add-ons in Google Sheets&lt;/a&gt; allow you to do all sorts of exciting things with spreadsheet data. My favourite (for now) is the Gogole Analytics Add-on, which makes it incredibly easy to pull analytics report data in to a spreadsheet using the Google Analytics API.&lt;/p&gt;

&lt;p&gt;Add-ons are only available in the &lt;a href=&quot;https://support.google.com/drive/answer/3541068?p=help_new_sheets&amp;amp;rd=1&quot;&gt;New Google Sheets&lt;/a&gt;, so if you&#39;re not yet using them hit &quot;Try the new Google Sheets&quot; at the bottom of a spreadsheet.&lt;/p&gt;

&lt;p&gt;To install the Gogole Analytics Add-on hit, &lt;strong&gt;Add-ons&lt;/strong&gt; &gt; &lt;strong&gt;Get Add-ons...&lt;/strong&gt; in the menu. Search for &quot;Google Analytics&quot; in the store, then install it. You&#39;ll probably have to authorise the app to access your drive account.&lt;/p&gt;

&lt;p&gt;Once installed there&#39;ll be options for it on the &lt;strong&gt;Add-ons&lt;/strong&gt; menu.&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Add-ons&lt;/strong&gt; &gt; &lt;strong&gt;Google Analytics&lt;/strong&gt; &gt; &lt;strong&gt;Create New Report&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This will open up a wizard (are they still called that?) to let you configure your first report. Give it a name e.g. &quot;My Report&quot;. Choose the account, property and profile you want to use. And select the metrics and dimentions. If you&#39;re not sure try setting metrics to &lt;strong&gt;&quot;Visits&quot;&lt;/strong&gt; and Dimensions to &lt;strong&gt;&quot;Source/Medium&quot;&lt;/strong&gt;. Then hit &lt;strong&gt;Create Report&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This will create a new worksheet containing the report configuration.&lt;/p&gt;

&lt;p&gt;To run the report click &lt;strong&gt;Add-ons&lt;/strong&gt; &gt; &lt;strong&gt;Google Analytics&lt;/strong&gt; &gt; &lt;strong&gt;Run Reports&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It&#39;ll take a moment or two, then give you a notification. If there are any problems with your report configuration, you&#39;ll see a message here.&lt;/p&gt;

&lt;p&gt;The results of the report will be created in a new worksheet, titled after your report. Now you&#39;ve got the data and can do all the usual spreadsheet magic.&lt;/p&gt;

&lt;p&gt;You can configure multiple reports on the Report Configuration worksheet, they will all be run at the same time and each save their data in a seperate worksheet. Each time you run a report, it&#39;ll overwrite the previous data. Unless you rename a report, in which case it&#39;ll create a new worksheet under that name.&lt;/p&gt;

&lt;h3&gt;Building Reports&lt;/h3&gt;

&lt;p&gt;Getting the data you want in a report can take a bit of trial and error. I&#39;d reccommend using the &lt;a href=&quot;http://ga-dev-tools.appspot.com/explorer/&quot;&gt;Google Analytics Query Explorer&lt;/a&gt; to develop your reports. This tool gives you a configurable interface to the Reporting API. Use it to try out different configurations, then once you&#39;re happy, copy the settings in to the spreadsheet.&lt;/p&gt;

&lt;h3&gt;Working with Dates&lt;/h3&gt;

&lt;p&gt;Use the built-in date functions in Google Sheets to create reports which run over relative time periods. This&#39;ll save you having to manually update the date field every time you run the report. Here&#39;s a few examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Today &lt;code&gt;=TODAY()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;One week ago: &lt;code&gt;=DATE(YEAR(TODAY()),MONTH(TODAY()),DAY(TODAY())-7)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The first day of last month: &lt;code&gt;=DATE(YEAR(TODAY()),MONTH(TODAY())-1,1)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The last day of last month: &lt;code&gt;=DATE(YEAR(TODAY()),MONTH(TODAY()),0)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The first of January last year: &lt;code&gt;=DATE(YEAR(TODAY())-1,1,1)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Formatting Values&lt;/h3&gt;

&lt;p&gt;Google Sheets has extensive formatting options, but sometimes you&#39;ll need to tweak the values returned by the Analytics API to get them to work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Percentage values (e.g. % New Visits, Bounce Rate) need to be divided by 100 to format correctly&lt;/li&gt;
&lt;li&gt;Duration values (e.g. Av. Time On Site) need to be divided by 86400 (seconds in a day) to format correctly.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Problems&lt;/h3&gt;

&lt;p&gt;There is a bug in the new Google Sheets, which prevents charts from appearing in PDF exports or when printing worksheets. This is a bit annoying if you want to distribute reports. Charts are included in exported XLSX documents, but the formatting can get a bit messed up sometimes.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Missing Blobs in Git</title>
   <link href="http://craig-russell.co.uk/2014/01/11/dangling-blobs-in-git.html"/>
   <updated>2014-01-11T00:00:00+00:00</updated>
   <id>http://craig552uk.github.com/2014/01/11/dangling-blobs-in-git.html</id>
   <content type="html">&lt;p&gt;I&#39;ve just had to fix a missing blob in a repo. Here&#39;s how I did it.&lt;/p&gt;

&lt;p&gt;you can see exactly what&#39;s missing with &lt;code&gt;git fsck&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; git fsck --full
Checking object directories: 100% (256/256), done.
Checking objects: 100% (137/137), done.
missing blob 2d31815dd6357b5c7573a4eebc6792b168b4d6a4
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We need to find which file the blob refers to.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; git ls-tree -r HEAD | g 2d31815dd6357b5c7573a4eebc6792b168b4d6a4
100644 blob 2d31815dd6357b5c7573a4eebc6792b168b4d6a4  lib/oauth2client/crypt.py
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we can reinstate it.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; git hash-object -w lib/oauth2client/crypt.py
2d31815dd6357b5c7573a4eebc6792b168b4d6a4
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So everything should be ok again.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; git fsck --full
Checking object directories: 100% (256/256), done.
Checking objects: 100% (137/137), done.
&lt;/code&gt;&lt;/pre&gt;
</content>
 </entry>
 
 <entry>
   <title>API Keys with Git Stash</title>
   <link href="http://craig-russell.co.uk/2013/11/21/api-keys-with-git-stash.html"/>
   <updated>2013-11-21T00:00:00+00:00</updated>
   <id>http://craig552uk.github.com/2013/11/21/api-keys-with-git-stash.html</id>
   <content type="html">&lt;p&gt;Working with API keys in git repositories can be a pain. You need the keys to test your project, but you don&#39;t want to publish them to the world.
This gets even more confusing when you have multiple versions of the keys that you are working with.
The &lt;code&gt;stash&lt;/code&gt; command in git is a great tool for solving this problem.&lt;/p&gt;

&lt;p&gt;The first step is to keep your API keys in a seperate file from the rest of your code. How you do this will be different depending what language, framework, envirenment &amp;amp;c. you use. For this demonstration I&#39;ll use python.&lt;/p&gt;

&lt;p&gt;Here we have a simple program consisting of two files.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# config.py
API_KEY = &quot;__YOUR_API_KEY__&quot;&lt;/code&gt;&lt;/pre&gt;


&lt;pre&gt;&lt;code&gt;# app.py
import config
print config.API_KEY&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;We can commit these changes to our repo together.
(NB: there may also be an app.pyc file, but we can &lt;a href=&quot;http://git-scm.com/docs/gitignore&quot;&gt;easily ignore this&lt;/a&gt;)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git add config.py app.py
$ git commit -m &quot;Basic application with config&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can edit the config file to contain our private API key&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# config.py
API_KEY = &quot;abc123_development_key&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And we&#39;ll also make some changes to our app.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# app.py
import config
print &quot;This is your API key:&quot;
print config.API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we can commit chanes to the app file, leaving the config file change uncommitted.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git add app.py
$ git commit -m &quot;Improved app&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So far, so simple. But what if we want to have multiple versions of our api keys?
This is where &lt;a href=&quot;http://git-scm.com/docs/git-stash&quot;&gt;git stash&lt;/a&gt; comes in handy.
The stash command allows you to save uncommited changes to one side so that you can work without them, then reapply these changes later.&lt;/p&gt;

&lt;p&gt;Lets stash our changed config file.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git stash save &quot;Development API Key&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we save a different configuration.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# config.py
API_KEY = &quot;abc123_production_key&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And stash this change too.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git stash save &quot;Production API key&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can list all our stashes.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git stash list
stash@{0}: On master: Production API Key
stash@{1}: On master: Development API Key
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now can can easily swap between different versions of the config file.&lt;/p&gt;

&lt;p&gt;Applying production key from stash:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git stash apply stash@{0}&lt;/code&gt;&lt;/pre&gt;


&lt;pre&gt;&lt;code&gt;# config.py
API_KEY = &quot;abc123_production_key&quot;&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Applying development key from stash: &lt;br/&gt;
(Note you must revert the previous change first)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git checkout config.py
$ git stash apply stash@{1}&lt;/code&gt;&lt;/pre&gt;




&lt;pre&gt;&lt;code&gt;# config.py
API_KEY = &quot;abc123_development_key&quot;&lt;/code&gt;&lt;/pre&gt;



</content>
 </entry>
 
 <entry>
   <title>JavaScript - How to Iterate Arrays Correctly</title>
   <link href="http://craig-russell.co.uk/2013/10/15/javascript-arrays-correctly.html"/>
   <updated>2013-10-15T00:00:00+00:00</updated>
   <id>http://craig552uk.github.com/2013/10/15/javascript-arrays-correctly.html</id>
   <content type="html">&lt;p&gt;There are several different ways to iterate over Arrays in JavaScript.
Each of these can behave differently when there are undefined values.
Here, I demonstrate each and explain their behaviour.&lt;/p&gt;

&lt;p&gt;For these examples, I&#39;m using the JS console in Chrome Dev Tools.
Other browsers may format responses differently.&lt;/p&gt;

&lt;p&gt;First off, create an Array with an explicitly set &quot;undefined&quot; element.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; a = [&#39;zero&#39;,&#39;one&#39;,undefined,&#39;three&#39;]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then add another element at a higher index.
You must create it this way, you&#39;ll see why in a bit.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; a[5] = &#39;five&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When we inspect the Array, we can see the two undefined elements.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; a
  [&quot;zero&quot;, &quot;one&quot;, undefined, &quot;three&quot;, undefined × 1, &quot;five&quot;]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice that the element at &lt;code&gt;a[4]&lt;/code&gt; is shown as &lt;code&gt;undefined × 1&lt;/code&gt; not simply &lt;code&gt;undefined&lt;/code&gt;.
This subtle difference tells us that this is an implicit undefined value in the Array, meaning it doesn&#39;t actually exist in memory.
Whereas the &lt;code&gt;undefined&lt;/code&gt; value at &lt;code&gt;a[2]&lt;/code&gt; was explicitly defined, so does exist in memory.&lt;/p&gt;

&lt;p&gt;Now we can see how different iterators handle these different &quot;undefined&quot; values.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;The first examines every index from 0 up to the largest index in the array.
Because indices in Arrays are non-sequential, &lt;code&gt;Array.length&lt;/code&gt; returns the highest index + 1.
So this iterator examines the full range of potential indices, returning the &lt;code&gt;undefined&lt;/code&gt; value it finds in the element at &lt;code&gt;a[2]&lt;/code&gt; and (crucially, but subtly different) returning undefined when it finds no element at &lt;code&gt;a[4]&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; for(var i=0, len=a.length; i&amp;lt;len; i++){ console.log(a[i]) }
  zero
  one
  undefined
  three
  undefined
  five
&lt;/code&gt;&lt;/pre&gt;

&lt;hr /&gt;

&lt;p&gt;The second examines each index incrementally from 0 upwards.
Because the assignment of each array value to a variable is also the test to continue the for loop, the iterator stops when it encounters the first &lt;code&gt;undefined&lt;/code&gt; value (Try &lt;code&gt;!!(e=a[1])&lt;/code&gt; and &lt;code&gt;!!(e=a[2])&lt;/code&gt; in your console).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; for(var i=0,e; e=a[i++];){ console.log(e) }
  zero
  one
&lt;/code&gt;&lt;/pre&gt;

&lt;hr /&gt;

&lt;p&gt;The third iterates over indices only.
So this only returns explicitly defined elements (including &lt;code&gt;a[2]&lt;/code&gt;) and ignores the implicit undefined element.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; for(var i in a){ console.log(a[i]) }
  zero
  one
  undefined
  three
  five
&lt;/code&gt;&lt;/pre&gt;

&lt;hr /&gt;

&lt;p&gt;At first glance it may seem weird that these iterators can behave so differently (especially to developers coming to JS from other languages).
But when we understand the nature of non-sequential indices in Arrays, how variables can be created with &lt;code&gt;undefined&lt;/code&gt; values and type-casting of &lt;code&gt;undefined&lt;/code&gt; values to &lt;code&gt;Boolean&lt;/code&gt;, the necessity of these different techniques becomes clear. And we realise that there is no &quot;correct&quot; way to iterate JavaScript Arrays.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>A New Direction for Easy Open Data</title>
   <link href="http://craig-russell.co.uk/2013/08/29/new-direction-for-easy-open-data.html"/>
   <updated>2013-08-29T00:00:00+00:00</updated>
   <id>http://craig552uk.github.com/2013/08/29/new-direction-for-easy-open-data.html</id>
   <content type="html">&lt;p&gt;About 6 months a go I published &lt;a href=&quot;http://app.easyopendata.com&quot;&gt;Easy Open Data&lt;/a&gt;, a tool to make it easy to publish custom-formatted open data from Google Spreadsheets. The &lt;a href=&quot;/2013/03/11/thank-you-wonderful-product-launch.html&quot;&gt;response I received was wonderful&lt;/a&gt;, and it has been gone on to be used by people to open up all sorts of interesting data.&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p&gt;Member pages now widely-updated. Twitter/Facebook links added thanks to &lt;a href=&quot;http://t.co/FHkFTbyI8g&quot;&gt;http://t.co/FHkFTbyI8g&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/gavinsblog&quot;&gt;@gavinsblog&lt;/a&gt; (eg: &lt;a href=&quot;http://t.co/Fp2cSlfRSx&quot;&gt;http://t.co/Fp2cSlfRSx&lt;/a&gt; )&lt;/p&gt;&amp;mdash; kildarestreet.com (@KildareStreet) &lt;a href=&quot;https://twitter.com/KildareStreet/statuses/328910661696487425&quot;&gt;April 29, 2013&lt;/a&gt;&lt;/blockquote&gt;


&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;


&lt;p&gt;This project attracted the attention &lt;a href=&quot;http://www.groupsia.org/about/&quot;&gt;Michael Roberts&lt;/a&gt; who works with International Development agencies. He saw that a tool like this was ideal for cash poor, time poor, NGOs who are required to publish aid spend information in the &lt;a href=&quot;http://www.aidtransparency.net/&quot;&gt;IATI&lt;/a&gt; standard he helped to develop. Together we put forward a funding bid for a project to develop the tool, to promote and support it&#39;s use among the ID community. Unfortunately we didn&#39;t receive the funding we needed.&lt;/p&gt;

&lt;p&gt;So, that&#39;s the past. Now I want to talk about the future.&lt;/p&gt;

&lt;p&gt;Despite this disappointing set-back, we are both still very committed to developing the tool and promoting it&#39;s use.&lt;/p&gt;

&lt;p&gt;I have decided to rewrite the code base from scratch, there are a few reasons for this. Some of the feedback I&#39;ve had from users has identified some incredibly useful features that I hadn&#39;t considered in the initial version. To deliver these would require some fairly fundamental changes to the tool. Rather than chopping around the already messy code base, it&#39;s seemed a good idea to start over.&lt;/p&gt;

&lt;p&gt;I also wanted to move the product to use &lt;a href=&quot;http://ckan.org&quot;&gt;Google App Engine&lt;/a&gt;. Given that the tool leans so heavily on Google Drive, I thought it reasonable to move closer to that eco-system. Easy Open Data is written in Ruby. As GAE only supports Java, Python and Go, this would have to change. To me Python was the most sensible choice, its a common language among open data enthusiasts, with a strong data mining heritage and used in high-profile products like &lt;a href=&quot;http://ckan.org&quot;&gt;CKAN&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We will be publishing the tool under an open source licence (TBD, but probably &lt;a href=&quot;http://opensource.org/licenses/MIT&quot;&gt;MIT&lt;/a&gt;). At present two releases are planned.&lt;/p&gt;

&lt;p&gt;Version 0.1 will be the first open release of the code base and is planned for November. This version of the tool will be minimally functional, in a fit state for developers to begin experimenting with, but not end users.&lt;/p&gt;

&lt;p&gt;Version 0.2 will be a more polished, featureful, release. The first that is fit for end users. This can be expected early next year.&lt;/p&gt;

&lt;p&gt;You can see track the development of these releases and planned features on the &lt;a href=&quot;https://github.com/opendatapress/open_data_press/issues&quot;&gt;issue tracker on GitHub&lt;/a&gt;. If you have any suggestions or thoughts, feel free to add them there.&lt;/p&gt;

&lt;p&gt;The last big development is the name. I chose &quot;Easy Open Data&quot; without much forethought (I&#39;m no marketeer). But I always felt that this name fails to explain that this is a tool for publishing open data. I also felt that a new name would help to differentiate this new incarnation of the tool from the previous one.&lt;/p&gt;

&lt;p&gt;The new tool is called &lt;strong&gt;Open Data Press&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&quot;Easy Open Data&quot; will, from now on, only refer to the legacy version.&lt;/p&gt;

&lt;p&gt;But what of this legacy? Over the past few months Easy Open Data has attracted a reasonably sized user-base. Some of whom have made impressive use of the tool. If you are among them, I&#39;ll be contacting you in the coming weeks. Asking for your input about the future of EOD and inviting you to join the new &lt;strong&gt;Open Data Press&lt;/strong&gt; project.&lt;/p&gt;

&lt;p&gt;Lastly, I&#39;d like to thank everyone who&#39;s offered their support of this project so far. I&#39;m thrilled by how the concept has resonated so well with so many people. Your feedback has been invaluable. I&#39;m really excited for the future of this project, and I can&#39;t wait for you to &lt;a href=&quot;https://github.com/opendatapress/open_data_press/issues&quot;&gt;see what we&#39;ve got planned&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Unit Testing Third-Party REST APIs in Python</title>
   <link href="http://craig-russell.co.uk/2013/08/06/unit-testing-rest-apis-with-webapp2.html"/>
   <updated>2013-08-06T00:00:00+00:00</updated>
   <id>http://craig552uk.github.com/2013/08/06/unit-testing-rest-apis-with-webapp2.html</id>
   <content type="html">&lt;p&gt;I&#39;ve wrestled with this problem for some time, and finally cracked it. Here&#39;s how to write unit tests for methods that use third-party REST APIs.&lt;/p&gt;

&lt;p&gt;The principle is actually fairly basic, in your tests you have to &quot;mock&quot; the role of the third party in any requests. So for an oAuth2 authentication handshake, you have to play the role of the identity provider. This sounds simple enough, but figuring out how to implement it can be a real pain.&lt;/p&gt;

&lt;p&gt;I&#39;ve got a project that makes use of various Google APIs. Some of these are supported by the &lt;a href=&quot;https://developers.google.com/api-client-library/python/&quot;&gt;Google API Client python libraries&lt;/a&gt; but some aren&#39;t. In those cases I use &lt;a href=&quot;https://code.google.com/p/httplib2/&quot;&gt;httplib2&lt;/a&gt; directly and parse the responses myself. To simplify the handling of authentication across both I use the &lt;a href=&quot;https://code.google.com/p/google-api-python-client/&quot;&gt;oAuth2Client libraries&lt;/a&gt; also.&lt;/p&gt;

&lt;p&gt;To write unit tests for my project, I&#39;ve had to mock responses for all these different API requests.&lt;/p&gt;

&lt;p&gt;Mocking requests basically means overriding the bit of code that sends a request out to a server. Instead of making a request to the third party, you return a dummy response, formatted to pass any verification in the client library.&lt;/p&gt;

&lt;p&gt;The libraries I&#39;m using use &lt;a href=&quot;https://code.google.com/p/httplib2/&quot;&gt;httplib2&lt;/a&gt; behind the scenes, as do many (most?) python REST API libraries. Overriding the &lt;code&gt;request&lt;/code&gt; method, I can return a dummy response to ensure that in a test environment, I control the responses.&lt;/p&gt;

&lt;p&gt;This is my mock http client class. The &lt;code&gt;request&lt;/code&gt; method returns an appropriate response for recognised URIs. For unrecognised URIs a message is logged, highlighting the URI that I need to mock a response for. It also returns an empty &lt;code&gt;Response&lt;/code&gt; object, so I don&#39;t get distracted by &lt;code&gt;NoneType&lt;/code&gt; errors.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from httplib2 import Response
import logging

class MockHttp(object):
    def request(self, uri, method=&quot;GET&quot;, body=None, headers=None, redirections=1, connection_type=None):

        if &#39;https://accounts.google.com/o/oauth2/token&#39; in uri:
            headers = {&#39;status&#39;: &#39;200&#39;}
            body = &#39;{&quot;access_token&quot;:&quot;dummy_token&quot;}&#39;
            return Response(headers), body

        logging.error(&quot;No response for &#39;%s&#39;&quot; % uri)
        return Response({}), &#39;&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In actual projects I keep the response body content in seperate files as some of them can be quite large. I&#39;ve left that part out for brevity.&lt;/p&gt;

&lt;p&gt;Using it in a unit test is very straight forward. Simply replace the http client instance in your application with the mock client. In this example &lt;code&gt;main&lt;/code&gt; is my &lt;a href=&quot;https://webapp-improved.appspot.com/&quot;&gt;WebApp2&lt;/a&gt; application and &lt;code&gt;google_api&lt;/code&gt; is my wrapper library for Google API calls.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import unittest
from tests.utils import MockHttp
import main
import google_api

class TestAuthentication(unittest.TestCase):

    def test_oauth2callback(self):
        # Replace http client in wrapper library with mock client
        google_api.httplib2.Http = MockHttp
        uri = &#39;/auth/oauth2callback?code=dummy_code&#39;
        response = main.app.get_response(uri)
        self.assertEqual(response.status_int, 200)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&#39;s pretty much it.&lt;/p&gt;

&lt;p&gt;Can&#39;t believe it too me so long to figure this out.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Semantic HTML is the Gateway Drug to Open Data</title>
   <link href="http://craig-russell.co.uk/2013/08/04/semantic-html-gateway-drug-to-open-data.html"/>
   <updated>2013-08-04T00:00:00+00:00</updated>
   <id>http://craig552uk.github.com/2013/08/04/semantic-html-gateway-drug-to-open-data.html</id>
   <content type="html">&lt;p&gt;James Padolsey &lt;a href=&quot;http://james.padolsey.com/general/semantic-html-is-dying/&quot;&gt;says that semantic HTML is dying&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;What happened to semantic HTML?
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;He&#39;s right.&lt;/p&gt;

&lt;p&gt;For a while the semantic web was all anyone was talking about. You couldn&#39;t turn around without hearing about how important microformats were, or the &lt;code&gt;rel&lt;/code&gt; attribute. Remember the fight over the HTML5 &lt;code&gt;datetime&lt;/code&gt; attribute?&lt;/p&gt;

&lt;p&gt;People used to care about this stuff.&lt;/p&gt;

&lt;p&gt;Now, not so much.&lt;/p&gt;

&lt;p&gt;Now people care about linked open data (which they should, by the way, I certainly do). But in the fuss, good old semantic HTML has been forgotten. It&#39;s easy to see why. Linked open data is sexy and exciting, everyone cares about linked open data. Hell, some of the most powerful Governments in the world care about linked open data!&lt;/p&gt;

&lt;p&gt;In contrast, engouraging people to write better markup just isn&#39;t exciting enough.&lt;/p&gt;

&lt;p&gt;But it is still important.&lt;/p&gt;

&lt;p&gt;Very important.&lt;/p&gt;

&lt;p&gt;Because semantic HTML is the gateway drug for open data.&lt;/p&gt;

&lt;p&gt;Many organisations are still unable to contribute to the linked open data project. For them time, resources, understanding, will, exposure and all sorts of other barriers prevent them for &#39;making the leap&#39; in to open data - the concept is too alien.&lt;/p&gt;

&lt;p&gt;But semantic HTML. That&#39;s easier step to take.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/cgutteridge&quot;&gt;Chris Gutteridge&lt;/a&gt; says that, in putting their information online, organisations are already doing open data, they&#39;re just doing it badly.&lt;/p&gt;

&lt;p&gt;Semantic HTML is not doing open data well, but it &lt;em&gt;is&lt;/em&gt; doing open data a little less badly.&lt;/p&gt;

&lt;p&gt;And &quot;HTML done a little less badly&quot; &amp;times; &quot;a lot of online information&quot; = &quot;a much better web&quot;.&lt;/p&gt;

&lt;p&gt;So, stay enthused about linked open data, but don&#39;t forget that good old HTML still has a part to play.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.S.&lt;/em&gt; The &lt;a href=&quot;/2013/01/14/argue-for-seo-not-open-data.html&quot;&gt;SEO argument&lt;/a&gt; also helps too.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>How to store Visitor ID in Google Analytics</title>
   <link href="http://craig-russell.co.uk/2013/07/29/ga-visitor-id.html"/>
   <updated>2013-07-29T00:00:00+00:00</updated>
   <id>http://craig552uk.github.com/2013/07/29/ga-visitor-id.html</id>
   <content type="html">&lt;p&gt;Google analytics doesn&#39;t store records for each individual visitor, but with a bit of JavaScript magic, it can be done.&lt;/p&gt;

&lt;p&gt;Google Analytics uses several cookies to help monitor visitors on your site, among the data stored in these is a &lt;a href=&quot;http://www.analytics-ninja.com/blog/2011/12/how-unique-are-unique-visitors-in-google-analytics.html&quot;&gt;visitor identifier&lt;/a&gt;.
This is a unique number that GA uses but doesn&#39;t store. It is possible to read this value out of the cookie and push it back up to GA in a custom variable, where it can be used in reports.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/craig552uk/6103720.js&quot;&gt;&lt;/script&gt;


&lt;p&gt;Note that the &lt;code&gt;_setCustomVar&lt;/code&gt; parameter is wrapped in a function, so that it isn&#39;t called until after the GA code has run.
This ensures that the cookie has already been set before trying to read it.&lt;/p&gt;

&lt;p&gt;On it&#39;s own this is interesting information, but it&#39;s made all-the-more useful when &lt;a href=&quot;http://cutroni.com/blog/2011/05/05/merging-google-analytics-with-your-data-warehouse/&quot;&gt;tied together with your CRM or data warehouse&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>We Need a Longer View of the Content Lifecycle</title>
   <link href="http://craig-russell.co.uk/2013/07/04/we-need-a-longer-view-of-content-lifecycle.html"/>
   <updated>2013-07-04T00:00:00+00:00</updated>
   <id>http://craig552uk.github.com/2013/07/04/we-need-a-longer-view-of-content-lifecycle.html</id>
   <content type="html">&lt;p&gt;Recently I&#39;ve been trying to understand different content management strategies and the implications these have for the underlying technology. Most of what I&#39;ve read fails to consider the long-term utility of content, considering only the newest to be useful. We need to develop a longer view of the life of web content. We should plan for content to live, not for years, but centuries.&lt;/p&gt;

&lt;p&gt;There are &lt;a href=&quot;https://en.wikipedia.org/wiki/Web_content_lifecycle&quot;&gt;no shortage of opinions&lt;/a&gt; about how you &lt;em&gt;should&lt;/em&gt; be managing your web content. Most models of the content life-cycle focus on the generation and optimisation of web content. Typically this process focusses on the newest content, while older content is forgotten and allowed to sink in to obscurity. Unvalued and unloved, the effort put in to managing content is squandered in the first few weeks of it&#39;s life.&lt;/p&gt;

&lt;p&gt;If your site has been around for long enough, a quick glance at your analytics will show you that somewhere out there, people do still value your old content. People are asking questions and finding the answers you provided years ago. Strangely many organisations seem blind to the value their old content has down the long-tail of SEO.&lt;/p&gt;

&lt;p&gt;Many modern CMS&#39; allow content to be shown at multiple locations in a site. A single content item can be combined with others and presented differently. When old content can be presented in new ways, it can attract new visitors and encourage old ones to explore new areas of the site. In this way old content can be re-purposed to serve new goals.&lt;/p&gt;

&lt;p&gt;Clearly organisations should value their older content and redeploy it in support of their present objectives. But I want to take a longer view of the life of content.&lt;/p&gt;

&lt;p&gt;Libraries and museums house books and texts that are centuries, even millennia, old. These are valuable records of people and knowledge that may otherwise be lost to history. And until a couple of decades ago most information was recorded in the same way, on paper, in books, journals and catalogues.&lt;/p&gt;

&lt;p&gt;The ease that we can now publish online has seen an explosion in the amount of information we are making available to the world. However, the rate at which content is being created is likely only matched by the rate at which it is lost. Server moves, lost backups, incompatible file formats, budget cuts and wilful deletion are just a few reasons why organisations fail to preserve their old content.&lt;/p&gt;

&lt;p&gt;Projects like the &lt;a href=&quot;http://archive.org/web/web.php&quot;&gt;Wayback Machine&lt;/a&gt; and the &lt;a href=&quot;http://www.webarchive.org.uk/ukwa/&quot;&gt;UK Web Archive&lt;/a&gt; take snapshots of parts of the web. But we cannot blindly defer this responsibility to these organisations. It would be a real tragedy if future historians look back upon this time, when publishing was never more accessible, to find so few records of our lives. How sad it would be if an organisational archive were to hold decades of records from before the millennium, but nothing after. We have to take responsibility for the long-term life of our content.&lt;/p&gt;

&lt;p&gt;This post is long enough, so I&#39;ll save my thoughts on how we might approach these problems for another night.&lt;/p&gt;
</content>
 </entry>
 

</feed>