<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Kenneth's Picnic</title>
	
	<link>http://kenneth.kufluk.com/blog</link>
	<description>Welcome to Kenneth's Picnic.  Put your feet up and admire the stars over London.</description>
	<lastBuildDate>Sun, 29 Aug 2010 20:08:56 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/KennethKufluk" /><feedburner:info uri="kennethkufluk" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>The Doors</title>
		<link>http://feedproxy.google.com/~r/KennethKufluk/~3/rqdlxeXsZnM/</link>
		<comments>http://kenneth.kufluk.com/blog/2010/08/the-doors/#comments</comments>
		<pubDate>Sun, 29 Aug 2010 20:00:06 +0000</pubDate>
		<dc:creator>Kenneth</dc:creator>
				<category><![CDATA[Personal]]></category>
		<category><![CDATA[Ranting]]></category>

		<guid isPermaLink="false">http://kenneth.kufluk.com/blog/?p=742</guid>
		<description><![CDATA[In this blog post, I critique the modern door, it&#8217;s place in our lives, and the social awkwardness that results. I propose a simpler system of door management, providing greater efficiency, hygiene and social satisfaction. The door is everywhere. To call it common is an injustice &#8211; it is as ubiquitous as the air we [...]]]></description>
			<content:encoded><![CDATA[<p>In this blog post, I critique the modern door, it&#8217;s place in our lives, and the social awkwardness that results.  I propose a simpler system of door management, providing greater efficiency, hygiene and social satisfaction.<br />
<span id="more-742"></span></p>
<p>The door is everywhere.  To call it common is an injustice &#8211; it is as ubiquitous as the air we breathe, the water we drink, the taxes we owe.  It is in our homes, our offices, our transport.  It keeps us safe while we sleep, while we drive.  It is our protection against the room next door, and the world outside.</p>
<p>The door is part of our vocabulary, our language.  We &#8220;open doors&#8221;, we &#8220;close a deal&#8221;.  We have an &#8220;open door policy&#8221;.  We swing them open, we slam them shut.  The door is our slave and our servant.  The door is our bitch.</p>
<p>But the door is also our enemy.  It attacks us, it frustrates us, it makes us look like fools.</p>
<h3>The Toilet Door</h3>
<p>The toilet door is my nemesis, the number one on my list of dastardly doors.  And I&#8217;m not even talking about the cubicle door, that never gives you enough room to close without brushing your legs against the outside of the toilet bowl.  </p>
<p>Nor even, the American cubicle door, starting a mighty three feet from the ground to allow full thigh viewing from urinal alley, and the inch-wide gap between the door and walls.  One wonders whether Americans in public toilets in England feel lonely in their out-of-sight claustrophobic boxes.  But these are not my primary concern.</p>
<p>My target is the exit door.  The exit door? you ask.  The exit door, I nod.</p>
<p>When leaving the toilet, or bathroom, or restroom, or outhouse, or water-closet, or so forth, the typical gentleman (for this is all I am permitted to observe), will customarily choose one of the following options.  He will either wash his hands, or he will not wash his hands.</p>
<p>I shall not question the wisdom of the non-washers.  Presumably they believe their hands to be unsullied by their efforts, usually involved in a mere &#8220;reveal-tug-dangle&#8221; gesture followed by the &#8220;tug-shake-tuck&#8221;.  An inspection of the spray-deck in the men&#8217;s urinals does not reassure me that hands are quite as sanitary as their conscience.  But I do not judge, I shall simply note that this practice exists and is commonplace.</p>
<p> A washer, indeed myself, would avail himself of the facilities, providing of course, and this is not always the case, that the washing facilities are cleaner than the sewage facilities.  Equipment provided is usually an unpleasant soap, scaldingly hot water in one tap, lukewarm water in another tap, based around a basin area.  The controls on the taps are judged to encourage the maximum use of water, such that there will always be one tap running for no apparent reason, which is impossible to shut off.</p>
<p>Once hands are adequately washed, one would look for the hand-drying facilities.  These are allocated on a ratio of one drying unit to every three washing units, on the basis of physics completely unknown to science:  that it is quicker to dry your hands than to wet them.  The drying units will have been provided further back into the toilet area, to encourage awkward confrontations with other toiletting members of the public, and to generally persuade the user into joining the wet-hands-exit, wipe-on-trousers masses.</p>
<p>Further encouragement into this camp is provided by the drying unit.  This has a fifty percent chance of existing, a forty percent chance of working, and a ten percent chance of actually doing any drying, since models manufactured before 2005 seemed to be modelled on the average drunk&#8217;s morning breath.  Of course, you may just have one of those clever Dyson units, which are really neat but still leave a few drops on the fingertips don&#8217;t they?</p>
<p>Doors, doors, I&#8217;m coming back to doors.  The exit of a toilet is always, always, always a pull door.  Always.</p>
<p>Why.  Why why why.  I&#8217;ve just spent four seconds exquisitely washing, and four hours slowly drying, my clean clean hands.  And now you&#8217;re asking me to grab hold of a door handle that has been held by every &#8220;tug-shake-tugger&#8221; and &#8220;wet-hand-wiper&#8221; who&#8217;s ever been in here.  </p>
<p>That handle is never cleaned either.  When the attendant (not a cleaner, never a cleaner), when the attendant comes to check the facilities, he (or she) will wedge the door open with their mop-bucket, and give a quick wipe to the spray deck.  But we know they never check behind the opened door.  That&#8217;s why that cock you drew in 2005 is still on that cubicle door over there.  Wasn&#8217;t funny then, isn&#8217;t funny now.</p>
<p>To make matters worse, there&#8217;s often two doors as well.  In case you waited long enough for someone else to come in (don&#8217;t ever try that), you&#8217;d still have the second to contend with.  Your hands will be soiled when you head back to your table, and your hamburger/nuts/asparagus/finger food.  It&#8217;s disgusting.</p>
<p>It&#8217;s disgusting and the door is at fault.  Remove the door.  Or let them be pushed, so I can kick it open.  Either way, when we all die of goldfish-flu, this blog post is my &#8220;I told you so&#8221;.</p>
<h3>CorriDoors</h3>
<p>See what I did there?  Clever, isn&#8217;t it.  But not as clever as the build regulations that state that fire doors must be installed throughout buildings, and that those doors need to be closed at all times.</p>
<p>Which gives us the corridor doors.  Harmless enough, just a barrier between you and where you want to be.  Just give them a push.</p>
<p>Or is it a pull?</p>
<p>Hope it&#8217;s a push anyway, I mean, I&#8217;m carrying an armful of stuff.</p>
<p>But, hey, it&#8217;s got a handle.  It&#8217;s a pull.  One of those simple, clear, obvious rules of life.  Right?</p>
<p>Wrong.  Fifty percent of the time, your average push door is going to have a handle.  Why?  We don&#8217;t know.  Maybe they&#8217;re future-proofing against change.  Maybe the unions are in on it.  In fact, if the door <em>swings both ways</em>, it&#8217;s even more likely to have handles.  And most people will pull the doors, which is both awkward, and inconvenient.  And unbelieveably, even though they pull to go through it one way, and pull to go through the other way, <em>most people will never realize the doors go both ways</em>.  At this point, the door is looking cleverer than we are.</p>
<p>And one more point lost by humanity, to the door, is locks.  Not the bold padlock, or the fancy chubb.  No, I mean the slot locks at the top and bottom of the door.  For we all know that when opening a set of doors in any building, the caretaker, janitor, or security guy will only ever open one of the two.  God knows why &#8211; maybe they only see the doors at night, when they&#8217;re used by one person at a time.  Next thing you know, you&#8217;ve got a hundred people pushing on both sides, before trying to squeeze through, ten abreast.  Certainly at my school it was a regular scrum to get between classes, there&#8217;d be a cry of &#8220;bundle!&#8221; and a whiff of Hillsborough in the morning.  This is how I lost all my teeth.  True story.</p>
<h3>Automatic doors</h3>
<p>What an amazing invention it is, the automatic door.  Sliding briskly aside as we approach, it is hard to believe that this work-driven slave to our presence could be a bad omen.</p>
<p>It is more of a trojan horse.  For you never know <a href="http://www.break.com/index/automatic-door-concept-lost-on-this-guy.html">how long it&#8217;ll take to open</a>.  And it&#8217;s always slightly longer than you&#8217;d like.  Maybe the sensors are just waiting for you to get close enough, so you have to pause, wait, and then go on.  It&#8217;s winding us up, little by little.</p>
<p>Either that, or they&#8217;re waaay too sensitive.  You want to hang around in the warmth of the hotel lobby?  Sure, but you&#8217;ll get looks, because even a hundred yards into this room, and you&#8217;re keeping the doors open.  The doors will alert other visitors to this faux-pas, by inching in slightly, as if to say &#8220;have you moved yet&#8221;, before opening again.  They&#8217;re playing a game, and they always win.</p>
<p>Lift doors, or elevators to our American friends, are widely know to be evil incarnate.  Who knows what will appear behind those doors?  Will there be a lift car, or will we fall to oblivion?  Will they close at all, without us squeezing uncomfortably backwards into a lawsuit from Debbie in Accounts?  This is why we face forward.  We need to keep an eye on the door, but we also need to be able to push backwards without going face to face.</p>
<p>Automatic doors may not be killers, but they will add to your stress levels in a thousand different ways.</p>
<h3>Door Etiquette</h3>
<p>In this brave new world of unwritten etiquette, it is the men who suffer most.  Do we buy dinner without asking, or should we split it.  The success of the date depends on it.  If she suggests splitting it, do we refuse?  And if so, how many times?  And the only thing we know for certain is that we&#8217;re not going home without paying something.  It&#8217;s a lose-lose situation.</p>
<p>And so it is with the door.  In days gone by, it would be appropriate to hold the door for a lady.  Nay, it would be appropriate to open the door with gusto, and to wave the lady through.</p>
<p>Now, we&#8217;re in a quagmire.  We all try to hold the door.  Even when it&#8217;s not actually convenient.  Especially when it&#8217;s not convenient.  We hold it for guys, girls, and in case we can&#8217;t see anyone, a passing breath of air.  I am not even going to cover the long distance holders, for whom you must <em>race</em> to be helped, for I think they&#8217;ve been dealt with repeatedly.</p>
<p>But it&#8217;s madness.  Every time someone opens a door for me and waves me through I feel like wrenching out his throat and hanging it from the door frame.  It&#8217;s a door, not a ten tonne weight!  I&#8217;ve got it.  I&#8217;ve got it.</p>
<p>Am I carrying heavy bags?  No.  Am I in some way unable to open the door myself?  No.  Am I wearing a hot dress that you&#8217;ve like to check out from the back?  Not usually!  Let me handle the door myself, and <em>get out of my way</em>!</p>
<p>The worst cretins, the real bastards, are the guys who try to hold a door open from the wrong side, while standing in it.  I don&#8217;t even credit them with a throat-ripping.  I give them a &#8220;what kind of plant life are you&#8221; look, and send them straight to hell.  Girls, it doesn&#8217;t just happen to you (though I bet it&#8217;s a lot more frequent), it happens to everyone.</p>
<p>Let&#8217;s just agree now.  You want to go through a door, go through it.  After you&#8217;ve gone through, if someone else is about, just hold it open a second longer (just one!), and let go.  Your friend has it from there.</p>
<p>It&#8217;s a door.  We can take it on alone.  It won&#8217;t kill us (unless it&#8217;s a toilet door).  It won&#8217;t hurt us (unless we&#8217;re getting slammed by an automatic).  It can&#8217;t chop us into tiny little pieces (unless it&#8217;s a revolving door).  It&#8217;s no obstacle (unless it&#8217;s a corridoor).  And we can get through it together (unless you&#8217;re holding it for me).</p>
<p>Or we can just move to Hawaii, where they don&#8217;t need doors.  Personally, I&#8217;m on the next plane.</p>
<img src="http://feeds.feedburner.com/~r/KennethKufluk/~4/rqdlxeXsZnM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2010/08/the-doors/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://kenneth.kufluk.com/blog/2010/08/the-doors/</feedburner:origLink></item>
		<item>
		<title>Chaining Asynchronous Methods in jQuery using the Queue</title>
		<link>http://feedproxy.google.com/~r/KennethKufluk/~3/Uj49it72_tI/</link>
		<comments>http://kenneth.kufluk.com/blog/2010/08/chaining-asynchronous-methods-in-jquery-using-the-queue/#comments</comments>
		<pubDate>Sat, 07 Aug 2010 19:20:45 +0000</pubDate>
		<dc:creator>Kenneth</dc:creator>
				<category><![CDATA[Projects]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>

		<guid isPermaLink="false">http://kenneth.kufluk.com/blog/?p=733</guid>
		<description><![CDATA[Someone recently asked me whether it would be possible to chain asynchronous events in JavaScript. After a little pondering, I figured out a way to do it with a simple queue. I thought this would be an awesome addition to chaining for a good few hours, until I remembered how jQuery did it, and that [...]]]></description>
			<content:encoded><![CDATA[<p>Someone recently asked me whether it would be possible to chain asynchronous events in JavaScript.  After a little pondering, I figured out a way to do it with a simple queue.  I thought this would be an awesome addition to chaining for a good few hours, until I remembered how jQuery did it, and that I&#8217;d recently used exactly that function.<span id="more-733"></span></p>
<p><strong>Chaining</strong> is the much-hyped process of calling multiple methods upon an object, all in one line.</p>
<pre class="brush: php">
$(&#039;#cup&#039;).addMilk().frothMilk().addEspresso();
</pre>
<p>It&#8217;s a simple trick to build into your functions:  all you need to do is return &#8216;this&#8217;.</p>
<pre class="brush: php">
function baristaAction() {
   // do stuff
   return this
}
</pre>
<p>Most jQuery plugins do this to enable chaining, albeit with slightly different syntax.  While potentially confusing, it&#8217;s simple enough and common enough to be quickly learnt.</p>
<pre class="brush: php">
$.fn.pluginAction = function() {
   // declare stuff
   return this.each(function() {
      // do stuff
   });
};
</pre>
<p>jQuery plugins look like this because the plugin has to act on a jQuery object, which is always an array of elements.  Even when you specify an identifier, jQuery will return an array of length one, and you usually need to do your stuff on each element before returning the same set to the next function in the chain.</p>
<p>Using the approach above, this is clearly never going to work:</p>
<pre class="brush: php">
$(&#039;#cup&#039;).giveToCustomer().waitForCoffeeToBeDrunk().takeBackFromCustomer();
</pre>
<p>If we&#8217;re chaining, then none of these methods can wait for other actions to take place before returning.  There&#8217;s no threading and sleeping in JavaScript.</p>
<p>The most common way to feign concurrency in JavaScript is to use the setTimeout and setInterval methods, particularly for animation.  Asynchronicity is also found when waiting for another asset to load, for example JSON data, AJAX content or large images.  These methods often use a callback function, placed either on the &#8220;onload&#8221; event of your data load, or after the setTimeout and setInterval managers have completed.</p>
<p>Our code could look like this:</p>
<pre class="brush: php">
$(&#039;#cup&#039;).giveToCustomer(function() {
    $(this).waitForCoffeeToBeDrunk(function() {
         $(this).takeBackFromCustomer();
    });
});
</pre>
<p>Nasty, right?  Right?  Nasty.</p>
<p>Let&#8217;s head away from the coffee and re-enter jQuery land.</p>
<p>In jQuery land, we find THIS code DOES work as expected:</p>
<pre class="brush: php">
$(&#039;#special-offer&#039;).show().hide().slideDown(&#039;slow&#039;).slideUp(&#039;fast&#039;);
</pre>
<p>Each action will take place in turn, the next only starting after the previous has completed.</p>
<p>So why are they so special?</p>
<p>jQuery manages this by maintaining a <em>queue</em>.  Queues are a common programming concept:  simply an array where you push new items on the end, and take them off the beginning.</p>
<pre class="brush: php">
var queue = [ ];
// add some items to the queue
queue.push(function() {
     //shave the woooorld
});
queue.push(function() {
     //make it a better face
});
// take an item off the queue and process it
var nextFunc = queue.shift();
nextFunc();
</pre>
<p>jQuery has built-in queues, so we don&#8217;t need to build our own like this.</p>
<p>For an example, here&#8217;s a really simple asynchronous method, which will make an object yellow for five seconds.</p>
<pre class="brush: php">
$.fn.makeYellowForFiveSeconds = function() {
    // I&#039;m only using actions which act on jQuery objects, so I don&#039;t need to use &#039;each&#039; as above.
    this.css( { &#039;background-color&#039; : &#039;yellow&#039;, color : &#039;yellow&#039; } );
    // reset the colour in five seconds time
    var that = this;
    setTimeout(function() {
        that.css( { &#039;background-color&#039; : &#039;none&#039;, color : &#039;inherit&#039; } );
    }, 5000);
    // action the next method in the chain
    return this;
};
</pre>
<p>If we use the above function like so</p>
<pre class="brush: php">
$(&#039;#some-element&#039;).makeYellowForFiveSeconds().hide();
</pre>
<p>We&#8217;ll probably never see the yellow.  It&#8217;ll go yellow and disappear immediately.  Five seconds later, the yellow disappears, and we won&#8217;t know that either because it&#8217;s already hidden.  We need to recode to use the queue:</p>
<pre class="brush: php">
$.fn.makeYellowForFiveSeconds = function() {
    // I&#039;m only using actions which act on jQuery objects, so I don&#039;t need to use &#039;each&#039; as above.
    this.css( { &#039;background-color&#039; : &#039;yellow&#039;, color : &#039;yellow&#039; } );
    // reset the colour in five seconds time
    var that = this;
    this.queue(function() {
        setTimeout(function() {
            that.css( { &#039;background-color&#039; : &#039;none&#039;, color : &#039;inherit&#039; } );
            that.dequeue();
        }, 5000);
    });
    // action the next method in the chain
    return this;
};
</pre>
<p>Now when we execute again,</p>
<pre class="brush: php">
$(&#039;#some-element&#039;).makeYellowForFiveSeconds().hide();
</pre>
<p>It works as expected:  the element appears yellow for five seconds, and only then disappears.<br />
How did we get there?  Well, we just popped an item on the jQuery &#8216;fx&#8217; queue.  Then, when our action was completed, we called &#8216;dequeue&#8217; on the same jQuery object to allow the next animation to take place.</p>
<p>jQuery is very smart about queues.  Each queue is tagged to the specific object, so queued actions on one item won&#8217;t hold up actions on another object.  Of course if we <strong>wanted</strong> to do that, we&#8217;d just need to pick a common object to hold the queue, like the body.  And equally, if we wanted to run two queues on a particular object, we can do that too, because both queue and dequeue will accept a queueName as first parameter.  The default queue is &#8216;fx&#8217;, which is where the animation occurs.</p>
<p>jQuery&#8217;s queuing is powerful and smart.  I used it in the <a href="http://mclaren.com/home">mclaren.com</a> website build, to coordinate actions.  And of course, if you don&#8217;t like their implementation, you can always <a href="http://www.dustindiaz.com/async-method-queues/">roll your own</a>.</p>
<img src="http://feeds.feedburner.com/~r/KennethKufluk/~4/Uj49it72_tI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2010/08/chaining-asynchronous-methods-in-jquery-using-the-queue/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://kenneth.kufluk.com/blog/2010/08/chaining-asynchronous-methods-in-jquery-using-the-queue/</feedburner:origLink></item>
		<item>
		<title>Ten of the best HTML5 Spotify mashups</title>
		<link>http://feedproxy.google.com/~r/KennethKufluk/~3/VCMv6-ili-o/</link>
		<comments>http://kenneth.kufluk.com/blog/2010/07/ten-of-the-best-html5-spotify-mashups/#comments</comments>
		<pubDate>Sun, 25 Jul 2010 17:47:14 +0000</pubDate>
		<dc:creator>Kenneth</dc:creator>
				<category><![CDATA[Projects]]></category>

		<guid isPermaLink="false">http://kenneth.kufluk.com/blog/?p=725</guid>
		<description><![CDATA[Number 1:  moretrackstrackslikethis.com A useful mashup of lastfm&#8217;s &#8220;similar tracks&#8221; service and Spotify gives a great way to find new artists and music matching your tastes.  What&#8217;s particularly good is that you can match single tracks, so even if you only like one track by a certain artist, you can find good matches. Written in [...]]]></description>
			<content:encoded><![CDATA[<p>
<h2>Number 1:  <a href="http://moretrackslikethis.com">moretrackstrackslikethis.com</a></h2>
<p><a href="http://kenneth.kufluk.com/blog/wp-content/uploads/2010/07/Screen-shot-2010-07-25-at-14.47.43.png"><img src="http://kenneth.kufluk.com/blog/wp-content/uploads/2010/07/Screen-shot-2010-07-25-at-14.47.43-300x165.png" alt="" title="moretrackslikethis.com" width="300" height="165" class="alignright size-medium wp-image-726" /></a></p>
<p></p>
<p>A useful mashup of lastfm&#8217;s &#8220;similar tracks&#8221; service and Spotify gives a great way to find new artists and music matching your tastes.  What&#8217;s particularly good is that you can match single tracks, so even if you only like one track by a certain artist, you can find good matches.</p>
<p></p>
<p>Written in 100% Pure CSS3, HTML5 and JavaScript.</p>
<p></p>
<p>
<h2>Number 2: admission that this is just shameless link-bait</h2>
<p>There&#8217;s some other great mashups out there. Check <a href="http://www.spotify.com/int/about/resources/">Spotify&#8217;s list</a>.</p>
<p></p>
<img src="http://feeds.feedburner.com/~r/KennethKufluk/~4/VCMv6-ili-o" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2010/07/ten-of-the-best-html5-spotify-mashups/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://kenneth.kufluk.com/blog/2010/07/ten-of-the-best-html5-spotify-mashups/</feedburner:origLink></item>
		<item>
		<title>Lost – cutting a long story short</title>
		<link>http://feedproxy.google.com/~r/KennethKufluk/~3/WFRg4Fld9mA/</link>
		<comments>http://kenneth.kufluk.com/blog/2010/06/lost-cutting-a-long-story-short/#comments</comments>
		<pubDate>Tue, 01 Jun 2010 19:22:13 +0000</pubDate>
		<dc:creator>Kenneth</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[lost]]></category>

		<guid isPermaLink="false">http://kenneth.kufluk.com/blog/?p=708</guid>
		<description><![CDATA[Ok, so to sum up. There is an island. This certainly contains spoilers. If you haven&#8217;t done the Lost thang, you probably should, because they&#8217;re really good, so stop reading this and head off to Amazon. Otherwise, if you&#8217;ve seen it all, and read all about it on E!, and seen the deleted scenes on [...]]]></description>
			<content:encoded><![CDATA[<p>Ok, so to sum up.</p>
<p>There is an island.</p>
<p>This certainly contains spoilers.  If you haven&#8217;t done the Lost thang, you probably should, because they&#8217;re really good, so stop reading this and head off to Amazon.  Otherwise, if you&#8217;ve seen it all, and read all about it on E!, and seen the deleted scenes on DVD and so on, then you are truly qualified.  Do read on.<br />
<span id="more-708"></span></p>
<p>There is an island.</p>
<p>The island has various inherent powers.  It has a light in the middle.  It has a strong electromagnetic force which baffles compasses and is prone to explosion.  It is able to move, if a wheel is turned.  Should the wheel be dislodged, the island can also travel in time.  It is able to send people to the middle of a desert somewhere using the same wheel.</p>
<p>It has a large statue of an egyptian looking deity, and a smattering of ancient temples.</p>
<p>The island cannot be approached except by submarine, shipwreck or plane crash.  The island cannot be left except by wheel, or by following a single compass bearing.  People heal quickly on the island, regardless of the ailment.</p>
<p>A woman lives on the island.</p>
<p>One day a boat crashes on the island.  After helping the survivor give birth to two boys, she kills the mother and takes the boys as her own.</p>
<p>Time passes, the boys grow.</p>
<p>The fair haired boy is fairly happy with his lot.</p>
<p>The dark haired boy learns of his mother&#8217;s demise, and adoptive mother&#8217;s betrayal.  He leaves the family and joins another small village on the island.  He is keen to leave the island.</p>
<p>The other boy just shrugs.  Maybe he&#8217;s stoned or something.</p>
<p>The mother kills the villagers, and in turn is killed by the dark haired boy.  Before she dies, the mother gives her non-specific powers to the fair-haired boy, who throws his dark-haired-brother into a pool of light as punishment.  The dark-haired boy dies, but lives on as a smoke monster.  The smoke monster is able to take the form of dead people, and so becomes the dark-haired boy again.  He is far from happy.</p>
<p>Time passes.  One day, a tidal wave brings an old ship to the island, destroying the statue.  The ship is the Black Rock, and contains a fragile amount of dynamite, which is mostly used by a crazy French woman from Babylon 5.  The survivor of the shipwreck is offered eternal life by the fair-haired boy in return for eternal service.  He leads a small group of villagers, trying to do the &#8220;right thing&#8221;, though none of them know what this is, as the fair-haired boy never actually says what it is he wants.  Another group of villagers live in a temple not far away, but don&#8217;t seem to know any of this.  They too, are big fans of the fair-haired boy.  And karate.  They love that stuff.</p>
<p>At some point the island is discovered by scientists (the &#8220;Drama Initiative&#8221;), who hope to use the island to mankind&#8217;s advantage, and breed polar bears.  They achieve a peaceful standoff with the villagers, and establish a force-field to prevent the smoke monster killing people.  The smoke monster does not attack the villagers outside the perimeter, for reasons unclear.</p>
<p>The scientists cause a problem, meaning the eletromagnetic field must be vented on a regular basis.  They combine this with a psychological test by locking up the maintenance team, slap on some warnings of a virus outside, and then sit back and monitor them with video cameras.  When the team forget to vent, they are shown scary symbols, and lights flash.  Underwear is changd.  When the system eventually explodes, it actually causes no damage, except to the venting system itself, proving the entire system was something of a timewaster.</p>
<p>Faced with the most ridiculous pseudo-scientific endeavours since the invention of homeopathy, the villagers outside the perimeter rise up against the harmless hippy scientists, headed by the poor son of a drunken employee who is unhappy with his lot.  He leads the village and all are happy, though he does not permit them to leave. </p>
<p>The fair-haired boy decides to bring some new people to the island.  He does this by crashing a plane on it.  Many people are killed and injured.  Of the survivors, many are then killed by the smoke monster.  Of the survivors, many are killed by the villagers.  Of those survivors, many are killed in attempts to leave the island.  And of the few remaining survivors, some escape.</p>
<p>The majority of the escapees return to the island as soon as they are able, by crashing another plane on it.  Of those people, most are killed by attempts to escape again, by villagers, and by the smoke monster, who has arbitrarily taken the form of one of the original plane crash survivors.</p>
<p>Of the handful of subsequent survivors, the leader of the villagers kills the fair-haired boy, for treating him poorly for most of his life.  The fair-headed boy brushes it off like a bad smell, and still continues to plague the poor cursed humans he crashed on the place.</p>
<p>Some more people die.</p>
<p>The fair-headed boy offers the few remaining survivors the opportunity to take over the running of the island.  One volunteers.  He immediately does the opposite of everything he was meant to do.  The smoke monster becomes vulnerable and is killed.  He will never see Paris in the spring.  Woo-hoo.  The volunteer then dies.  Aw.  Someone else takes over, seconded by the leader of the villagers who has been accepted despite repeated killing and torture of other survivors.</p>
<p>The fair-headed boy is named Jacob.  He is able to travel anywhere at whim.  He brings people to the island knowing they will die.  He is able to assist or even offer immortality, but he does not.  He crashes planes for a bit of company.  For some reason, he is know as the Good Guy.</p>
<p>The dark-haired boy simply wishes to leave the island.  He cannot, for his brother killed him.  He kills bad guys and good guys alike, but brings no people to the island.  He seems no more morally corrupt than the survviors themselves, but is known as the Devil.</p>
<p>Is that fair?</p>
<p>Only Michael&#8217;s kid (&#8220;that&#8217;s MY boy&#8221;) and the Kwon&#8217;s kid (sob sob) leave the island in peace, and move on.  I think probably, they win.</p>
<p>Of course, at the final judgement, they&#8217;re all dead.  But they had a good time and made friends along the way.  So that&#8217;s all ok then.</p>
<img src="http://feeds.feedburner.com/~r/KennethKufluk/~4/WFRg4Fld9mA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2010/06/lost-cutting-a-long-story-short/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://kenneth.kufluk.com/blog/2010/06/lost-cutting-a-long-story-short/</feedburner:origLink></item>
		<item>
		<title>JS Fireworks – in SVG</title>
		<link>http://feedproxy.google.com/~r/KennethKufluk/~3/aTMjK-Hy3vI/</link>
		<comments>http://kenneth.kufluk.com/blog/2010/05/js-fireworks-in-svg/#comments</comments>
		<pubDate>Sun, 23 May 2010 14:28:45 +0000</pubDate>
		<dc:creator>Kenneth</dc:creator>
				<category><![CDATA[Projects]]></category>
		<category><![CDATA[canvas]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[svg]]></category>

		<guid isPermaLink="false">http://kenneth.kufluk.com/blog/?p=706</guid>
		<description><![CDATA[I&#8217;ve taken another look at last year&#8217;s Chrome Experiment, JS Fireworks. This time I&#8217;ve rewritten it to use SVG, whose arrival in IE9 promises to make HTML more interesting. In fact, I&#8217;m far more excited about animated SVG than CSS transforms and the fabled HTML5. I used Keith Wood&#8217;s jQuery SVG library, which seems quite [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve taken another look at last year&#8217;s Chrome Experiment, <a href="http://www.chromeexperiments.com/detail/js-fireworks/">JS Fireworks</a>.</p>
<p>This time I&#8217;ve rewritten it to use SVG, whose arrival in IE9 promises to make HTML more interesting.  In fact, I&#8217;m far more excited about animated SVG than CSS transforms and the fabled HTML5.</p>
<p>I used Keith Wood&#8217;s <a href="http://keith-wood.name/svg.html">jQuery SVG library</a>, which seems quite helpful, and simply replaced the &#8216;draw line&#8217; commands with their equivalents.</p>
<p>Canvas is the bitmap to SVG&#8217;s vector, so while I have to clear the screen and redraw each time in canvas, I merely need to move the lines in SVG.  Presumably the number of shapes on screen affects performance, so that was a big difference.</p>
<p>Here&#8217;s the result: <a href="http://js-fireworks.appspot.com/svg/index.html">JS-Fireworks in SVG</a>.  I&#8217;ve reduced the number of items in each explosion from 30 down to 10.  You&#8217;ll see why.</p>
<p>It runs very quickly in Chrome (Mac), slowly in FireFox, and <em>smoothly</em>, though not excessively quickly, in IE9, which I&#8217;m quite excited about.  Where&#8217;s IE9 Experiments?</p>
<p>I haven&#8217;t tried IE678.  But then I haven&#8217;t tried Mosaic either.</p>
<img src="http://feeds.feedburner.com/~r/KennethKufluk/~4/aTMjK-Hy3vI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2010/05/js-fireworks-in-svg/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://kenneth.kufluk.com/blog/2010/05/js-fireworks-in-svg/</feedburner:origLink></item>
		<item>
		<title>aitch-tee-tee-pee colon slash slash</title>
		<link>http://feedproxy.google.com/~r/KennethKufluk/~3/mtzn1dobTBM/</link>
		<comments>http://kenneth.kufluk.com/blog/2010/05/aitch-tee-tee-pee-colon-slash-slash/#comments</comments>
		<pubDate>Sat, 15 May 2010 11:05:38 +0000</pubDate>
		<dc:creator>Kenneth</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Ranting]]></category>

		<guid isPermaLink="false">http://kenneth.kufluk.com/blog/?p=702</guid>
		<description><![CDATA[It&#8217;s lovely to see someone stand up and take the blame for a mistake they&#8217;ve made. I&#8217;m not talking about the Government (obviously), I&#8217;m talking Tim Berners-Lee, inventor of the World-Wide Web. He&#8217;s come out and apologised for the redundant slashes that appear in every web address (url). Good man. But what of the rest? [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s lovely to see someone stand up and take the blame for a mistake they&#8217;ve made.  I&#8217;m not talking about the Government (obviously), I&#8217;m talking Tim Berners-Lee, inventor of the World-Wide Web.  He&#8217;s come out and <a href="http://news.bbc.co.uk/1/hi/8306631.stm">apologised for the redundant slashes</a> that appear in every web address (url).</p>
<p>Good man.  But what of the rest?  The &#8220;www.&#8221; that was so unpronounceable is already obsolete, and personally I think twitter can take credit for popularising the contemporary non-dubbed url form.  Boffins in lab coats has worked tirelessly to make memory ubiquitous and cheap, but we&#8217;ve just stuck some character limits in there to be fashionable or something.  Hey ho.  But the &#8220;www&#8221; is gone.</p>
<p>Can anyone tell me why there&#8217;s a huhtetep, &#8220;http:&#8221;, still shown in my address bar?  What&#8217;s it for?  What does it tell me?  I don&#8217;t actually have to type it in these days, but it appears there anyway.  Why?</p>
<p>Is it to show that I&#8217;m looking at a document provided by HyperText Transfer Protocol?  I don&#8217;t care about that!</p>
<p>Is it to show that I *could* be looking at an FTP site, using the same browser?  Ok, fair call, but that&#8217;s so rare to do so, that you could default to <em>not</em> showing &#8220;http:&#8221;, and then only show &#8220;ftp:&#8221; when FTP sites are used.  It&#8217;s not like every browser has a built-in FTP client anyway.  Same goes for local files.</p>
<p>Is it to show the &#8220;s&#8221; when I look at an &#8220;https&#8221; page, meaning that the connection between my browser and the website is encrypted?  Well, ok, but what was wrong with the padlock?  Why is there such a strong connection between certificates and https anyway?  They mean completely different things.  I don&#8217;t need a certificate to know gmail.com is Google.  Equally, a certificate costs about 20 bucks and has so few checks that I&#8217;m hardly reassured when dealing with a new site by the presence of the certificate.  What I want to see is a padlock.  Drop the &#8220;https&#8221; and show me a padlock.</p>
<p>Is it for future extensibility, to enable a future Internet to use new and unusual protocols?  Like &#8220;about:&#8221;?  Again, it would be simple enough to recognise a default of http.  If you go to about:config, then display the protocol.  Why is this hard?  If a new protocol came along to overtake http, then I think a bigger browser update would be needed anyway.</p>
<p>I think browser manufacturers should take treat it like the port.  Every web page is served by a port, and for most of the web, that&#8217;s port 80.  You could look at this website by typing http://kenneth.kufluk.com:80.  But mostly, the 80 is assumed.  You only ever type in a port if you&#8217;re not using port 80, such as for local development.  If you type &#8220;:80&#8243; into a web browser like Chrome, it disappears.  Let&#8217;s do that for &#8220;http://&#8221; as well.  if you&#8217;re thinking there might be confusion between ports and protocols, you&#8217;re wrong.  Protocols are letters-only, Internet domains need at least one dot, and ports are only numeric.</p>
<p>I&#8217;m using Chrome version 5, the latest in a long history of browsers.  Surely it&#8217;s long past time to kill off the http://.  And if you look closely, you&#8217;ll see the iPhone already has.</p>
<p><a href="http://upload.wikimedia.org/wikipedia/commons/7/74/Timeline_of_web_browsers.svg"><img alt="" src="http://upload.wikimedia.org/wikipedia/commons/7/74/Timeline_of_web_browsers.svg" title="History of Web Browsers" class="alignnone" width="240" height="178" /></a></p>
<img src="http://feeds.feedburner.com/~r/KennethKufluk/~4/mtzn1dobTBM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2010/05/aitch-tee-tee-pee-colon-slash-slash/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://kenneth.kufluk.com/blog/2010/05/aitch-tee-tee-pee-colon-slash-slash/</feedburner:origLink></item>
		<item>
		<title>Satchmo/Django: “ProgrammingError:  can’t adapt type ‘__proxy__’”</title>
		<link>http://feedproxy.google.com/~r/KennethKufluk/~3/yCRVR4Y0kXA/</link>
		<comments>http://kenneth.kufluk.com/blog/2010/05/satchmodjango-programmingerror-cant-adapt-type-__proxy__/#comments</comments>
		<pubDate>Wed, 05 May 2010 13:32:26 +0000</pubDate>
		<dc:creator>Kenneth</dc:creator>
				<category><![CDATA[Projects]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[satchmo]]></category>

		<guid isPermaLink="false">http://kenneth.kufluk.com/blog/?p=700</guid>
		<description><![CDATA[I got the above error when laoding a shipping module in Satchmo, but upon working out the cause, I reckoned it must be a pretty common error these days. The exception is raised in /django/db/backends/util.py, line 19. When I checked the local vars of the query.py step, line 2369, I got the following SQL: &#039;UPDATE [...]]]></description>
			<content:encoded><![CDATA[<p>I got the above error when laoding a shipping module in Satchmo, but upon working out the cause, I reckoned it must be a pretty common error these days.</p>
<p>The exception is raised in /django/db/backends/util.py, line 19.<br />
When I checked the local vars of the query.py step, line 2369, I got the following SQL:</p>
<pre class="brush: sql">
&#039;UPDATE &quot;shop_order&quot; SET &quot;site_id&quot; = %s, &quot;contact_id&quot; = %s, &quot;ship_addressee&quot; = %s, &quot;ship_street1&quot; = %s, &quot;ship_street2&quot; = %s, &quot;ship_city&quot; = %s, &quot;ship_state&quot; = %s, &quot;ship_postal_code&quot; = %s, &quot;ship_country&quot; = %s, &quot;bill_addressee&quot; = %s, &quot;bill_street1&quot; = %s, &quot;bill_street2&quot; = %s, &quot;bill_city&quot; = %s, &quot;bill_state&quot; = %s, &quot;bill_postal_code&quot; = %s, &quot;bill_country&quot; = %s, &quot;notes&quot; = NULL, &quot;sub_total&quot; = %s, &quot;total&quot; = %s, &quot;discount_code&quot; = %s, &quot;discount&quot; = %s, &quot;method&quot; = %s, &quot;shipping_description&quot; = %s, &quot;shipping_method&quot; = %s, &quot;shipping_model&quot; = %s, &quot;shipping_cost&quot; = %s, &quot;shipping_discount&quot; = %s, &quot;tax&quot; = %s, &quot;time_stamp&quot; = %s, &quot;status&quot; = %s WHERE &quot;shop_order&quot;.&quot;id&quot; = %s
</pre>
<p>with the following params:</p>
<pre class="brush: php">
(1, 761, u&#039;abc abc&#039;, u&#039;abc&#039;, u&#039;abcabc&#039;, u&#039;abc&#039;, u&#039;(UK32)&#039;, u&#039;E17 8QG&#039;, u&#039;GB&#039;, u&#039;abc abc&#039;, u&#039;abc&#039;, u&#039;abcabc&#039;, u&#039;abc&#039;, u&#039;(UK32)&#039;, u&#039;E17 8QG&#039;, u&#039;GB&#039;, u&#039;13.2500000000&#039;, u&#039;15.0000000000&#039;, &#039;&#039;, u&#039;0E-10&#039;, u&#039;Online&#039;, &#039;Dots Postage and Packing&#039;, &lt;django.utils.functional.__proxy__ object at 0x24142d0&gt;, &#039;dotship&#039;, u&#039;1.7500000000&#039;, u&#039;0E-10&#039;, u&#039;0E-10&#039;, u&#039;2010-05-05 14:13:07.134682&#039;, u&#039;&#039;, 713)
</pre>
<p>You can see the __proxy__ that shouldn&#8217;t be there.</p>
<p>Looking back at my code that provides that particular value, I found I&#8217;d used the _() shortcut, which in this file, is bound to ugettext_lazy.  Of course, this is the problem!  The lazy evaluation isn&#8217;t being executed before the query is evaluated.</p>
<p>To fix, either use gettext directly, or change the shortcut for _ from gettext_lazy to gettext.</p>
<img src="http://feeds.feedburner.com/~r/KennethKufluk/~4/yCRVR4Y0kXA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2010/05/satchmodjango-programmingerror-cant-adapt-type-__proxy__/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://kenneth.kufluk.com/blog/2010/05/satchmodjango-programmingerror-cant-adapt-type-__proxy__/</feedburner:origLink></item>
		<item>
		<title>Replacing the Satchmo homepage by overriding URLs</title>
		<link>http://feedproxy.google.com/~r/KennethKufluk/~3/5UGbEQBZYaY/</link>
		<comments>http://kenneth.kufluk.com/blog/2010/05/replacing-the-satchmo-homepage-by-overriding-urls/#comments</comments>
		<pubDate>Tue, 04 May 2010 09:39:05 +0000</pubDate>
		<dc:creator>Kenneth</dc:creator>
				<category><![CDATA[Projects]]></category>
		<category><![CDATA[django]]></category>

		<guid isPermaLink="false">http://kenneth.kufluk.com/blog/?p=698</guid>
		<description><![CDATA[You can override URLs used by Satchmo by using the built-in urlhelper. So my project urls.py looks a bit like this: from django.conf.urls.defaults import * from satchmo_store.urls import urlpatterns from django.conf import settings from satchmo_utils import urlhelper urlpatterns += patterns(&#039;&#039;, #add my normal urls here (r&#039;^blog/index/$&#039;, &#039;myblog.views.blogindex&#039;), (r&#039;^photos/&#039;, include(&#039;photoapp.urls&#039;)), ) urlhelper.replace_urlpatterns( urlpatterns, [ #add override [...]]]></description>
			<content:encoded><![CDATA[<p>You can override URLs used by Satchmo by using the built-in urlhelper.</p>
<p>So my project urls.py looks a bit like this:</p>
<pre class="brush: python">
from django.conf.urls.defaults import *

from satchmo_store.urls import urlpatterns

from django.conf import settings
from satchmo_utils import urlhelper

urlpatterns += patterns(&#039;&#039;,
    #add my normal urls here
    (r&#039;^blog/index/$&#039;, &#039;myblog.views.blogindex&#039;),
    (r&#039;^photos/&#039;, include(&#039;photoapp.urls&#039;)),
)

urlhelper.replace_urlpatterns(
    urlpatterns,
    [
        #add override urls here (match the name from satchmo&#039;s url files)
        url(r&#039;^$&#039;, &#039;myblog.views.homepage&#039;, {}, name=&#039;satchmo_shop_home&#039;),
    ]
)
</pre>
<img src="http://feeds.feedburner.com/~r/KennethKufluk/~4/5UGbEQBZYaY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2010/05/replacing-the-satchmo-homepage-by-overriding-urls/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://kenneth.kufluk.com/blog/2010/05/replacing-the-satchmo-homepage-by-overriding-urls/</feedburner:origLink></item>
		<item>
		<title>Building McLaren.com – Part 6:  Monitoring</title>
		<link>http://feedproxy.google.com/~r/KennethKufluk/~3/S4HxbJNedxg/</link>
		<comments>http://kenneth.kufluk.com/blog/2010/04/building-mclaren-com-part-6-monitoring/#comments</comments>
		<pubDate>Wed, 07 Apr 2010 16:17:52 +0000</pubDate>
		<dc:creator>Kenneth</dc:creator>
				<category><![CDATA[Work]]></category>
		<category><![CDATA[mclaren]]></category>

		<guid isPermaLink="false">http://kenneth.kufluk.com/blog/?p=646</guid>
		<description><![CDATA[I&#8217;ve just finished working on McLaren&#8217;s new F1 site, http://mclaren.com/home, for the 2010 season, at Pirata London, for Work Club. Part six, the last part, covers the monitoring tools. Of course, we&#8217;re using the standard Google Analytics monitoring, which is great at delivering summary stats for past events (or even earlier in the day if [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just finished working on McLaren&#8217;s new F1 site, <a href="http://mclaren.com/home">http://mclaren.com/home</a>, for the 2010 season, at <a href="http://www.piratalondon.com">Pirata London</a>, for <a href="http://www.work-club.com/">Work Club</a>.</p>
<p><a href="http://kenneth.kufluk.com/blog/wp-content/uploads/2010/03/mclaren-site-2010.png"><img src="http://kenneth.kufluk.com/blog/wp-content/uploads/2010/03/Screen-shot-2010-03-31-at-13.02.12-300x213.png" alt="" title="The new McLaren F1 site for 2010" width="300" height="213" class="alignnone size-medium wp-image-595" /></a></p>
<p>Part six, the last part, covers the monitoring tools.<span id="more-646"></span></p>
<p>Of course, we&#8217;re using the standard Google Analytics monitoring, which is great at delivering summary stats for past events (or even earlier in the day if you go and move the dates to include today).  I&#8217;ve implemented the newer asynchronous calls of course.</p>
<p>For <strong>real-time</strong> monitoring of stats, we&#8217;re using two tools.  One, we merge the subscriber counts returned from nginx to show the number of viewers during the race.</p>
<p>Second, we use <a href="http://chartbeat.com">ChartBeat</a>.  It is <em>awesome</em>.<br />
<img src="http://kenneth.kufluk.com/blog/wp-content/uploads/2010/04/Screen-shot-2010-04-01-at-10.40.00-300x234.png" alt="" title="chartbeat - great realtime stats" width="300" height="234" class="alignnone size-medium wp-image-647" /></p>
<p>There&#8217;s a limited amount I can show here, since the dashboard screen is quite interactive.  The stats show above are for a random weekday morning just before Easter, and so are quite low.</p>
<p>Click here to view <a href="http://chartbeat.com/dashboard/?url=kenneth.kufluk.com&#038;k=29a30ae6190da31dfe34743eb1c5a651">live stats for this site</a> (though it&#8217;s probably only you watching right now).</p>
<p>While our visitors are screen-switching between our website and the TV footage, we&#8217;re also toggling to ChartBeat.  It&#8217;s been a great help to be able to watch the subscriber counts, mix in the twitter feedback, and see exactly where everyone is.</p>
<p>However, we found that while we can see visitors watching for up to two hours on ChartBeat, our &#8220;average time on site&#8221; recorded for Google Analytics was tiny &#8211; around two minutes!</p>
<h2>Accounting for the Google Analytics &#8220;Time on Site&#8221; discrepancy</h2>
<p>Checking through GA&#8217;s documentation reveals the reason for the difference.</p>
<blockquote><p>In order to capture the length of a visit, Google Analytics tracks the elapsed time between pageviews. The last page of a visit will not be recorded (as there is no subsequent pageview).</p></blockquote>
<p><a href="http://www.google.com/support/googleanalytics/bin/answer.py?hl=en&#038;answer=57044">http://www.google.com/support/googleanalytics/bin/answer.py?hl=en&#038;answer=57044</a></p>
<p>So if you have a page which is viewed for a significant period of time, and is then closed without further interaction, your visit durations can be seriously compromised.</p>
<p>Our solution is to use Event Tracking to log an event every minute.</p>
<pre class="brush: jscript">
	// Ping google analytics every minute to show accurate figures for &quot;time on site&quot; and &quot;length of visit&quot;.
	// this can also decrease &quot;bounce rate&quot; figures.
	// one minute is the recommended interval
	var gaPing = setInterval(function() {
		//using the async tracking calls
		_gaq.push([&#039;_trackEvent&#039;, &#039;SomeSortOfCategory&#039;, &#039;SomeSortOfAction&#039;]);
	}, 60 * 1000);
</pre>
<p>Since implementing this code, we&#8217;ve had a lot less disparity between ChartBeat and GA figures, though there is still some (<10%).</p>
<p>The recommended view for Google Analytics for viewing something like a race, which lasts for just two hours, is to go to:<br />
Visitors &gt; Visitor Trending &gt; Time on Site<br />
Choose the <em>day</em> that you&#8217;re interested in.<br />
Then click the little &#8216;hour&#8217; icon in the top right (hadn&#8217;t noticed that had you?)<br />
<img src="http://kenneth.kufluk.com/blog/wp-content/uploads/2010/04/Screen-shot-2010-04-01-at-11.05.06.png" alt="" title="clock icon" width="162" height="46" class="alignnone size-full wp-image-649" /></p>
<p>And we finally get some real stats.  Our average visit length is now well over an hour during the race, which is <em>huge</em>.<br />
<a href="http://kenneth.kufluk.com/blog/wp-content/uploads/2010/04/time-on-site.png"><img src="http://kenneth.kufluk.com/blog/wp-content/uploads/2010/04/time-on-site-293x300.png" alt="" title="time-on-site" width="293" height="300" class="alignnone size-medium wp-image-650" /></a></p>
<h2>A warning on tag expiry</h2>
<p>Both ChartBeat and Google have an upper limit on views.  Google will record a maximum of <a href="http://code.google.com/apis/analytics/docs/tracking/eventTrackerGuide.html#implementationConsiderations">500 tags per user session</a>, which is fine is we keep our pings to a minute.  ChartBeat has a limit of two hours, which causes a noticeable false dropoff towards the end of our races.</p>
<h2>Wrapping up</h2>
<p>Ok, I think that&#8217;s all that needs to be shared in this series.  If you have any extra questions, let me know.  If you&#8217;re working on a large-scale realtime data server, and need me for some consulting/development <em>definitely</em> give me a call.  And if you think there&#8217;s a better way to do all of this, let me know as well.</p>
<img src="http://feeds.feedburner.com/~r/KennethKufluk/~4/S4HxbJNedxg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2010/04/building-mclaren-com-part-6-monitoring/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://kenneth.kufluk.com/blog/2010/04/building-mclaren-com-part-6-monitoring/</feedburner:origLink></item>
		<item>
		<title>Building McLaren.com – Part 5: Serving from the Cloud</title>
		<link>http://feedproxy.google.com/~r/KennethKufluk/~3/jT0G4rMSWd0/</link>
		<comments>http://kenneth.kufluk.com/blog/2010/04/building-mclaren-com-part-5-serving-from-the-cloud/#comments</comments>
		<pubDate>Wed, 07 Apr 2010 16:14:43 +0000</pubDate>
		<dc:creator>Kenneth</dc:creator>
				<category><![CDATA[Work]]></category>
		<category><![CDATA[mclaren]]></category>

		<guid isPermaLink="false">http://kenneth.kufluk.com/blog/?p=633</guid>
		<description><![CDATA[I&#8217;ve just finished working on McLaren&#8217;s new F1 site, http://mclaren.com/home, for the 2010 season, at Pirata London, for Work Club. I&#8217;ll be writing up what we&#8217;ve done here in several parts. Sign up for my RSS feed to keep updated. Part five covers the setting up of broadcast servers using Amazon EC2. If you&#8217;ve never [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just finished working on McLaren&#8217;s new F1 site, <a href="http://mclaren.com/home">http://mclaren.com/home</a>, for the 2010 season, at <a href="http://www.piratalondon.com">Pirata London</a>, for <a href="http://www.work-club.com/">Work Club</a>.</p>
<p><a href="http://kenneth.kufluk.com/blog/wp-content/uploads/2010/03/mclaren-site-2010.png"><img src="http://kenneth.kufluk.com/blog/wp-content/uploads/2010/03/Screen-shot-2010-03-31-at-13.02.12-300x213.png" alt="" title="The new McLaren F1 site for 2010" width="300" height="213" class="alignnone size-medium wp-image-595" /></a></p>
<p>I&#8217;ll be writing up what we&#8217;ve done here in several parts.  Sign up for my <a href="http://feeds.feedburner.com/KennethKufluk">RSS feed</a> to keep updated.</p>
<p>Part five covers the setting up of broadcast servers using Amazon EC2.<span id="more-633"></span></p>
<p><strong>If you&#8217;ve never worked with Amazon EC2 before, please follow my &#8216;<a href="http://kenneth.kufluk.com/blog/2010/03/getting-started-with-amazon-ec2/">Getting Started</a>&#8216; guide first.</strong></p>
<p>In a previous part, we covered nginx setup set-by-step, so this time we&#8217;re going to look at creating a set of cloud servers with a single line of code.</p>
<h2><a name="setup_using_a_script" id="setup_using_a_script">Setup using a script</a></h2>
<p>Required:  ec2 command line tools</p>
<p>Amazon AMIs allow you to pass &#8216;user-data&#8217; into the image.  The alestic AMIs are configured to allow this data to be executed as soon as the machine starts.  For more on this, have a look at their article &#8220;<a href="http://alestic.com/2009/06/ec2-user-data-scripts">Automate EC2 Instance Setup with user-data Scripts</a>&#8220;.</p>
<p>I&#8217;m going to use a script called &#8220;<a href="http://kenneth.kufluk.com/pirata/install-nginx-mclaren">install-nginx-mclaren</a>&#8220;.  Save it to your working folder now, and execute the lines below from the same folder.<br />
This script was quite hard to write, due to various complications with the way the script gets passed in.  Line breaks are particularly difficult, and it&#8217;s always hard to set values deep in a configuration file using a script.
</p>
<pre class="code">ec2-run-instances -n 1 --key mclarenkey --user-data-file install-nginx-mclaren ami-bdc0ebc9 -t c1.xlarge</pre>
<p>where <code>&#039;n</code>&#039; is the number of instances to start.</p>
<p>
This starts a 64-bit 8-core 7GB “High-CPU Extra Large” Server running an Ubuntu 9.10 Karmic AMI, from Alestic.com
</p>
<p>
Your server is now visible in the Amazon AWS Management Console.
</p>
<p>
After around a minute, your servers should be running.  You can view them by typing:
</p>
<pre class="code">ec2-describe-instances</pre>
<p>Response:
</p>
<pre class="code">[Deprecated] Xalan: org.apache.xml.res.XMLErrorResources_en_US
RESERVATION	r-66ca1711	893696797735	default
INSTANCE	i-ecde7c9b	ami-b3c0ebc7	ec2-12-345-67-89.eu-west-1.compute.amazonaws.com	ip-10-226-42-19.eu-west-1.compute.internal	running	mclarenkey	0		m1.small	2010-03-16T10:50:47+0000	eu-west-1a	aki-b02a01c4	ari-39c2e94d		monitoring-disabled	12.345.67.89	10.226.42.19			ebs
BLOCKDEVICE	/dev/sda1	vol-62967b0b	2010-03-16T10:50:57.000Z	</pre>
<p>You can now see the Public <acronym title="Domain Name System">DNS</acronym> to connect.<br/></p>
<p>When using ssh, connect as user “ubuntu” (this is related to the choice of AMI)<br/></p>
<pre class="code">ssh -i ~/.ssh/mclarenkey.pem ubuntu@ec2-12-345-67-89.eu-west-1.compute.amazonaws.com</pre>
<p>It will take a few minutes for the setup script to run.  You can watch it in action like so:
</p>
<pre class="code">tail -f /var/log/syslog</pre>
<p>Our server is now running!
</p>
<p>
View it here:
</p>
<pre class="code">http://ec2-12-345-67-89.eu-west-1.compute.amazonaws.com/</pre>
<p>If all is well, you&#8217;ll be sent straight to mclaren.com!<br />
More useful are the feed urls:</p>
<pre class="code">http://ec2-12-345-67-89.eu-west-1.compute.amazonaws.com/feed/publish

http://ec2-12-345-67-89.eu-west-1.compute.amazonaws.com/feed/subscribe</pre>
<p>Remember to pop into your nginx conf file and configure your POST IPs!</p>
<p>In the final part in the series, I&#8217;ll cover monitoring.</p>
<img src="http://feeds.feedburner.com/~r/KennethKufluk/~4/jT0G4rMSWd0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2010/04/building-mclaren-com-part-5-serving-from-the-cloud/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://kenneth.kufluk.com/blog/2010/04/building-mclaren-com-part-5-serving-from-the-cloud/</feedburner:origLink></item>
	</channel>
</rss>
