<?xml version="1.0" encoding="UTF-8"?>
<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/"
	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/"
	>

<channel>
	<title>Kenneth&#039;s Universe &#187; Projects</title>
	<atom:link href="http://kenneth.kufluk.com/blog/blog/projects/feed/" rel="self" type="application/rss+xml" />
	<link>http://kenneth.kufluk.com/blog</link>
	<description>The guy with the unreadable blog.</description>
	<lastBuildDate>Tue, 27 Dec 2011 16:53:50 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Five things you don&#8217;t know</title>
		<link>http://kenneth.kufluk.com/blog/2011/12/five-things-you-dont-know/</link>
		<comments>http://kenneth.kufluk.com/blog/2011/12/five-things-you-dont-know/#comments</comments>
		<pubDate>Thu, 01 Dec 2011 05:27:58 +0000</pubDate>
		<dc:creator>Kenneth</dc:creator>
				<category><![CDATA[Projects]]></category>

		<guid isPermaLink="false">http://kenneth.kufluk.com/blog/?p=982</guid>
		<description><![CDATA[&#8230; until you have a baby. They come prefilled with poo They have very sharp fingernails They don&#8217;t just sleep and cry &#8211; they spend a lot of time awake They spend an inordinate amount of time and energy straining &#8230; <a href="http://kenneth.kufluk.com/blog/2011/12/five-things-you-dont-know/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>&#8230; until you have a baby.</p>
<ul>
<li>They come <a href="http://en.wikipedia.org/wiki/Meconium">prefilled with poo</a></li>
<li>They have very sharp fingernails</li>
<li>They don&#8217;t just sleep and cry &#8211; they spend a lot of time awake</li>
<li>They spend an inordinate amount of time and energy straining to fart</li>
<li>Adults have very big peculiar heads</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2011/12/five-things-you-dont-know/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The whole shebang</title>
		<link>http://kenneth.kufluk.com/blog/2011/07/the-whole-hashbang/</link>
		<comments>http://kenneth.kufluk.com/blog/2011/07/the-whole-hashbang/#comments</comments>
		<pubDate>Sat, 23 Jul 2011 21:44:38 +0000</pubDate>
		<dc:creator>bob</dc:creator>
				<category><![CDATA[Projects]]></category>

		<guid isPermaLink="false">http://kenneth.kufluk.com/blog/?p=949</guid>
		<description><![CDATA[My colleagues have been amicably bickering, online and offline, about the use of hashbangs. Ben Cherry explains that HashBangs are necessary, though not pretty, temporary workarounds to the lack of pushState support, which is part of the HTML5 spec. http://www.adequatelygood.com/2011/2/Thoughts-on-the-Hashbang &#8230; <a href="http://kenneth.kufluk.com/blog/2011/07/the-whole-hashbang/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>My colleagues have been amicably bickering, online and offline, about the use of hashbangs.</p>
<p>Ben Cherry explains that HashBangs are necessary, though not pretty, temporary workarounds to the lack of pushState support, which is part of the HTML5 spec.<br />
<a href="http://www.adequatelygood.com/2011/2/Thoughts-on-the-Hashbang">http://www.adequatelygood.com/2011/2/Thoughts-on-the-Hashbang</a></p>
<p>Dan Webb explains that this temporary workaround goes against the fundamental rule that &#8220;cool URIs don&#8217;t change&#8221;, and that they are bad for the web in general.<br />
<a href="http://danwebb.net/2011/5/28/it-is-about-the-hashbangs">http://danwebb.net/2011/5/28/it-is-about-the-hashbangs</a></p>
<p>When we discuss this sort of thing, we&#8217;re talking about the web in general, not about any Twitter pages, URLs, sites or strategy. Our personal sites are for personal opinions.<span id="more-949"></span></p>
<p>Dan and Ben have strong points, but I think the Internet is sufficiently large as to accommodate a variety of architectures. While building one way may simply be better, for excellent reasons, than another way, one is often forced to choose the lesser route due to external constraints.</p>
<p>New Twitter is a good example: a clientside application built using JavaScript. Besides the obvious UI upgrade, there was also a desire to reduce the load on our servers, and leverage our own API. This enabled us to concentrate resources on scaling and bugfixing the API in the backend (good for everyone), while letting frontend developers iterate quickly against an agreed specification. It was a win-win architecture.</p>
<p>The result is an application which needs to allow navigation without server calls. Thus the hashbang in the URL. It&#8217;s a necessary consequence of the requirements of the project.</p>
<p>Dan does raise some excellent points that the hashbangs cause problems. Returning to a hypothetical example, we might still have reasons not to rearchitect back to the classical page-request method. So we should address the problems Dan raises directly.</p>
<p><strong>1 Spiders should execute JavaScript</strong></p>
<p>There&#8217;s essentially no reason why a spider shouldn&#8217;t be executing some form of JavaScript. It&#8217;s mature enough. We&#8217;re using JavaScript to write out our content, and so the spider should be able to execute our JavaScript before it evaluates our DOM for content. It merely needs to know when the page is ready for this to happen.</p>
<p><strong>2 Ajax pages need a &#8216;Page Loaded&#8217; event</strong></p>
<blockquote><p>Spiders and search indexers can and do sometimes implement JavaScript runtimes. However, even in this case there’s no well recognised way to say ‘this is a redirect’ or ‘this content is not found’ in a way that non-humans will understand.</p></blockquote>
<p>We just need this specification. Let us have a way to signal HTTP response code equivalents like 404, 500 and &#8220;Page complete&#8221; through manipulation of the DOM with JavaScript.</p>
<p><strong>3 Hashbangs are a fallback</strong></p>
<p>The <a href="http://code.google.com/web/ajaxcrawling/docs/getting-started.html">original hashbang proposal</a> from Google aliases hashbanged urls to _escaped_fragment_ querystring parameters, allowing it to read the content of hashbanged urls as a server-side rendered page. I don&#8217;t believe this is a good system.</p>
<p>For a start, our linked URLs should be &#8216;cool&#8217;. It is only JavaScript that should add the hashbang, in browsers that need it. For example:</p>
<pre>&lt;a href="/kpk"&gt;Kenneth&lt;/a&gt;
&lt;script&gt;if ($.browser.msie) $('a').click(function(){location.hash='!'+this.href;return false});&lt;/script&gt;</pre>
<p>When Google reads this link, it should request &#8216;/kpk&#8217;. As our page is a clientside app, the server will respond with a redirect to &#8216;/&#8217;, then a pushState back to &#8216;/kpk&#8217;, before rendering the content to the DOM. If we can then trigger a &#8216;page loaded&#8217; event, Google can start reading our content.</p>
<p><strong>4 Hashbangs should be invisible</strong></p>
<p>A hashbang is a temporary workaround for the lack of pushState. While our links should only be hashbanged for the non-pushState browsers, Google may still find a hashbang in a URL. As such, Google should regard it as invisible. The URL it saves should be the URL without a hashbang.</p>
<p>For example,<br />
Spider finds link to http://twitter.com/#!kpk<br />
Spider saves link as http://twitter.com/kpk<br />
Spider finds link to http://twitter.com/#!kpk/mentions?page=10<br />
Spider saves link as http://twitter.com/kpk/mentions?page=10</p>
<p>This lets us switch to Cool URLs with pushState when and where it becomes available. It lets us use canonical urls. And should we choose to revert to a client/server model later on, we are able to do so.</p>
<p><strong>5 Hashbangs should be eternally supported</strong></p>
<blockquote><p>Once you hashbang, you can&#8217;t go back.</p></blockquote>
<p>Once a URL is made visible, you should be committed to maintaining that link forever. Fortunately, hashbanged URLs are easy to replace, if they&#8217;ve been designed invisibly. If you don&#8217;t use hashbangs anymore, just render them invisible with this script on your homepage:</p>
<pre>&lt;script&gt;if (location.hash.charAt(1)=='!') location.replace(location.hash.substr(2));&gt;&lt;/script&gt;</pre>
<p>&nbsp;</p>
<p>So, in summary, I suggest we (or rather, Google, as the authority over content reading) should accept the clientside application on its own terms, rather than as an alias to a server-side application. For while the client-server model has certain inherent advantages, there will still be occasions when a clientside application is more appropriate.</p>
<p>We can support that by changing the rules on interpreting hashbangs, and by introducing a DOM element controlled by JavaScript that describes the page status.</p>
<p><script type="text/javascript">// <![CDATA[
if (location.hash.charAt(1)=='!') location.replace(location.hash.substr(2));>
// ]]&gt;</script></p>
]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2011/07/the-whole-hashbang/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8220;the nerdiest thing I&#8217;ve seen all day&#8221;</title>
		<link>http://kenneth.kufluk.com/blog/2011/07/the-nerdiest-thing-ive-seen-all-day/</link>
		<comments>http://kenneth.kufluk.com/blog/2011/07/the-nerdiest-thing-ive-seen-all-day/#comments</comments>
		<pubDate>Tue, 19 Jul 2011 04:12:26 +0000</pubDate>
		<dc:creator>Kenneth</dc:creator>
				<category><![CDATA[Projects]]></category>

		<guid isPermaLink="false">http://kenneth.kufluk.com/blog/?p=945</guid>
		<description><![CDATA[In between the hours spent coding the hardcore JavaScript behind New Twitter, I like to put together fun little JavaScript demos. They get shown, if they&#8217;re good enough, on the screens around the office. Today&#8217;s is a tribute to the &#8230; <a href="http://kenneth.kufluk.com/blog/2011/07/the-nerdiest-thing-ive-seen-all-day/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In between the hours spent coding the hardcore JavaScript behind New Twitter, I like to put together fun little JavaScript demos. They get shown, if they&#8217;re good enough, on the screens around the office.</p>
<p>Today&#8217;s is a tribute to the almighty Matrix. <span id="more-945"></span>Although they sadly never made any sequels, and the effects have been copied so often they now seem cliché, it was an outstanding film of its time.</p>
<p>So here it is: a Twitter List timeline, shown as a Matrixy matrix:<br />
<a href="http://kenneth.kufluk.com/matrix/"> http://kenneth.kufluk.com/matrix/</a></p>
<p>Initially, I wanted to have the tweets scrolling down the page using CSS animations. Sadly, my machine got completely overwhelmed with only a few streams. I would&#8217;ve turned to my friend the canvas, but our display screens are something like 1900&#215;800 and slow, which makes full-screen canvas too jerky. So I just rendered a large set of absolutely positioned divs, one for each character.</p>
<p>Reading the text is a bit tricky. I supposed that in an ideal world, the tweets would stream upwards, but I didn&#8217;t want to deviate so far from the original. And so the tweets stream down the screen, and are mostly unreadable. I have tried reversing the text, but that simply makes them harder to read. English is not a language designed for reading bottom to top.</p>
<p>The image in the background is taken from a png. I draw it to a hidden canvas, but draw it scaled to the same dimensions (pixels) as the grid (characters). Then, I work out the visibility (brightness+opacity) of each (now-pixellated) pixel. This is added to the &#8220;bg_opacity&#8221; property of the grid cell, which is combined with the opacity of the current character to give the effect.</p>
<p>It&#8217;s quite easy to swap out the list and the image, and to tune the character size, just by editing variables at the top of the script.</p>
<p>The code is, naturally, on Github:<br />
<a href="https://github.com/kennethkufluk/Twitter-Matrix"> https://github.com/kennethkufluk/Twitter-Matrix</a></p>
<p>Have a play, have a tinker. Let me know how I could improve the effect, and improve the performance.</p>
<p><strong>Update:</strong></p>
<p>I jiggled the code around a bit.  Instead of absolutely positioning each character, and setting their content and opacity each time, I now insert a row of characters at a time.  The row has spans for setting each char&#8217;s opacity.  The bird image is now a translucent canvas overlay.</p>
<p>Performance is significantly better, and you can use Inspector without crashing the browser, but the layering doesn&#8217;t seem to work reliably in Chrome.  I&#8217;m not sure why.  So sometimes you just don&#8217;t see the bird.</p>
<p>And when you see super-wide Unicode characters, it can upset the grid a bit.  I haven&#8217;t worried about that.</p>
<p><strong>Update 2</strong></p>
<p>I took away &#8220;-webkit-transform-style: preserve-3d;&#8221; from the body tag, and the z-indexed layers now work properly.</p>
]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2011/07/the-nerdiest-thing-ive-seen-all-day/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Comcast</title>
		<link>http://kenneth.kufluk.com/blog/2010/12/comcast/</link>
		<comments>http://kenneth.kufluk.com/blog/2010/12/comcast/#comments</comments>
		<pubDate>Tue, 28 Dec 2010 04:13:29 +0000</pubDate>
		<dc:creator>Kenneth</dc:creator>
				<category><![CDATA[Projects]]></category>

		<guid isPermaLink="false">http://kenneth.kufluk.com/blog/?p=837</guid>
		<description><![CDATA[I think this guy may have a Genuine People Personality™. Kenneth > Hi. I expected installation yesterday evening, but no engineer arrived. Please can you confirm appointment time? Ely > Hello Kenneth_, Thank you for contacting Comcast Live Chat Support. &#8230; <a href="http://kenneth.kufluk.com/blog/2010/12/comcast/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I think this guy may have a <a href="http://en.wikipedia.org/wiki/Technology_in_The_Hitchhiker's_Guide_to_the_Galaxy">Genuine People Personality</a>™.</p>
<p>Kenneth > Hi.  I expected installation yesterday evening, but no engineer arrived.  Please can you confirm appointment time?</p>
<p>Ely > Hello Kenneth_, Thank you for contacting Comcast Live Chat Support. My name is Ely. Please give me one moment to review your information.<span id="more-837"></span></p>
<p>Ely > It&#8217;s nice to have you in chat! I always remain committed and determined to deliver the best customer service experience this day to you, as a valued customer of Comcast. Before anything else, I would like to thank you for giving me the opportunity to help and resolve your issue today through this chat. Despite the issue, I still honestly hope you&#8217;re doing fine, Kenneth.</p>
<p>Ely > Let me begin this conversation by letting you know how sorry I am for the trouble you are experiencing right now. I have been through this, myself. I understand what you are going through and this has not been a simple inconvenience on your part. To completely brighten up your day, let me tell you that this issue and your satisfaction are my top priorities for today.</p>
<p>Ely > I understand that you were supposed to have an installation yesterday but no one came. Is that correct, Kenneth?</p>
<p>Kenneth_ > yes</p>
<p>Ely > I see. I understand the importance of being able to confirm your installation of your services. I do apologize for the incovnience that this has caused you. I can definitely take care of this for you today.</p>
<p>Ely > While pulling up your account, let me share with you one of our FREE services. Comcast.net: your gateway to a world of online entertainment. Enjoy full access to Comcast.net where you can share photos, listen to your favorite music, shop, and play games. Check TV listings and access over 13,000 news and entertainment videos from Fox Sports, E!, and more.</p>
<p>Ely > So how are you doing today, Kenneth?</p>
<p>Kenneth_ > No, stop being chatty and marketing.</p>
<p>Ely > I apologize about that, Kenneth. I will refrain now. But yes let us go ahead and confirm your installation.</p>
<p>Ely > So your installation was indeed supposed to be 12/14 at 4-6PM.</p>
<p>Kenneth_ > Ok, so what happened?  No phone call, no email, no engineer.</p>
<p>Ely > I do apologize about that, Kenneth. I am afraid I am not to sure either on what happened for there are no pertinent information here in your account either left by the local office that were supposed to be handling the installation.</p>
<p>Kenneth_ > and there&#8217;s no pertinent information on the account?  how can that happen?<br />
Kenneth_ > I mean, I&#8217;m a new customer, and already I&#8217;m unhappy.  <strong>How is this a good way to do business?</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2010/12/comcast/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Nobody has wished me a Merry Christmas</title>
		<link>http://kenneth.kufluk.com/blog/2010/12/nobody-has-wished-me-a-merry-christmas/</link>
		<comments>http://kenneth.kufluk.com/blog/2010/12/nobody-has-wished-me-a-merry-christmas/#comments</comments>
		<pubDate>Fri, 24 Dec 2010 21:25:18 +0000</pubDate>
		<dc:creator>Kenneth</dc:creator>
				<category><![CDATA[Projects]]></category>

		<guid isPermaLink="false">http://kenneth.kufluk.com/blog/?p=844</guid>
		<description><![CDATA[In a land of excesses and enthusiasm, of Macy&#8217;s and Hollywood, we expected Christmas to be something of a big deal. We can hardly expect to celebrate with our usual joie de vivre, pulling crackers over a wobbly napkin-strewn table &#8230; <a href="http://kenneth.kufluk.com/blog/2010/12/nobody-has-wished-me-a-merry-christmas/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In a land of excesses and enthusiasm, of Macy&#8217;s and Hollywood, we expected Christmas to be something of a big deal.</p>
<p>We can hardly expect to celebrate with our usual joie de vivre, pulling crackers over a wobbly napkin-strewn table waiting for plates filled with myriad festive stodge, hot and cold, while our family plays the tradition games of &#8216;who can have the loudest conversation&#8217;.</p>
<p>Alas, we are stuck away from home and cannot partake.  I am disappointment incarnate.<span id="more-844"></span></p>
<p>As a child, Christmas has a very tangible quality &#8211; the crinkly stockings stuffed with chocolate money, small toys and a tangerine.  Waking up to the smell of the Christmas tree, heightened by the central heating and windows closed against the cold.  Crisply wrapped presents to be opened and enjoyed, only to be ignored and forgotten the very next day.  The only day of the year with no TV.</p>
<p>As an adult it becomes more awkward.  It becomes more about meeting family.  Relatives you haven&#8217;t seen since the last Christmas have somehow grown more distant.  You have less in common, and talk is trapped down to roads and weather.  And roads.  And weather.  You spend the day in with a vague sense of deja vu, as every conversation becomes a repeat from the year before.</p>
<p>But the English <em>do</em> Christmas.  We just do.  It&#8217;s like sprouts &#8211; it may not be any good, but we&#8217;re damn well going to celebrate it.  It feels <em>special</em>.</p>
<p>The build-up starts in October &#8211; as we have no Thanksgiving, and Halloween is little distraction.  George Michael mourns his last Christmas (you think he&#8217;d learn) from every pine-laden storefront.  Oxford Street is inaccessible to all but the bravest buyer from mid-November.  The weather gets colder &#8211; a lot colder &#8211; and the nights draw in.  Sunset is at around 3pm, and it feels properly dark, all the time.</p>
<p>It&#8217;s not a religious thing.  Christmas is a national event, not a religious one.  It has two public holidays: Christmas Day and <a href="http://en.wikipedia.org/wiki/Boxing_day">Boxing Day</a>.  We celebrate with Father Christmas, trees, gifts, mistletoe, snow, reindeer, holly, and food.  Nothing religious, nor offensive, there.</p>
<p>So here we are in San Francisco, and you could argue that it&#8217;s the same.  The shops have enormous wreathes on the front, and equally gigantic trees.  We saw workers spend three days building the tree in Union Square.  Building?  Yes, building.  They start with a normal tree, and the screw in extra branches to fill out the gaps and make it rounded.  Shocked?  It was like finding out there&#8217;s no Santa.  But apart from shattering one 32-year-old&#8217;s illusions of trees, there&#8217;s no harm done.  It looks good.</p>
<p>So there&#8217;s trees, and Santa, and elves, reindeer and all the rest.  How is it different?</p>
<p>I&#8217;m not sure.  There&#8217;s something missing.</p>
<p>&#8220;Happy Holidays&#8221; seems so disingenuous to me, an Englishman (or &#8220;Brit&#8221;, as they would have me).  But that&#8217;s ok &#8211; it rarely gets mentioned.  I remember that last Christmas I walked through St Pancras station, and they&#8217;d employed someone to spend all day dressed in Dickensian garb, to bow grandly and wish everyone in the station a very Merry Christmas.  It felt real.</p>
<p>This just feels like a day off.  Nobody has wished me a Merry Christmas here.  We need that guy.</p>
<p>Tomorrow, Christmas Day, we&#8217;ll be headed to Safeway.  It&#8217;ll be open, and so will Starbucks.<br />
We&#8217;ll get our coffees, then go for a walk along the beach.  In the sunshine.<br />
We hope your Christmas is a bit more Christmassy.</p>
<p>From eight hours behind, and five thousand miles away, Merry Christmas to everyone!</p>
]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2010/12/nobody-has-wished-me-a-merry-christmas/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Dynamic Twitter Icon with Greasemonkey script in Chrome</title>
		<link>http://kenneth.kufluk.com/blog/2010/11/dynamic-twitter-icon-with-greasemonkey-script-in-chrome/</link>
		<comments>http://kenneth.kufluk.com/blog/2010/11/dynamic-twitter-icon-with-greasemonkey-script-in-chrome/#comments</comments>
		<pubDate>Sun, 28 Nov 2010 03:05:38 +0000</pubDate>
		<dc:creator>Kenneth</dc:creator>
				<category><![CDATA[Projects]]></category>

		<guid isPermaLink="false">http://kenneth.kufluk.com/blog/?p=823</guid>
		<description><![CDATA[As a quick response to @ev Also, it would be great if tweets updated automatically, and is it possible to have the favicon turn red when there&#8217;s new tweets? #AskEv 15th October 2010 8:41 pm via webReplyRetweetFavorite @orismology Dominic Mulligan &#8230; <a href="http://kenneth.kufluk.com/blog/2010/11/dynamic-twitter-icon-with-greasemonkey-script-in-chrome/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>As a quick response to</p>
<p><!-- tweet id : 27476405800 --><br />
<style type='text/css'>#bbpBox_27476405800 a { text-decoration:none; color:#0099B9; }#bbpBox_27476405800 a:hover { text-decoration:underline; }</style>
<div id='bbpBox_27476405800' class='bbpBox' style='padding:20px; margin:5px 0; background-color:#0099B9; background-image:url(http://a3.twimg.com/a/1298748610/images/themes/theme1/bg.png); background-repeat:no-repeat'>
<div style='background:#fff; padding:10px; margin:0; min-height:48px; color:#3C3940; -moz-border-radius:5px; -webkit-border-radius:5px;'><span style='width:100%; font-size:18px; line-height:22px;'>@<a class="tweet-url username" href="http://twitter.com/ev">ev</a> Also, it would be great if tweets updated automatically, and is it possible to have the favicon turn red when there&#8217;s new tweets? <a href="http://twitter.com/search?q=%23AskEv" title="#AskEv" class="tweet-url hashtag">#AskEv</a></span>
<div class='bbp-actions' style='font-size:12px; width:100%; padding:5px 0; margin:0 0 10px 0; border-bottom:1px solid #e6e6e6;'><img align='middle' src='http://kenneth.kufluk.com/blog/wp-content/plugins/twitter-blackbird-pie//images/bird.png' /><a title='tweeted on 15th October 2010 8:41 pm' href='http://twitter.com/#!/orismology/status/27476405800' target='_blank'>15th October 2010 8:41 pm</a> via web<a href='https://twitter.com/intent/tweet?in_reply_to=27476405800' class='bbp-action bbp-reply-action' title='Reply'><span><em style='margin-left: 1em;'></em><strong>Reply</strong></span></a><a href='https://twitter.com/intent/retweet?tweet_id=27476405800' class='bbp-action bbp-retweet-action' title='Retweet'><span><em style='margin-left: 1em;'></em><strong>Retweet</strong></span></a><a href='https://twitter.com/intent/favorite?tweet_id=27476405800' class='bbp-action bbp-favorite-action' title='Favorite'><span><em style='margin-left: 1em;'></em><strong>Favorite</strong></span></a></div>
<div style='float:left; padding:0; margin:0'><a href='http://twitter.com/intent/user?screen_name=orismology'><img style='width:48px; height:48px; padding-right:7px; border:none; background:none; margin:0' src='http://a0.twimg.com/profile_images/1198803436/5286281601_721b4ef63e_normal.jpg' /></a></div>
<div style='float:left; padding:0; margin:0'><a style='font-weight:bold' href='http://twitter.com/intent/user?screen_name=orismology'>@orismology</a>
<div style='margin:0; padding-top:2px'>Dominic Mulligan</div>
</div>
<div style='clear:both'></div>
</div>
</div>
<p><!-- end of tweet --></p>
<p><!-- tweet id : 27476697539 --><br />
<style type='text/css'>#bbpBox_27476697539 a { text-decoration:none; color:#A8AB9A; }#bbpBox_27476697539 a:hover { text-decoration:underline; }</style>
<div id='bbpBox_27476697539' class='bbpBox' style='padding:20px; margin:5px 0; background-color:#D4BEA7; background-image:url(http://a1.twimg.com/profile_background_images/156917969/x7f6ed669043911a931ed4248be65e63.png);'>
<div style='background:#fff; padding:10px; margin:0; min-height:48px; color:#C3B7A1; -moz-border-radius:5px; -webkit-border-radius:5px;'><span style='width:100%; font-size:18px; line-height:22px;'>@<a class="tweet-url username" href="http://twitter.com/orismology">orismology</a> I don&#8217;t think it&#8217;s possible to make the favicon turn red. But we do change the page title and put the # in there. <a href="http://twitter.com/search?q=%23AskEv" title="#AskEv" class="tweet-url hashtag">#AskEv</a></span>
<div class='bbp-actions' style='font-size:12px; width:100%; padding:5px 0; margin:0 0 10px 0; border-bottom:1px solid #e6e6e6;'><img align='middle' src='http://kenneth.kufluk.com/blog/wp-content/plugins/twitter-blackbird-pie//images/bird.png' /><a title='tweeted on 15th October 2010 8:45 pm' href='http://twitter.com/#!/ev/status/27476697539' target='_blank'>15th October 2010 8:45 pm</a> via web<a href='https://twitter.com/intent/tweet?in_reply_to=27476697539' class='bbp-action bbp-reply-action' title='Reply'><span><em style='margin-left: 1em;'></em><strong>Reply</strong></span></a><a href='https://twitter.com/intent/retweet?tweet_id=27476697539' class='bbp-action bbp-retweet-action' title='Retweet'><span><em style='margin-left: 1em;'></em><strong>Retweet</strong></span></a><a href='https://twitter.com/intent/favorite?tweet_id=27476697539' class='bbp-action bbp-favorite-action' title='Favorite'><span><em style='margin-left: 1em;'></em><strong>Favorite</strong></span></a></div>
<div style='float:left; padding:0; margin:0'><a href='http://twitter.com/intent/user?screen_name=ev'><img style='width:48px; height:48px; padding-right:7px; border:none; background:none; margin:0' src='http://a0.twimg.com/profile_images/1147019935/evedit0xr_2_normal.jpg' /></a></div>
<div style='float:left; padding:0; margin:0'><a style='font-weight:bold' href='http://twitter.com/intent/user?screen_name=ev'>@ev</a>
<div style='margin:0; padding-top:2px'>Evan Williams</div>
</div>
<div style='clear:both'></div>
</div>
</div>
<p><!-- end of tweet --></p>
<p>I&#8217;ve put together a quick greasemonkey script to change the favicon when new messages arrive.  In #NewTwitter, it&#8217;s surprisingly easy to build simple scripts that add to the behaviour of the page.<span id="more-823"></span></p>
<p>Taking leaves from the books of Matt (<a href="http://mzsanford.wordpress.com/2010/09/19/grease-monkey-for-newtwitter/">Greasemonkey programming for #NewTwitter</a> and Remy (<a href="http://remysharp.com/2010/08/24/dynamic-favicons/">Dynamic favicons</a>), and using jQuery&#8217;s event delegation to capture the custom &#8220;newItemsCountChanged&#8217; event generated within the page, I simply update a number in the favicon when messages are waiting.  It&#8217;s displayed in a red circle, and when counts are more than a single digit, it just displays a &#8216;plus&#8217;.</p>
<pre class="brush: javascript">
    $(document).delegate(&#039;div&#039;, &#039;newItemsCountChanged&#039;, function(e, tweetcount) {
        // make icon and update
    });
</pre>
<p>A complication is that user scripts in Chrome are run in a separate context from the main page, meaning I have no access to jQuery, or the functions of the page.  I overcame this by converting my function to a string and pasting it into the page as a script node.  Hardly elegant, but it shouldn&#8217;t break the security model.</p>
<pre class="brush: javascript">
    var script = document.createElement(&quot;script&quot;);
    script.textContent = &quot;(&quot; + updateFavIcon.toString() + &quot;)();&quot;;
    document.body.appendChild(script);
</pre>
<p>Why do this?  Primarily to be able to be notified of updates when the tabs are pinned, and you can&#8217;t see the numbered update in the tab title.  There are similar scripts available for <a href="http://userscripts.org/scripts/show/24430">Gmail</a> and <a href="http://userscripts.org/scripts/show/84382">Google Calendar</a>.</p>
<p>Why doesn&#8217;t it work in Firefox? I&#8217;m not sure.  If anyone can debug, please let me know.  Also, it&#8217;d be nice to capture DMs and @mentions too.  Currently I&#8217;m just picking the number from the shown timeline.</p>
<p>To install, simply click this link.  You do not need to install any Greasemonkey extension first &#8211; this will run natively!<br />
<a href="http://kenneth.kufluk.com/greasemonkey/twitter-favicon.user.js">http://kenneth.kufluk.com/greasemonkey/twitter-favicon.user.js</a><br />
The &#8220;.user.js&#8221; identifies the script as installable in Chrome.</p>
<p>To remove, head to <a href="chrome://extensions">chrome://extensions</a> and uninstall &#8220;Twitter Dynamic Icon&#8221;.  If you find Twitter running slowly or oddly, please try removing this script <em>first</em>.</p>
<p>Source code here:</p>
<pre class="brush: javascript">
// ==UserScript==
// @name           Twitter Dynamic Icon
// @description    Changes the number on the Twitter favicon to reflect the current date, as per http://remysharp.com/2010/08/24/dynamic-favicons and http://userscripts.org/scripts/show/84382
// @version        1.0
// @author         KennethKufluk
// @namespace      ttp://kenneth.kufluk.com/blog/2010/11/dynamic-twitter-icon-with-greasemonkey-script-in-chrome/
// @require        http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js
// @include        http://twitter.com/*
// @include        https://twitter.com/*
// ==/UserScript==

(twitterLoaded = function() {
  if (document.body.className.match(&#039;loading&#039;)) {
    setTimeout(twitterLoaded, 5000);
  } else {
    var script = document.createElement(&quot;script&quot;);
    script.textContent = &quot;(&quot; + updateFavIcon.toString() + &quot;)();&quot;;
    document.body.appendChild(script);
  }
})();
var updateFavIcon = function() {
  var canvas = document.createElement(&#039;canvas&#039;),
    ctx,
    img = document.createElement(&#039;img&#039;),
    link = document.createElement(&#039;link&#039;),
    tweetcount = 0,
    head = document.getElementsByTagName(&#039;head&#039;)[0];

  if (canvas.getContext) {
    canvas.height = canvas.width = 16; // set the size
    ctx = canvas.getContext(&#039;2d&#039;);
    img.src = &#039;http://twitter.com/favicon.ico&#039;;

    //called on update to the displayed timeline
    $(document).delegate(&#039;div&#039;, &#039;newItemsCountChanged&#039;, function(e, tweetcount) {
      ctx.clearRect(0,0,16,16);
      ctx.drawImage(img, 0, 0);
      ctx.font = &#039;bold 10px &quot;helvetica&quot;,&quot;Arial&quot;,sans-serif&#039;;
      ctx.textAlign = &#039;center&#039;;
			if (tweetcount&gt;0) {
				// draw a circle
				ctx.fillStyle = &#039;#FF0000&#039;;
				ctx.beginPath();
				ctx.arc(10, 10, 5, 0, Math.PI*2, true);
				ctx.closePath();
  			ctx.fill();
				// add the number
				ctx.fillStyle = &#039;#F0EEDD&#039;;
				if (tweetcount&gt;9) tweetcount = &quot;+&quot;;
				ctx.fillText(tweetcount, 10, 13);
	    }
      link.setAttribute(&#039;type&#039;, &#039;image/png&#039;);
      link.setAttribute(&#039;rel&#039;, &#039;shortcut icon&#039;);
      link.setAttribute(&#039;href&#039;, canvas.toDataURL(&#039;image/png&#039;));
      head.appendChild(link);
    });
  }
};
</pre>
]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2010/11/dynamic-twitter-icon-with-greasemonkey-script-in-chrome/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Twitter Streams, Node.js, Web Sockets and the X Factor. Or, how to overload your server.</title>
		<link>http://kenneth.kufluk.com/blog/2010/10/twitter-streams-node-js-web-sockets-and-the-x-factor-or-how-to-overload-your-server/</link>
		<comments>http://kenneth.kufluk.com/blog/2010/10/twitter-streams-node-js-web-sockets-and-the-x-factor-or-how-to-overload-your-server/#comments</comments>
		<pubDate>Tue, 12 Oct 2010 16:32:03 +0000</pubDate>
		<dc:creator>Kenneth</dc:creator>
				<category><![CDATA[Projects]]></category>

		<guid isPermaLink="false">http://kenneth.kufluk.com/blog/2010/10/twitter-streams-node-js-web-sockets-and-the-x-factor-or-how-to-overload-your-server/</guid>
		<description><![CDATA[I&#39;ve just launched a new experimental website: http://xfactortweets.com Please don&#39;t be too judgemental of the subject matter. The aim of the site is to play with web sockets and the twitter streams, and really, to see how far it can &#8230; <a href="http://kenneth.kufluk.com/blog/2010/10/twitter-streams-node-js-web-sockets-and-the-x-factor-or-how-to-overload-your-server/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div class='posterous_autopost'>
<div>I&#39;ve just launched a new experimental website:</div>
<div><a href="http://xfactortweets.com">http://xfactortweets.com</a></div>
<div>Please don&#39;t be too judgemental of the subject matter. <img src='http://kenneth.kufluk.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </div>
<p><span id="more-818"></span>
<p />
<div>The aim of the site is to play with web sockets and the twitter streams, and really, to see how far it can be pushed.</div>
<p />
<div>The page starts off effectively blank.  The site listens for tweets mentioning &quot;xfactor&quot;, in real time.  When a tweet is found, it&#39;s shown immediately.  If the tweet also matches one of the contestant&#39;s names, then it starts to draw the graph.  Each contestant is ranked according to the number of mentions, starting randomly when the page is loaded, and slowly filtering to reflect the mood of the public at the time.  Next to each contestant&#39;s name is the number of mentions received.  The graph is only updated when a ranked place changes.</div>
<p />
<div>At the top of the page is the usual facebook and tweet buttons, with another box to enable tweeting directly on the page, to allow the user to get involved without leaving the site.</div>
<p />
<div>The tweet box is simply using Twitter&#39;s @anywhere functionality.</div>
<p />
<div>The graph is drawn very simply, using RaphaelJS for svg/vml support in a cross-browser environment.</div>
<div>The ranked contestants are shown as DIVs and manipulated using jQuery&#39;s animate method on the position.</div>
<div>The HTML behind the scenes is built from the HTML5 boilerplate template.</div>
<p />
<div>Twitter&#39;s stream does not have native support for web sockets yet.  So we need some sort of server arrangement to filter out the feed to us.</div>
<div>An online search yielded Remy&#39;s <a href="http://remysharp.com/2010/02/14/slicehost-nodejs-websockets/">Slicehost, Node.js &amp; WebSockets</a>, where he aims for a similar goal.  It&#39;s a little out of date, but is a good start.  He points us int he direction of @andregoncalves &#39;s github project: <a href="http://github.com/andregoncalves/twitter-nodejs-websocket">twitter-nodejs-websocket</a>.  After flicking through some of the forks, I can see that it needs a slight fix to work, but that @rishavrastogi has forked it to simply use <a href="http://github.com/technoweenie/twitter-node">twitter-node</a> and <a href="http://github.com/LearnBoost/Socket.IO">socket.io</a>.  Socket.io will give us cross-browser support for the web sockets, which is a great bonus.  And since it uses just to libraries, the script is now really simple.  Great work.</div>
<p />
<div>I followed a commenter&#39;s advice on Remy&#39;s site and hosted with Linode, something I&#39;ve always wanted to try.  It seems a little more expensive that Amazon EC2, but gives a better machine, easier access and I suspect scaling will be simpler.</div>
<p />
<div>Once I got my Linode instance running, I installed node, git and so forth using Remy&#39;s guide.  I then installed npm, which was not trivial, and used it to install <a href="http://socket.io">socket.io</a>.  I tried to get twitter-node as well, but hit some snags.  Npm should be simple, but the permission issues are a pain in the arse to fix.  This bit took longer than I expected.</div>
<p />
<div>I then hacked the server.js, to get it to track my keyword: &quot;xfactor&quot; instead of &quot;iphone&quot;, by default.  I also got <a href="http://kevin.vanzonneveld.net/techblog/article/run_nodejs_as_a_service_on_ubuntu_karmic/">nodejs running as a service</a>.  And I adapted it to serve my static files.</div>
<div>I finally had the site running.  It was surprising how easy it was to run.</div>
<p />
<div>In fact, you can just curl a stream direct from twitter.  We&#39;ll create a file called ‘tracking’ that contains, excluding the quotation marks, the phrase: “track=basketball,football,baseball,footy,soccer” then get the stream matching that list:</div>
<pre class="brush: php">
echo &amp;amp;amp;quot;track=basketball,football,baseball,footy,soccer&amp;amp;amp;quot; &amp;amp;amp;gt;tracking
curl -d @tracking http://stream.twitter.com/1/statuses/filter.json -uAnyTwitterUser:Password
</pre>
<div>You should immediately start to see awesome.</div>
<p />
<div>Now, if you think that&#39;s good, try tracking the keyword &quot;xfactor&quot; when the show is on.</div>
<div>I launched my server on Saturday morning, and was seeing a tweet every five to ten seconds.  It should be around that now.</div>
<div>But when the show&#39;s on, you&#39;re looking at 10-20 tweets <i>per second, minimum</i>.  It&#39;s incredibly fast.</div>
<div>And those tweets will whizz straight through to the front end.  You&#39;ll need a good machine to handle this.  The tweets displayed simply become a blur, and the graph races along.</div>
<div>Even if you&#39;re not a fan, it&#39;s worth watching the site just to get an idea of the throughout that twitter, node and websockets can handle.</div>
<p />
<div>Now, my site didn&#39;t take off.  Maybe my friends aren&#39;t XFactor followers.  It&#39;s their loss.</div>
<div>But I doubt the site could support much more than 4 viewers anyway, at peak.  Soon enough, it&#39;ll hit the bandwidth limit on the network card.</div>
<p />
<div>Find the code here:</div>
<div><a href="http://github.com/kennethkufluk/X-Factor-Tweets">http://github.com/kennethkufluk/X-Factor-Tweets</a></div>
<p />
<div>If I was building McLaren again, I&#39;d use <a href="http://socket.io">socket.io</a>, and demand more regular updates than once a second.  It&#39;d be great to use this in anger.</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2010/10/twitter-streams-node-js-web-sockets-and-the-x-factor-or-how-to-overload-your-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>University: I want my money back</title>
		<link>http://kenneth.kufluk.com/blog/2010/10/university-i-want-my-money-back/</link>
		<comments>http://kenneth.kufluk.com/blog/2010/10/university-i-want-my-money-back/#comments</comments>
		<pubDate>Tue, 12 Oct 2010 14:01:03 +0000</pubDate>
		<dc:creator>Kenneth</dc:creator>
				<category><![CDATA[Projects]]></category>

		<guid isPermaLink="false">http://kenneth.kufluk.com/blog/2010/10/university-i-want-my-money-back/</guid>
		<description><![CDATA[UK University tuition fees are in the news again.  Early leaks and rumours suggest that students will be expected to pay around £7,000 a year, up from the current £3,000, which was itself a huge rise on the first £1,000, &#8230; <a href="http://kenneth.kufluk.com/blog/2010/10/university-i-want-my-money-back/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div class='posterous_autopost'>UK University tuition fees are in the news again.  Early leaks and rumours suggest that students will be expected to pay around £7,000 a year, up from the current £3,000, which was itself a huge rise on the first £1,000, the original &quot;top-up&quot; fee levied on students, which only started just after I&#39;d graduated myself, a little over ten years ago.
<p /> That&#39;s an amazing rise.<span id="more-816"></span>  I started university with a grant of around £700 a year and a &quot;top-flight&quot; bursary (provided to science students with better than AAB A-level grades) of £750 a year.  We&#39;ve gone from that credit of £1500 a year to a charge of £7,000 a year in just ten years.
<p /> Naturally, the Americans, and numerous other countries, will be surprised by our concern.  A mere seven grand a year to attend some of the best universities in the world is a marginal sum, compared to the Ivy League.  Parents in the US start a college fund when their child is born.  The wealthiest parents can pay for the best education, spiced up by a few scholarship places and imported sportsmen.
<p /> But education in the UK is different, and proudly so.  For a start, like the health service, it&#39;s free.  We recognise that a good education is the basis of our economy, and the principle reason why such a geographically tiny country still has a great international standing.  But in the past ten years, something changed.  University has somehow become a right of passage, to which all are entitled, not just the rich, or smart.  The first I agree with &#8211; the second I will take issue with.  Money should not play a role in university attendance.  This is why the new fees can be paid entirely with credit.  But surely educational achievement should have some contribution?
<p /> The government aim has been for fifty percent of all school-leavers to attend university.  Fifty percent.  That&#39;s about the percentage of pupils at my secondary school who got five A-Cs at GCSE.  And that basically means that you can read, write and count to ten.  Should ALL of these pupils be attending universities?  and if so, what do they hope to achieve?
<p /> When you come right down to it, what do UK universities offer?
<p />I would sum it up as the following:<br />- a qualification<br />- a chance to defer a decision about which career to follow<br />- a feeling of inclusion; that you are not &#39;left out&#39; while others go away<br /> &#8211; a chance to stay in academia
<p />I might also add:<br />- the chance to drink vast quantities of low-price beer on credit<br />- the chance to get older by three years without working
<p />What I think is sad about the above lists is what&#39;s missing.  I think many students are out to get &#39;a degree&#39;.  A piece of paper.  A qualification which will let you claim a higher-paying job.  Employers are almost as much to blame.  We ask for a degree, sometimes a relevant degree, and we check our box on the form.  That is all.
<p /> And this works.  Why should I employ someone with a degree over someone without?  Because it&#39;s a good indication.<br />The trouble is that <b>smart people go to university, but university doesn&#39;t make people smart</b>.
<div> It&#39;s not the training that we&#39;re looking for, not the skills that they&#39;ve learnt.  Just the fact that they went to university gets our box ticked.</div>
<p />
<div>What&#39;s missing from the lists above is education.  I think university should be a place for people with a real passion for the subject to get together and bash heads.  To discuss ideas, to teach each other the latest trick, to discuss the latest findings.  Maths, physics, literature, film, whatever subject.  As long as you&#39;re passionate about it.</div>
<p />
<div>I went to university at the University of Warwick, back in 1996.  It&#39;s a campus university based just outside Coventry, borrowing it&#39;s more prestigious name from the town and castle a few miles further away.  I chose Warwick on two good solid principles: it&#39;s a renowned university, and the sun shone on the open day.  There were probably other reasons too, for I also remember being impressed by a young Professor showing us Hot Java in a web browser.</div>
<p />
<div>This was 1996.  The Internet was coming of age.  Looking back, this will be viewed as one of the most exciting periods of computer history.</div>
<p />
<div>And so, as a (doubtless) spotty teenage youth, I joined up.  I piled all my belongings, including boxes and boxes of computer gear, into my parents&#39; car, and unloaded into my student dorms.  This was a quality establishment.  We had our own rooms, with ensuite bathrooms.  Luxury.
<p /> </div>
<div>At the time, I&#39;d just come from quite an awkward period in my history, being sixth form.  After five long years of commuting to the best secondary school in the local area by train, and faced with the prospect of doing so for two more years in a suit, I switched to the local, shabby, sixth form down the road.  This one offered Computing and Further Maths too, so my choice was not so bad.   But the trouble was, I knew nobody here.  I&#39;d left the secondary school with no close friends to keep in contact with, and struggled to fit into life in sixth form college.  I&#39;d done the same between primary and secondary schools too, and found that jarring enough.  So I arrived at university without any great social experience, beyond knowing two thousand ways to annoy my two brothers, and with a kind of cabin fever from living at home that made it hard to adapt to different ways of doing things.</div>
<p />
<div>My real love and obsession was computers.  Always has been.  My parents are both computer programmers (seriously), so somehow it&#39;s in my blood, in my DNA.  In school you&#39;d have found me in the computer room at every lunch break, and for an hour after school.  At home, I&#39;d be transfixed by dial-up bulletin boards (since I couldn&#39;t afford an internet subscription).  At sixth form, I&#39;d got a holiday job, and coded a clinical trial management database which I&#39;d then submitted for coursework, getting a huge 95% result.  I played with 3D, with raytracing, with OS/2, with Windows, with DOS, with everything.  I knew what I was doing, and loved doing it.</div>
<p />
<div>Arriving at university for that first term was something of a shock.  The computer science lab was full of green-screen terminals running unix.  All the courses for that first year were crushing dull, and reiterated ground we&#39;d covered already.  For some reason, computer science was taught as though you&#39;d not used a computer before.  I wondered if English was taught starting with the alphabet, or if the maths classes were doing hundreds, tens and units.  The lectures weren&#39;t hard.  Well, there weren&#39;t many of them anyway &#8211; I hadn&#39;t a single morning lecture in the first term at all.  We were taught &quot;maths for computer science&quot;, which turned out to be dry pure maths. After two years of further maths, this isn&#39;t what you want to hear.  I looked around for the keen computing lecturers, that would bring me into the department&#39;s inner circle, to get involved in real projects.  I found none.  My tutor was the maths lecturer &#8211; probably still the most boring man on the planet.</div>
<p />
<div>I struggled.  Or rather, I didn&#39;t.  I gave up.  I used the computer in my room.  Couldn&#39;t even get online, since there was no network or phone in the rooms.  I couldn&#39;t even pay to have one installed.  I was offline, except for green screen terminals.  It was pitiful.</div>
<p />
<div>By the time of the exams, I was sick of it.  Lectures sucked the fun out of any subject they touched, that wasn&#39;t dull enough already.  I wasn&#39;t the only one who walked out of the databases course saying &quot;thank god I knew that already&quot;.  After locking myself into my room for computing, except for excursions to the union bar, I realised I&#39;d had enough.  I remember walking out of each exam at the earliest possible opportunity.  My reasoning was that the first 30% of the questions were the easiest, you couldn&#39;t leave for the first half-hour of each 3-hour exam.  So I&#39;d answer the first third of the questions, get up and go.  It felt so good to go.
<p /> After three years of university, I got my degree.  I&#39;ve ticked your box.  But I failed at it.  I couldn&#39;t get interested in the dry dullness.  I must&#39;ve been hell to live with.  I learned very little.  And I hated crammed bars.</div>
<p />
<div>Despite my grants, I had a student loan of £4,000, two interest free student overdrafts of £1,200, and basically no idea of the value of money.</div>
<p />
<div>But there were good things.  I kept my holiday job, and was good at it.  I learned that presenting to work colleagues about something you care, was easy.  The red-faced embarrassment of presenting to class disappeared.  While commuting to work, I met a guy on a train who ran a web development company.  Slowly, I learned how the business world worked.</div>
<p />
<div>I remember that some of my lecturers were indignant about &#39;practical&#39; questions.  &quot;When are we ever going to use this?&quot;  we asked.  Apparently we were supposed to be interested in the subject itself, not practical applications.  University was not supposed to be a preparation for the world of work.</div>
<p />
<div>So what is university now?  We merged in the polytechnics, and invented degrees in travel &amp; leisure.  We&#39;re in a befuddlement of ambitions.  Are we training graduates for business, or offering a stepping stone into research and academia?  Should all qualifications be degrees, and should they all be three years?</div>
<p />
<div>We&#39;ve seen from GCSEs, SATs, 11+, A-Levels and AS-levels, that stability is preferable to endless government tinkering.  And the independence of universities gives that resistance to change.  But I think it&#39;s time to answer the single outstanding question:</div>
<p />
<div><b>What is university </b><i><b>for</b></i><b>?</b>
<p /></div>
<div>Once we know that, we can focus on delivering it.  Or, students might decide that it&#39;s not for them.  Maybe they&#39;re happy to avoid three years of maths, and would rather get straight into web design apprenticeships.  Maybe we don&#39;t all need degrees.  Maybe there should be different kinds of degrees. </div>
<p />
<div>I left with £6,500 of debt and nothing but a certificate to show for it.  Another £21,000 of debt would have left me <b>far more angry</b> about what little I got for my money.  </div>
<div>Students these days must demand a better deal.</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2010/10/university-i-want-my-money-back/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Loading more than 32 stylesheets in IE for Development</title>
		<link>http://kenneth.kufluk.com/blog/2010/09/loading-more-than-32-stylesheets-in-ie-for-development/</link>
		<comments>http://kenneth.kufluk.com/blog/2010/09/loading-more-than-32-stylesheets-in-ie-for-development/#comments</comments>
		<pubDate>Sun, 12 Sep 2010 11:47:53 +0000</pubDate>
		<dc:creator>Kenneth</dc:creator>
				<category><![CDATA[Projects]]></category>
		<category><![CDATA[Proper Articles]]></category>

		<guid isPermaLink="false">http://kenneth.kufluk.com/blog/?p=778</guid>
		<description><![CDATA[Fellow Pub Standards coder Matt Bee recently ranted about IE on Twitter (one of the many good things Twitter is for): IE won&#8217;t style owt if more than 31 stylesheets are loaded, but does IE8 really only style up to &#8230; <a href="http://kenneth.kufluk.com/blog/2010/09/loading-more-than-32-stylesheets-in-ie-for-development/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Fellow Pub Standards coder <a href="http://twitter.com/mattbee">Matt Bee</a> recently ranted about IE on Twitter (one of the many good things Twitter is for):</p>
<p><!-- tweet id : 23926928229 --><br />
<style type='text/css'>#bbpBox_23926928229 a { text-decoration:none; color:#c30000; }#bbpBox_23926928229 a:hover { text-decoration:underline; }</style>
<div id='bbpBox_23926928229' class='bbpBox' style='padding:20px; margin:5px 0; background-color:#000000; background-image:url(http://a3.twimg.com/profile_background_images/13707025/twitter-bg.jpg);'>
<div style='background:#fff; padding:10px; margin:0; min-height:48px; color:#333; -moz-border-radius:5px; -webkit-border-radius:5px;'><span style='width:100%; font-size:18px; line-height:22px;'>IE won&#8217;t style owt if more than 31 stylesheets are loaded, but does IE8 really only style up to 24 and then stop? <a href="http://twitter.com/search?q=%23fuckingbastardofacuntIE" title="#fuckingbastardofacuntIE" class="tweet-url hashtag">#fuckingbastardofacuntIE</a></span>
<div class='bbp-actions' style='font-size:12px; width:100%; padding:5px 0; margin:0 0 10px 0; border-bottom:1px solid #e6e6e6;'><img align='middle' src='http://kenneth.kufluk.com/blog/wp-content/plugins/twitter-blackbird-pie//images/bird.png' /><a title='tweeted on 8th September 2010 4:07 pm' href='http://twitter.com/#!/mattbee/status/23926928229' target='_blank'>8th September 2010 4:07 pm</a> via <a href="http://www.tweetdeck.com" rel="nofollow" target="blank">TweetDeck</a><a href='https://twitter.com/intent/tweet?in_reply_to=23926928229' class='bbp-action bbp-reply-action' title='Reply'><span><em style='margin-left: 1em;'></em><strong>Reply</strong></span></a><a href='https://twitter.com/intent/retweet?tweet_id=23926928229' class='bbp-action bbp-retweet-action' title='Retweet'><span><em style='margin-left: 1em;'></em><strong>Retweet</strong></span></a><a href='https://twitter.com/intent/favorite?tweet_id=23926928229' class='bbp-action bbp-favorite-action' title='Favorite'><span><em style='margin-left: 1em;'></em><strong>Favorite</strong></span></a></div>
<div style='float:left; padding:0; margin:0'><a href='http://twitter.com/intent/user?screen_name=mattbee'><img style='width:48px; height:48px; padding-right:7px; border:none; background:none; margin:0' src='http://a2.twimg.com/profile_images/1211826320/bvutts-quarry-2010_normal.jpg' /></a></div>
<div style='float:left; padding:0; margin:0'><a style='font-weight:bold' href='http://twitter.com/intent/user?screen_name=mattbee'>@mattbee</a>
<div style='margin:0; padding-top:2px'>Matt Bee</div>
</div>
<div style='clear:both'></div>
</div>
</div>
<p><!-- end of tweet --></p>
<p>It reminded me that I&#8217;d asked him about this before: why on earth would you want to load &gt;31 stylesheets?  <span id="more-778"></span>Apparently this is the fault of the Drupal CMS which attaches CSS to individual modules.  Personally, if I was going beyond a dozen stylesheets, I&#8217;d seriously consider inline style at that point.  Too many small files are an admin headache, and if you&#8217;re building tiny modules, then it might well be best to keep the styles with the HTML.</p>
<p>However, I grant that this problem exists, and that you could be put in a situation where it couldn&#8217;t be helped.  For the sake of argument, you&#8217;re not using the CMS&#8217;s built-in CSS compiler because of the compile-time lag, and you&#8217;re not using Minify (which is really quick), because you don&#8217;t want to keep updating the CSS list, or something.</p>
<p>Either way, what you want is a workaround for the limit.</p>
<p>This doesn&#8217;t sound like a particularly hard problem, especially if you know the secret of IE:  you can use @import statements in your stylesheets to import more.  Each &#8216;document&#8217; will only accept up to 32, so you have to group your stylesheets into groups of 32, and then import them.</p>
<p>Obviously we&#8217;re not going to do that by hand, and I&#8217;m not going to go googling for a javascript solution, because &#8230; because, well, I feel like writing one myself.</p>
<p>Here goes.</p>
<p>So, first up, let&#8217;s insert our script.  I can imagine that all our CSS files are neatly loaded in the head of the document, and if that&#8217;s true, I can just add the script as the last line of the head, without needing to worry about any onload events:</p>
<pre class="brush: html">
...
&lt;!--[if LT IE 9]&gt; &lt;script type=&quot;text/javascript&quot; src=&quot;ie-css-limit.js&quot;&gt;&lt;/script&gt; &lt;![endif]--&gt;
&lt;/head&gt;
</pre>
<p>Notice how I&#8217;ve also put it in Conditional Comments, so other browsers won&#8217;t be bothered.</p>
<p>It&#8217;s possible that your CSS isn&#8217;t in the head.  If you&#8217;re associating the CSS with individual modules, and your CMS isn&#8217;t smart enough to group them all in the head, you might have stylesheet elements scattered throughout the document.  In this case, we can place the script link in the same way as before, but we&#8217;ll add the defer attribute, so it only gets executed when the page loads.  Note that this could confuse your page load order, so you could get some funny effects if you have other onload events relying on existing CSS styles.</p>
<pre class="brush: html">
...
&lt;!--[if LT IE 9]&gt; &lt;script defer type=&quot;text/javascript&quot; src=&quot;ie-css-limit.js&quot;&gt;&lt;/script&gt; &lt;![endif]--&gt;
&lt;/head&gt;
</pre>
<p>Ok, we&#8217;re now loading a script.  I guess we&#8217;d better write it.</p>
<p>What we want to do is rip all the link elements out of the document, and then re-import them using the @import trick from above.</p>
<p>First, let&#8217;s declare some variables.</p>
<pre class="brush: javascript">
//  a constant used to group stylesheets.  Twenty seems safe
var MAX_STYLESHEETS = 20;
//  get all the link elements in the document
var links = document.getElementsByTagName(&#039;LINK&#039;);
// a set of stylesheet URLs that we later want to import
var linkurls = [];
</pre>
<p>We&#8217;ll copy those links straight into an array.  Otherwise when we removed stylesheets, the set will be reordered.</p>
<pre class="brush: javascript">
//  copy those links into an array
var linkarr = [];
for (var i=0;i&lt;links.length;i++) linkarr.push(links[i]);
</pre>
<p>Ok, now let&#8217;s rip out the stylesheets and build our url array:</p>
<pre class="brush: javascript">
// Kill off our existing stylesheets
for (var i=0;i&lt;linkarr.length;i++) {
var link = linkarr[i];
// if this isn&#039;t a stylesheet, ignore it (it could be a favicon)
if (!link || link.rel!=&#039;stylesheet&#039;) continue;
// add the href to our array
linkurls.push(link.href);
// remove the stylesheet
link.parentNode.removeChild(link);
}
</pre>
<p>And now we want to use our array to build groups of new import stylesheets:</p>
<pre class="brush: javascript">
// Create a new stylesheet full of imports
var newSS = document.createStyleSheet();
for (var i=0;i&lt;linkurls.length;i++) {
newSS.addImport(link.href);
// if full, start a new import stylesheet
if (i % MAX_STYLESHEETS == 0) newSS = document.createStyleSheet();
}
</pre>
<p>Ok, so we glue all those bits together and stick it in our JavaScript file and bingo, we can load 20 * 31 = 620 stylesheets!</p>
<p>Ok, disclaimer time:</p>
<li>I haven&#8217;t tested this except in IE6 on IETester.</li>
<li>You should wrap the whole thing into a closure, to avoid namespace pollution.</li>
<li>You should only allow this to run on your dev server.  It&#8217;ll take time to process, probably give weird effects, and you&#8217;re going to be making twice as many stylesheet calls as usual, and apparently that&#8217;s already a lot.  Use Minify, or your CSS compiler, for any kind of large site.  Or, better, use LESS CSS in the first place.  The PHP version is excellent.</li>
<li>To answer Matt&#8217;s original question, I have no idea how many stylesheets IE8 can load.</li>
]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2010/09/loading-more-than-32-stylesheets-in-ie-for-development/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Chaining Asynchronous Methods in jQuery using the Queue</title>
		<link>http://kenneth.kufluk.com/blog/2010/08/chaining-asynchronous-methods-in-jquery-using-the-queue/</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[Proper Articles]]></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 &#8230; <a href="http://kenneth.kufluk.com/blog/2010/08/chaining-asynchronous-methods-in-jquery-using-the-queue/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></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>
]]></content:encoded>
			<wfw:commentRss>http://kenneth.kufluk.com/blog/2010/08/chaining-asynchronous-methods-in-jquery-using-the-queue/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

