<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.2" -->
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	>

<channel>
	<title>Patrick Collison's Blog</title>
	<link>http://collison.ie/blog</link>
	<description>I hate self-referential taglines</description>
	<pubDate>Sun, 27 Jun 2010 21:30:29 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.2</generator>
	<language>en</language>
			<item>
		<title>Tracing memory leaks in Ruby</title>
		<link>http://collison.ie/blog/2010/06/tracing-memory-leaks-in-ruby</link>
		<comments>http://collison.ie/blog/2010/06/tracing-memory-leaks-in-ruby#comments</comments>
		<pubDate>Sun, 27 Jun 2010 21:10:45 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://collison.ie/blog/2010/06/tracing-memory-leaks-in-ruby</guid>
		<description><![CDATA[A project I&#8217;m working on at the moment has a lot of long-lived objects, and we want to make sure that everything gets garbage collected correctly.
While trying to track down some issues, I wished I had Squeak&#8217;s PointerExplorer, which makes it easy to examine the references to an object—and figure out who&#8217;s causing problems by [...]]]></description>
			<content:encoded><![CDATA[<p>A project I&#8217;m working on at the moment has a lot of long-lived objects, and we want to make sure that everything gets garbage collected correctly.</p>
<p>While trying to track down some issues, I wished I had Squeak&#8217;s <a href="http://map.squeak.org/package/1508934b-79ea-4216-956c-1948e9d48aad">PointerExplorer</a>, which makes it easy to examine the references to an object—and figure out who&#8217;s causing problems by hanging on to one.</p>
<p>After a quick look at a <a href="http://timetobleed.com/memprof-a-ruby-level-memory-profiler/">few</a> <a href="http://blog.evanweaver.com/articles/2007/04/28/bleak_house/">existing</a> tools for tracing leaks, it doesn&#8217;t appear that there&#8217;s currently any way of doing this. So I took some <a href="http://timetobleed.com/plugging-ruby-memory-leaks-heapstack-dump-patches-to-help-take-out-the-trash/">code</a> from Joe Damato, updated it a bit, and implemented two things: weak arrays, and <tt>GC.heap_find()</tt>.</p>
<p>Weak arrays work pretty much as you&#8217;d expect:</p>
<pre>&gt;&gt; a = []
=&gt; []
&gt;&gt; a.weak = true
=&gt; true
&gt;&gt; 1000.times { a &lt;&lt; Object.new }
=&gt; 1000
&gt;&gt; GC.start
=&gt; nil
&gt;&gt; a[200]
=&gt; nil</pre>
<p>Like the PointerExplorer, <tt>GC.heap_find</tt> scans the heap to find references to an object. Since it uses the same algorithms that the garbage collector itself uses, it won&#8217;t miss anything. (If Ruby&#8217;s mark-and-sweep collector can&#8217;t find your object, it&#8217;s not going to be kept.)</p>
<pre>&gt;&gt; obj = Object.new
=&gt; #&lt;Object:0x1007f6900&gt;
&gt;&gt; a = [obj]
=&gt; [#&lt;Object:0x1007f6900&gt;]
&gt;&gt; h = {:foo =&gt; 2, :bar =&gt; obj}
=&gt; {:bar=&gt;#&lt;Object:0x1007f6900&gt;, :foo=&gt;2}
&gt;&gt; refs = GC.heap_find(obj)
=&gt; [{:bar=&gt;#&lt;Object:0x1007f6900&gt;, :foo=&gt;2}, [#&lt;Object:0x1007f6900&gt;]]
&gt;&gt; refs[1].object_id
=&gt; 2151609120
&gt;&gt; a.object_id
=&gt; 2151609120</pre>
<p>One slight issue is that <tt>heap_find</tt> can&#8217;t return some objects that are traversed by Ruby&#8217;s GC, but aren&#8217;t first class Ruby objects—things like <tt>SCOPE</tt>s and <tt>VARMAP</tt>s. <tt>heap_find</tt> could indicate their presence somehow, but, since they&#8217;re not first class, they can&#8217;t be returned directly. This isn&#8217;t that big a deal: memory issues here are pretty unlikely, and any present probably indicate a bug in Ruby itself.</p>
<p>Because the arrays returned by <tt>heap_find</tt> are weak, you can continue to explore the object graph as far as you like, without worrying about them interfering with the results, and leading to confusing additional references.</p>
<pre>&gt;&gt; refs.weak?
=&gt; true
&gt;&gt; obj2 = Object.new
=&gt; #&lt;Object:0x1013ec9c0&gt;
&gt;&gt; foo = [1, 2, obj2]
=&gt; [1, 2, #&lt;Object:0x1013ec9c0&gt;]
&gt;&gt; GC.heap_find(obj2)
=&gt; [[1, 2, #&lt;Object:0x1013ec9c0&gt;]]
&gt;&gt; foo.weak = true
=&gt; true
&gt;&gt; GC.heap_find(obj2)
=&gt; []
</pre>
<p><a href="/code/gcpatch.txt">Here&#8217;s the patch</a> for ruby 1.8.7-p174 (shipped with OS X 10.6).</p>
]]></content:encoded>
			<wfw:commentRss>http://collison.ie/blog/2010/06/tracing-memory-leaks-in-ruby/feed</wfw:commentRss>
		</item>
		<item>
		<title>A good email client, please.</title>
		<link>http://collison.ie/blog/2010/02/a-good-email-client-please</link>
		<comments>http://collison.ie/blog/2010/02/a-good-email-client-please#comments</comments>
		<pubDate>Tue, 02 Feb 2010 00:31:30 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://collison.ie/blog/2010/02/a-good-email-client-please</guid>
		<description><![CDATA[Gmail proved that, despite the apparently high switching costs, a new webmail client can quickly get a lot of traction. There&#8217;s room now to do to Gmail what Gmail did to everything else. The replacement should have some concept of workflow (&#8221;archive, but remind me to respond tomorrow&#8221;, &#8220;send, and alert me if I don&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p>Gmail proved that, despite the apparently high switching costs, a new webmail client can quickly get a lot of traction. There&#8217;s room now to do to Gmail what Gmail did to everything else. The replacement should have some concept of workflow (&#8221;archive, but remind me to respond tomorrow&#8221;, &#8220;send, and alert me if I don&#8217;t get a response within a few days&#8221;), some concept of teams and colleagues (allow threads to be shared as a first-class object, rather than flailing around with forwards and CC lines), be some way smart about mining the semi-structured mails going through the system (flight booking emails should be automatically annotated with .ics files), know something about prioritization (I like Twitter DMs because of the assumption that they&#8217;ll go to a mobile device. If I&#8217;ve sent more than 20 emails to someone, they should have the option of copying their mail to me as an SMS).</p>
<p>Potentially most powerfully of all, developers should be able create their own plug-ins that run on the server. There should be an agreement between plug-in developers and the webmail provider that creating a plug-in automatically grants a royalty-free perpetual irrevocable worldwide (etc.) license to the provider, and that the source code to any plug-in may be merged into the main product. Though plug-ins have niche appeal, this could be a good source of new features, and a strong competitive advantage. I&#8217;d just fix Gmail if I could.</p>
<p>I&#8217;d happily pay for any service that got this stuff right.</p>
]]></content:encoded>
			<wfw:commentRss>http://collison.ie/blog/2010/02/a-good-email-client-please/feed</wfw:commentRss>
		</item>
		<item>
		<title>clean-downloads</title>
		<link>http://collison.ie/blog/2009/12/clean-downloads</link>
		<comments>http://collison.ie/blog/2009/12/clean-downloads#comments</comments>
		<pubDate>Wed, 09 Dec 2009 06:28:42 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://collison.ie/blog/2009/12/clean-downloads</guid>
		<description><![CDATA[This has solved the eternal &#8220;there&#8217;s 3GB of stuff in my Downloads directory that I don&#8217;t feel comfortable deleting&#8221; problem for me:
$ crontab -l
0 * * * *   /Users/patrick/Binaries/clean-downloads
$ cat Binaries/clean-downloads
#!/bin/zsh
find ~/Downloads -maxdepth 1 -amin +720 -exec mv {} ~/.Trash \;
You have twelve hours to do something with whatever it is you downloaded, [...]]]></description>
			<content:encoded><![CDATA[<p>This has solved the eternal &#8220;there&#8217;s 3GB of stuff in my Downloads directory that I don&#8217;t feel comfortable deleting&#8221; problem for me:</p>
<pre>$ crontab -l
0 * * * *   /Users/patrick/Binaries/clean-downloads
$ cat Binaries/clean-downloads
#!/bin/zsh
find ~/Downloads -maxdepth 1 -amin +720 -exec mv {} ~/.Trash \;</pre>
<p>You have twelve hours to do something with whatever it is you downloaded, or it&#8217;ll end up in the Trash. I highly recommend it.</p>
]]></content:encoded>
			<wfw:commentRss>http://collison.ie/blog/2009/12/clean-downloads/feed</wfw:commentRss>
		</item>
		<item>
		<title>Surprises</title>
		<link>http://collison.ie/blog/2009/10/surprises</link>
		<comments>http://collison.ie/blog/2009/10/surprises#comments</comments>
		<pubDate>Mon, 19 Oct 2009 00:41:53 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[Start-ups]]></category>

		<guid isPermaLink="false">http://collison.ie/blog/2009/10/surprises</guid>
		<description><![CDATA[Someone asked me today what surprised me most about doing a start-up. This was my response:

How slowly things change. When we started Auctomatic in mid-2007, eBay was dominant but faltering, PayPal was lumbering along without any innovation, Facebook was amazing everyone (and scaring Google) with their growth, the iPhone was reshaping the cell phone industry, [...]]]></description>
			<content:encoded><![CDATA[<p>Someone asked me today what surprised me most about doing a start-up. This was my response:</p>
<ul>
<li>How slowly things change. When we started Auctomatic in mid-2007, eBay was dominant but faltering, PayPal was lumbering along without any innovation, Facebook was amazing everyone (and scaring Google) with their growth, the iPhone was reshaping the cell phone industry, and everyone was talking about Twitter. Two and a half years on, that still sounds like a reasonable assessment of things. With Auctomatic, we felt this tremendous sense of urgency. That may have been good for other reasons, but it was misguided. When building something, I now think you should assume that you&#8217;ve plenty of time, and that very little will change in the interim. (This is, admittedly, the kind of rule that works until it doesn&#8217;t.)</li>
<li>Tied to this, the realization that a good product is so much more important than first mover advantage. Obvious, but keeps surprising me. Facebook, the iPhone, Dropbox, Skype, etc., have an amazing array of failed predecessors.</li>
<li>Succeeding at biz dev just requires endless persistence.</li>
<li>Internationalization is an underexploited axis—people try to expand on the x-y plane, and ignore this third dimension. We grew our <a href="http://steamheavyindustries.com">iPhone app</a> revenue by over 200% through internationalization. The biggest competitve advantage we ever had with Auctomatic was supporting the obscure international eBay sites that the big US players ignored. I&#8217;m generalizing from pretty limited experience, but if I were a floundering start-up trying to get to cashflow positive, internationalizing is probably the first trick I&#8217;d try.</li>
<li>How dangerous the assumption that you&#8217;re going to grow is: &#8220;oh, we need to build this this way, because when we&#8217;re successful, we&#8217;ll need it&#8221;. This is often used as an argument against over-engineering for scalability, but it applies more generally. Now, when coding, I try to think: &#8220;how can I write this such that if people saw my code, they&#8217;d be amazed at how little there is and how little it does&#8221;.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://collison.ie/blog/2009/10/surprises/feed</wfw:commentRss>
		</item>
		<item>
		<title>Undop</title>
		<link>http://collison.ie/blog/2009/08/undop</link>
		<comments>http://collison.ie/blog/2009/08/undop#comments</comments>
		<pubDate>Sun, 16 Aug 2009 00:10:51 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://collison.ie/blog/2009/08/undop</guid>
		<description><![CDATA[Like most internet users, I waste too much time on the web. Despite that, I&#8217;ve never had much luck with the apps that set out to solve this, like Freedom or RescueTime. They feel too heavy-handed. Instead, I want fairly repetitive and annoying prods that make wasting time less fun&#8212;the equivalent of small electric shocks, [...]]]></description>
			<content:encoded><![CDATA[<p>Like most internet users, I waste too much time on the web. Despite that, I&#8217;ve never had much luck with the apps that set out to solve this, like <a href="http://macfreedom.com/">Freedom</a> or <a href="http://www.rescuetime.com/">RescueTime</a>. They feel too heavy-handed. Instead, I want fairly repetitive and annoying prods that make wasting time less fun&mdash;the equivalent of small electric shocks, counterbalancing the <a href="http://www.slate.com/id/2224932/">Dopamine hits</a>.</p>
<p>So here&#8217;s <a href="http://github.com/pc/undop">undop</a>. Every time I visit a domain in <tt>~/.bad_sites</tt>, it dims the display by 30%, gradually returning it to its previous brightness over the course of 30 seconds. It&#8217;s both an annoyance and a reminder. The effect is small enough that I don&#8217;t mind it on those occasions when I actually <i>do</i> want to read Twitter or Hacker News or whatever blog, but it&#8217;s jarring enough that I now subconsciously avoiding following links to them, and have mostly broken the check-for-new-stuff muscle memory.</p>
<p><!--Overall, it seems to be a good test: if I'm not willing to endure the fleeting inconvenience of a marginally darker display, I should probably not be doing --></p>
<p>Caveats: it only works with Safari on OS X. (Patches with support for other browsers welcome.) I&#8217;m guessing it might not be good for display backlights.</p>
]]></content:encoded>
			<wfw:commentRss>http://collison.ie/blog/2009/08/undop/feed</wfw:commentRss>
		</item>
		<item>
		<title>Facebook doesn&#8217;t want you to deactivate your account</title>
		<link>http://collison.ie/blog/2009/07/facebook-doesnt-want-you-to-deactivate-your-account</link>
		<comments>http://collison.ie/blog/2009/07/facebook-doesnt-want-you-to-deactivate-your-account#comments</comments>
		<pubDate>Sun, 05 Jul 2009 22:49:43 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://collison.ie/blog/2009/07/facebook-doesnt-want-you-to-deactivate-your-account</guid>
		<description><![CDATA[
]]></description>
			<content:encoded><![CDATA[<p><a href="http://collison.ie/pics/60b1637dffc83eeb2597be5afe89fe5c.png"><img style="border: none" width="600" src="http://collison.ie/pics/60b1637dffc83eeb2597be5afe89fe5c.png"></a></p>
]]></content:encoded>
			<wfw:commentRss>http://collison.ie/blog/2009/07/facebook-doesnt-want-you-to-deactivate-your-account/feed</wfw:commentRss>
		</item>
		<item>
		<title>Screenshots to URLs</title>
		<link>http://collison.ie/blog/2009/06/screenshots-to-urls</link>
		<comments>http://collison.ie/blog/2009/06/screenshots-to-urls#comments</comments>
		<pubDate>Sun, 28 Jun 2009 23:14:10 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://collison.ie/blog/2009/06/screenshots-to-urls</guid>
		<description><![CDATA[Whenever I take a screenshot, the next step is usually to paste it into an email or IM conversation. Here&#8217;s a modified version of a launchd script for OS X, originally from Avi, that automates that: whenever you take a screenshot, it uploads it to a server of your choice, places the URL on the [...]]]></description>
			<content:encoded><![CDATA[<p>Whenever I take a screenshot, the next step is usually to paste it into an email or IM conversation. <a href="http://gist.github.com/137399">Here&#8217;s</a> a modified version of a launchd script for OS X, originally from <a href="http://avibryant.com">Avi</a>, that automates that: whenever you take a screenshot, it uploads it to a server of your choice, places the URL on the clipboard, and beeps. Download and execute the script to install the service. It assumes you use key-based SSH authentication.</p>
]]></content:encoded>
			<wfw:commentRss>http://collison.ie/blog/2009/06/screenshots-to-urls/feed</wfw:commentRss>
		</item>
		<item>
		<title>Where&#8217;d that code go?</title>
		<link>http://collison.ie/blog/2009/06/whered-that-code-go</link>
		<comments>http://collison.ie/blog/2009/06/whered-that-code-go#comments</comments>
		<pubDate>Sun, 28 Jun 2009 23:02:28 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://collison.ie/blog/2009/06/whered-that-code-go</guid>
		<description><![CDATA[$ &#60; ~/Binaries/git-find-removal
#!/bin/zsh
if [ $# != 2 ] ; then
  echo "$0 &#60;commit&#62; &#60;string&#62;" &#62;/dev/stderr
  exit 1
fi
git bisect start
git bisect good $1
git bisect bad
git bisect run grep -qRE $2 .
$ git-find-removal HEAD~20 'def my_important_function'
]]></description>
			<content:encoded><![CDATA[<pre>$ &lt; ~/Binaries/git-find-removal
#!/bin/zsh
if [ $# != 2 ] ; then
  echo "$0 &lt;commit&gt; &lt;string&gt;" &gt;/dev/stderr
  exit 1
fi
git bisect start
git bisect good $1
git bisect bad
git bisect run grep -qRE $2 .</pre>
<pre>$ git-find-removal HEAD~20 'def my_important_function'</pre>
]]></content:encoded>
			<wfw:commentRss>http://collison.ie/blog/2009/06/whered-that-code-go/feed</wfw:commentRss>
		</item>
		<item>
		<title>App School</title>
		<link>http://collison.ie/blog/2009/06/app-school</link>
		<comments>http://collison.ie/blog/2009/06/app-school#comments</comments>
		<pubDate>Fri, 12 Jun 2009 08:31:46 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://collison.ie/blog/2009/06/app-school</guid>
		<description><![CDATA[App School just went live. It&#8217;s an iPhone development training course taught by my friend Daniel, and run by SQT, my Mum&#8217;s training company, and Mulley Communications. The courses will be based in Dublin&#8212;it should be a pretty cool chance for anyone Irish to quickly get up to speed with everything related to iPhone app [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://appschool.ie">App School</a> just went live. It&#8217;s an iPhone development training course taught by my friend <a href="http://daniel.ie">Daniel</a>, and run by <a href="http://sqt.ie">SQT</a>, my Mum&#8217;s training company, and <a href="http://www.mulley.ie">Mulley Communications</a>. The courses will be based in Dublin&mdash;it should be a pretty cool chance for anyone Irish to quickly get up to speed with everything related to iPhone app development (including some tips on navigating the notorious app submission process&#8230;).</p>
<p>I&#8217;ve known Daniel since first year in secondary school&mdash;he convinced me to learn PHP, my first real (&#8221;real&#8221;?) programming language. He&#8217;s one of the best programmers I&#8217;ve ever worked with, and just won an IBM Open Source Award for his work on <a href="http://www.skynet.ie/~daniel/rls/Yakumo-Final-Report.pdf">Yakumo [PDF]</a>, an open-source library for using the iPhone a game input device. Despite only just graduating now, a couple of companies have already spotted his win-ness&mdash;he interned with the hardcore physics guys at <a href="http://havok.com">Havok</a> in San Francisco last summer.</p>
<p>App School is lucky to have him, and I think the courses are going to be killer.</p>
<p>See also: <a href="http://www.mulley.net/2009/06/12/app-school-learn-to-make-iphone-applications/">Damien</a>, <a href="web2ireland.org/2009/06/12/irish-iphone-app-school-announced/">Web 2 Ireland</a>, <a href="http://www.irishtimes.com/newspaper/finance/2009/0612/1224248686508.html">Irish Times</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://collison.ie/blog/2009/06/app-school/feed</wfw:commentRss>
		</item>
		<item>
		<title>Hacking for fun and profit with Mathematica and the Google Analytics API</title>
		<link>http://collison.ie/blog/2009/04/hacking-for-fun-and-profit-with-mathematica-and-the-google-analytics-api</link>
		<comments>http://collison.ie/blog/2009/04/hacking-for-fun-and-profit-with-mathematica-and-the-google-analytics-api#comments</comments>
		<pubDate>Tue, 28 Apr 2009 01:30:06 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://collison.ie/blog/2009/04/hacking-for-fun-and-profit-with-mathematica-and-the-google-analytics-api</guid>
		<description><![CDATA[I&#8217;ve always been surprised by how much web analytics software sucks. Web sites produce reams of interesting statistical data, many sites have a strong interest in growing their traffic, and yet even the leaders in the field—Google Analytics and co.—do nothing to help: they make no attempt to analyze the data; they just display it [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve always been surprised by how much web analytics software sucks. Web sites produce reams of interesting statistical data, many sites have a strong interest in growing their traffic, and yet even the leaders in the field—Google Analytics and co.—do nothing to help: they make no attempt to <em>analyze</em> the data; they just <em>display</em> it in fairly pedestrian ways.</p>
<p>Every day, you log into your analytics dashboard, and you see basically the same picture that you saw the day before. It&#8217;s left up to you to find out what&#8217;s changed. Did your search referrals for some mid-ranking keyword rise hugely? Are you getting referrals from some site that never linked to you before?</p>
<p>Additionally, most packages don&#8217;t provide any mechanism for you to integrate your business-specific data with your web site data. Sure, you can sometimes hack this with things like tracking visits to special &#8220;checkout&#8221; pages, but fundamentally there&#8217;s no direct way of integrating off-site data (sales of an iPhone app, say).</p>
<p>I wrote some Emacs-based software to do all of this last year (<a href="http://collison.ie/blog/2008/06/pictures-in-the-slime-repl">including charts in the REPL</a>), and have been using it fairly happily. Recently, I&#8217;ve started using Mathematica more and more to process log data, and have been very happy with the results.</p>
<p>A few days ago, Google released an API for Google Analytics (<a href="http://www.centernetworks.com/google-analytics-usage">largely invisible but enormously successful</a>). I spent a while over the weekend writing a bridge to Mathematica, and playing with the data, particularly that related to my iPhone app (<a href="/wikipedia-iphone">Encyclopedia</a>, which stores a copy of Wikipedia on your phone for offline browsing).</p>
<style>img { border: none; }</style>
<p><img src="http://collison.ie/pics/4ae43431df0819193f79b762a5718a72.png"></p>
<p>We can start off by doing fairly standard things, like number of visits from each search term by date:</p>
<p><img src="http://collison.ie/pics/a49a3f0925c7ef5b7803ddb0ad1b5c62.png"></p>
<p>And we can, say, chart the result. (First, we remove the &#8220;(not set)&#8221; results that the API returns.)</p>
<p><img src="http://collison.ie/pics/ae0a106a6301bbda281093f8c344ba63.png"></p>
<p>What fraction of this is from search traffic related to the iPhone app? We can select the promising search terms, and compare them with overall search traffic (as far as I know, no boolean logic is possible in the Google Analytics web interface):</p>
<p><img src="http://collison.ie/pics/c09f01384db345b76142e13818e87214.png"></p>
<p>Looks like most of the Google traffic is from the app-related keywords. We can also pretty trivially look at the geographical distribution of these visitors. First, let&#8217;s load the data:</p>
<p><img src="http://collison.ie/pics/7d40b77d89e60865e055525f9f53861d.png"></p>
<p>And group the result by country:</p>
<p><img src="http://collison.ie/pics/f65ab9cad122e4368d312f627fd6eff7.png"></p>
<p>We can now define a simple <tt>WorldPlot</tt> function, and use it with our data:</p>
<p><img src="http://collison.ie/pics/71a8406b77a32ee06fbc391cc1516af5.png"></p>
<p>(Brighter colours indicate more visits.) Okay, that&#8217;s somewhat interesting. But how many sales does the app get per visit? I track my sales in <a href="http://dabbledb.com">Dabble DB</a>, so I&#8217;ll load the data from there. They provide a CSV file of country code to unit sales mappings:</p>
<p><img src="http://collison.ie/pics/9b5b79cf00ae0dc28fd0bd095267de6f.png"></p>
<p>We can pretty easily import this into Mathematica:</p>
<p><img src="http://collison.ie/pics/d5ce380b8b15b2a8da04fdbd981b660c.png"></p>
<p>Using Mathematica&#8217;s <tt>CountryData[]</tt> function, which knows about country codes (as well as their shapes), we can easily integrate the keyword referrals and the sales data to generate a heat map of purchases per search referral:</p>
<p><img src="http://collison.ie/pics/a36d456ca020683b7a45b888ecdf9774.png"></p>
<p>The interesting outlier here is Mexico. Though they don&#8217;t visit the site much, they do buy the app a lot. (Hundreds of times to date.) I&#8217;m still not sure why. The two maps also show that, although Ireland sends quite a bit of traffic to the site, it converts quite poorly—perhaps because my .ie domain causes my search rank there to be artificially inflated.</p>
<p>Okay, ignoring the app for a while, we might also be interested in questions like &#8220;what are my most important search terms?&#8221;. One way of measuring this is to look at the total time on your site due by each search term. (Google Analytics tells you the <em>average</em> time on site for each term, but that&#8217;s not much help in telling you where you should direct your work.)</p>
<p>Let&#8217;s load the data:</p>
<p><img src="http://collison.ie/pics/2ca7ccf907266596cb0a7adb33b1884e.png"></p>
<p>And define a simple function that computes the total number of seconds on the site driven by each keyword:</p>
<p><img src="http://collison.ie/pics/9019e4e15c551ba1e36f86abd2b4e455.png"></p>
<p>We can compute the set of search terms that were used to get to the site:</p>
<p><img src="http://collison.ie/pics/0b3084a2ab8a96700f5c92fbf39895d4.png"></p>
<p>And sort them by time on site:</p>
<p><img src="http://collison.ie/pics/d4e400675963c9d0a9db65dbd9b542bd.png"></p>
<p>Ignoring the first two (corresponding to &#8220;(not set)&#8221;, which we could of course filter out), it seems that &#8220;wiki&#8221;, &#8220;wikipedia&#8221; and &#8220;iphone&#8221; are the important terms.</p>
<p>We might also be interested to see how keyword usage changes over time. Let&#8217;s load two months of keyword data:</p>
<p><img src="http://collison.ie/pics/ec7b38b76220dafe3c6d77cf89a4de9a.png"></p>
<p>And define a simple function to count the fraction of referrals that are from a particular keyword in some given dataset:</p>
<p><img src="http://collison.ie/pics/8d778aa3c380939d1aa3f3f3f1c32a6d.png"></p>
<p>We can test it with something like:</p>
<p><img src="http://collison.ie/pics/6cf33299a3f7cc634d2edfb823fc7b0a.png"></p>
<p>Okay, 4% of the site&#8217;s visitors came by searching for something containing the word &#8220;iPhone&#8221;.</p>
<p>Now let&#8217;s compare two months of data:</p>
<p><img src="http://collison.ie/pics/d618317f3e7f805ff8b9095abcde150f.png"></p>
<p>These are the search keywords that showed the biggest increase between October and January. And they correspond quite closely to what you&#8217;d expect—<a href="http://collison.ie/blog/2008/11/dynamic-defaultpng-files-on-the-iphone">default.png files on the iPhone</a> and <a href="http://collison.ie/blog/2008/12/leopard-and-back-to-my-mac-tunnels">Back To My Mac</a> are both topics I wrote about in the intervening time period.</p>
<p>Keeping with the spirit of analysing changes, we can look at non-search referrals:</p>
<p><img src="http://collison.ie/pics/b241e6beaf22ea7b72b9eb18d4add39f.png"></p>
<p>We can drop the direct referrals, group them by source, and select the first referral from each site:</p>
<p><img src="http://collison.ie/pics/637497381cd53e44d0337506f77c6bd6.png"></p>
<p>And then we can do something like plot the first referral from each site against the amount of traffic it sent—a chart of buzz, basically:</p>
<p><img src="http://collison.ie/pics/2f2cd8ac96f2fc57c0d5eff8dbdc4def.png"></p>
<p>Next, we can look at how traffic flows around the site. First, we load (landing page, exit page) tuples:</p>
<p><img src="http://collison.ie/pics/32f81d1b8f24314d31e4266a0da97aec.png"></p>
<p>And then hack together a function to generate a directed graph:</p>
<p><img src="http://collison.ie/pics/db8c043bd27fae2e9bb30ad26a16837e.png"></p>
<p>Yielding a pretty interesting result:</p>
<p><img src="http://collison.ie/pics/087a25947b5027b9fa927350bbf7d629.png"></p>
<p>As a final example, we can, for no good reason, take advantage of the latitude and longitude metrics that the API provides and quickly create a video of visits by hour, showing traffic move across the globe. First, we load the data, and define two helper functions:</p>
<p><img src="http://collison.ie/pics/f75e1b6f42975dcdf7608a21cdfd7247.png"></p>
<p>We can test it out on one of the hours:</p>
<p><img src="http://collison.ie/pics/2a47c8aab04853213503f0a885e80211.png"></p>
<p>Looks good. Let&#8217;s export an image for each hour, which we can then join with QuickTime:</p>
<p><img src="http://collison.ie/pics/c9b8c092e429cd4548989c7df32bdde9.png"></p>
<p>The result is <a href="/code/hourvisits.mov">here</a>. (You probably want to have it loop when you play it.)</p>
<p>Mathematica doesn&#8217;t get much attention from the programming community (largely because of Wolfram&#8217;s pricing, as far as I can tell). But its power is undeniable—I spent about 5 hours writing the Google Analytics interface and generating the above data. I wrote this blog post over lunch. If anyone else is interested in using the Mathematica/Google Analytics interface, let me know in the comments, and I&#8217;ll package it up and release it somewhere (it requires modified versions of a few libraries).</p>
<p>Lastly, over the past year, I spent a lot of time talking to my friend <a href="http://avibryant.com">Avi</a> about the state of web analytics. He and the guys at Dabble DB decided to do something about it, and it looks like <a href="http://dshbrd.com">dshbrd</a> will launch soon. From what I&#8217;ve seen so far, it looks like it&#8217;ll be win.</p>
]]></content:encoded>
			<wfw:commentRss>http://collison.ie/blog/2009/04/hacking-for-fun-and-profit-with-mathematica-and-the-google-analytics-api/feed</wfw:commentRss>
		</item>
	</channel>
</rss>
