<?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>Matt Kirman</title>
	<atom:link href="http://mattkirman.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://mattkirman.com</link>
	<description>The infrequently updated blog of Matt Kirman. Founder &#38; web app developer. Rubyist. Dangerous with coffee.</description>
	<lastBuildDate>Mon, 23 Apr 2012 19:51:15 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Don&#8217;t ignore your dreams</title>
		<link>http://mattkirman.com/2012/04/23/dont-ignore-your-dreams/</link>
		<comments>http://mattkirman.com/2012/04/23/dont-ignore-your-dreams/#comments</comments>
		<pubDate>Mon, 23 Apr 2012 19:51:15 +0000</pubDate>
		<dc:creator>Matt</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://mattkirman.com/?p=804</guid>
		<description><![CDATA[Don&#8217;t ignore your dreams; don&#8217;t work too much; say what you think; cultivate friendships; be happy.]]></description>
			<content:encoded><![CDATA[<p>Don&#8217;t ignore your dreams; don&#8217;t work too much; say what you think; cultivate friendships; be happy.</p>
]]></content:encoded>
			<wfw:commentRss>http://mattkirman.com/2012/04/23/dont-ignore-your-dreams/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Relative Line Numbers in Vim</title>
		<link>http://mattkirman.com/2012/04/18/relative-line-numbers-in-vim/</link>
		<comments>http://mattkirman.com/2012/04/18/relative-line-numbers-in-vim/#comments</comments>
		<pubDate>Wed, 18 Apr 2012 21:07:46 +0000</pubDate>
		<dc:creator>Matt</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[dotfiles]]></category>
		<category><![CDATA[vim]]></category>

		<guid isPermaLink="false">http://mattkirman.com/?p=772</guid>
		<description><![CDATA[I&#8217;ve been gradually moving back to Vim from and one aspect that has really swayed me is the recent addition of the relativenumber setting in Vim 7.3. One thing that I used to be particularly guilty of was repeatedly hammering j and k rather than performing the mental arithmetic required to use the much shorter [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been gradually moving back to Vim from and one aspect that has really swayed me is the recent addition of the <code class="codecolorer text solarized-light"><span class="text">relativenumber</span></code> setting in Vim 7.3.</p>
<p>One thing that I used to be particularly guilty of was repeatedly hammering <code class="codecolorer text solarized-light"><span class="text">j</span></code> and <code class="codecolorer text solarized-light"><span class="text">k</span></code> rather than performing the mental arithmetic required to use the much shorter <code class="codecolorer text solarized-light"><span class="text">37j</span></code>. I had the same issues deleting or moving lines where switching into visual mode was quicker than counting lines and using <code class="codecolorer text solarized-light"><span class="text">d12d</span></code>.</p>
<p><img src="/wp-content/uploads/2012/04/vim-relative-number-1.png" width="700" height="274" /><br />
<span class="caption">Relative line numbers in Vim</span></p>
<h3>Going Relative</h3>
<p>Vim now has a setting called <code class="codecolorer text solarized-light"><span class="text">relativenumber</span></code> which acts in a similar way to the <code class="codecolorer text solarized-light"><span class="text">number</span></code> setting. However, rather than calculating line numbers from the top of the file it shows them relative to the line you&#8217;re currently on.</p>
<p>I always disable the arrow keys in insert mode, to force myself to use <code class="codecolorer text solarized-light"><span class="text">10j</span></code> and keep my hands on the home row (plus it&#8217;s great for trolling). I prefer to use relative line numbers when in normal mode for ease of movement and absolute line numbers in insert mode. We can set this up with:</p>
<div class="codecolorer-container vim solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="vim codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #804040;">au</span> <span style="color: #25BB4D;">InsertEnter</span> <span style="color: #000000;">*</span> <span style="color: #000000;">:</span><span style="color: #804040;">set</span> <span style="color: #668080;">nu</span><br />
<span style="color: #804040;">au</span> <span style="color: #25BB4D;">InsertLeave</span> <span style="color: #000000;">*</span> <span style="color: #000000;">:</span><span style="color: #804040;">set</span> rnu</div></div>
<p>Occasionally it&#8217;s useful to go to a specific line, such as when fixing failing tests. At first glance using relative line numbers appears to complicate the issue somewhat. But, line movement shortcuts such as <code class="codecolorer text solarized-light"><span class="text">&lt;line-number&gt;gg</span></code> still work.</p>
]]></content:encoded>
			<wfw:commentRss>http://mattkirman.com/2012/04/18/relative-line-numbers-in-vim/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Designing a product is keeping five thousand&#8230;</title>
		<link>http://mattkirman.com/2011/11/20/designing-a-product-is-keeping-five-thousand/</link>
		<comments>http://mattkirman.com/2011/11/20/designing-a-product-is-keeping-five-thousand/#comments</comments>
		<pubDate>Sun, 20 Nov 2011 22:17:50 +0000</pubDate>
		<dc:creator>Matt</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://mattkirman.com/?p=739</guid>
		<description><![CDATA[Designing a product is keeping five thousand things in your brain and fitting them all together in new and different ways to get what you want. And every day you discover something new that is a new problem or a new opportunity to fit these things together a little differently. And it’s that process that [...]]]></description>
			<content:encoded><![CDATA[<p>Designing a product is keeping five thousand things in your brain and fitting them all together in new and different ways to get what you want. And every day you discover something new that is a new problem or a new opportunity to fit these things together a little differently.</p>
<p>And it’s that process that is the magic.</p>
]]></content:encoded>
			<wfw:commentRss>http://mattkirman.com/2011/11/20/designing-a-product-is-keeping-five-thousand/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Graphing the switch to Nginx</title>
		<link>http://mattkirman.com/2011/06/24/graphing-the-switch-to-nginx/</link>
		<comments>http://mattkirman.com/2011/06/24/graphing-the-switch-to-nginx/#comments</comments>
		<pubDate>Fri, 24 Jun 2011 21:13:32 +0000</pubDate>
		<dc:creator>Matt</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://mattkirman.com/?p=660</guid>
		<description><![CDATA[As a quick followup to my previous post detailing how to run WordPress behind a Nginx reverse proxy I thought I&#8217;d post an interesting graph retrieved from Google Webmaster Tools showing page load times of this site over the past few months: I switched to the Nginx/Apache configuration just before the start of June and, [...]]]></description>
			<content:encoded><![CDATA[<p>As a quick followup to my previous post detailing how to run <a href="/2011/06/01/how-to-speed-up-wordpress-with-nginx/">WordPress behind a Nginx reverse proxy</a> I thought I&#8217;d post an interesting graph retrieved from Google Webmaster Tools showing page load times of this site over the past few months:</p>
<p><img src="http://cdn.mattkirman.com/wp-content/uploads/2011/06/mattkirman.com-page-load-times.png?f21a40d4774988b615181bd05e0a64cb" /></p>
<p>I switched to the Nginx/Apache configuration just before the start of June and, thankfully, it appears that the performance increase I noticed has also been observed by others.</p>
<p>Additionally, Google reports that the slowest load time was a shocking <strong>5,572ms</strong> with a fastest time of <strong>225ms</strong>. Not too shabby from a single 256MB server.</p>
]]></content:encoded>
			<wfw:commentRss>http://mattkirman.com/2011/06/24/graphing-the-switch-to-nginx/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How to speed up WordPress with Nginx</title>
		<link>http://mattkirman.com/2011/06/01/how-to-speed-up-wordpress-with-nginx/</link>
		<comments>http://mattkirman.com/2011/06/01/how-to-speed-up-wordpress-with-nginx/#comments</comments>
		<pubDate>Wed, 01 Jun 2011 21:19:30 +0000</pubDate>
		<dc:creator>Matt</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://mattkirman.com/?p=556</guid>
		<description><![CDATA[Recently I&#8217;ve wondering whether it was worth trying to improve my WordPress-based blog performance. While it wasn&#8217;t particularly terrible, waiting over 2 seconds just to load a single page isn&#8217;t exactly stunning. I took a typical approach and installed the WP Super Cache plugin. Page loads dropped down to ~1 second. Much better, but there [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I&#8217;ve wondering whether it was worth trying to improve my WordPress-based blog performance. While it wasn&#8217;t particularly terrible, waiting over 2 seconds just to load a single page isn&#8217;t exactly stunning.</p>
<p>I took a typical approach and installed the <a href="http://wordpress.org/extend/plugins/wp-super-cache/" target="_blank">WP Super Cache plugin</a>. Page loads dropped down to ~1 second. Much better, but there must be some more performance gains to be found somewhere without modifying the WordPress source code itself.</p>
<p>Inspired by <a href="http://markmaunder.com/2009/how-to-handle-1000s-of-concurrent-users-on-a-360mb-vps/" target="_blank">this post by Mark Maunder</a> I decided to see if I could shoehorn WordPress into a similar reverse proxy/persistent process mould. So far, it works brilliantly.</p>
<p>With the following tweaks I managed to go from 12 requests/s to over 30 requests/s on the same hardware &#8211; a single 256MB Rackspace Cloud server &#8211; whilst reducing latency from ~2 seconds to an average of only 0.4 seconds.</p>
<p><span id="more-556"></span></p>
<h3>Step 1. Configure Apache</h3>
<p>You&#8217;ve really got to be running Apache with mod_php. Even if you stop reading here you&#8217;ll still find that your server performs better. In order to allow more requests to be handled by Apache, disable Keepalive connections.</p>
<p>You&#8217;ll find at this point that your requests will slow down a bit as clients will have to create a new connection for every request. You will, however, be able to handle many more requests as you will no longer have clients with slow connections tying up processes. We&#8217;re going to rectify this slow down in the next step.</p>
<p><img src="http://cdn.mattkirman.com/wp-content/uploads/2011/05/apache_mod_php.png?dee6d16937d77abacec463472c34109e" /></p>
<p>It is also important to change the IP address that Apache listens on to <code class="codecolorer text solarized-light"><span class="text">127.0.0.1</span></code> so that it can only be accessed from the local machine. Additionally, you will need to change the port from the default port 80 to, for example, port 81. This is because Nginx will need to run on port 80.</p>
<div class="codecolorer-container apache solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="apache codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #adadad; font-style: italic;">#/etc/apache2/ports.conf</span><br />
<br />
<span style="color: #adadad; font-style: italic;"># Listen 80</span><br />
<span style="color: #00007f;">Listen</span> 127.0.0.1:<span style="color: #ff0000;">81</span></div></div>
<h3>Step 2. Configure Nginx as a Reverse Proxy</h3>
<p><a href="http://nginx.org/" target="_blank">Nginx</a> is a &#8220;high performance web server and a reverse proxy server&#8221; that&#8217;s capable of handling thousands of concurrent users whilst occupying only a few megabytes of memory.</p>
<p>To install Nginx on Debian/Ubuntu distributions it&#8217;s as simple as:</p>
<div class="codecolorer-container bash solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666;">$ </span><span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get install</span> nginx</div></div>
<p>Initially we&#8217;re just going to create an Nginx virtual host that acts as a <a href="http://wiki.nginx.org/NginxHttpProxyModule" target="_blank">reverse proxy</a> to our persistent Apache processes. If you have never worked with Nginx before this may sound a little daunting so I&#8217;ve copied the important parts of my conf file below:</p>
<div class="codecolorer-container nginx solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td><div class="nginx codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000066;">server</span> <span style="color: #66cc66;">&#123;</span><br />
&nbsp; <span style="color: #000066;">listen</span> <span style="">80</span> default<span style="color: #66cc66;">;</span><br />
&nbsp; <span style="color: #000066;">server_name</span> mattkirman.com<span style="color: #66cc66;">;</span> <span style="color: #808080; font-style: italic;"># Change this!</span><br />
<br />
&nbsp; <span style="">add_header</span> Cache-Control public<span style="color: #66cc66;">;</span><br />
<br />
&nbsp; <span style="color: #000066;">location</span> / <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; <span style="">proxy_pass</span> <span style="color: #000066;">http</span>://127.0.0.1:<span style="">81</span><span style="color: #66cc66;">;</span><br />
&nbsp; &nbsp; <span style="">proxy_buffering</span> on<span style="color: #66cc66;">;</span><br />
&nbsp; &nbsp; <span style="">proxy_buffers</span> <span style="">12</span> 12k<span style="color: #66cc66;">;</span><br />
&nbsp; &nbsp; <span style="">proxy_redirect</span> off<span style="color: #66cc66;">;</span><br />
<br />
&nbsp; &nbsp; <span style="">proxy_set_header</span> X-Real-IP <span style="">$remote_addr</span><span style="color: #66cc66;">;</span><br />
&nbsp; &nbsp; <span style="">proxy_set_header</span> X-Forwarded-For <span style="">$remote_addr</span><span style="color: #66cc66;">;</span><br />
&nbsp; &nbsp; <span style="">proxy_set_header</span> Host <span style="">$host</span><span style="color: #66cc66;">;</span><br />
&nbsp; <span style="color: #66cc66;">&#125;</span><br />
<span style="color: #66cc66;">&#125;</span></div></td></tr></tbody></table></div>
<p>Because we&#8217;re running WordPress behind a proxy it&#8217;s important that we forward information such as the website host name and the client IP address. By adding <code class="codecolorer nginx solarized-light"><span class="nginx"><span style="">proxy_set_header</span> Host <span style="">$host</span></span></code> we can make the reverse proxy completely transparent. We&#8217;ll make use of the <code class="codecolorer text solarized-light"><span class="text">X-Forwarded-For</span></code> header later.</p>
<p>Unfortunately, if you omit the <code class="codecolorer nginx solarized-light"><span class="nginx"><span style="">proxy_set_header</span> Host</span></code> line you will no longer be able to log into your WordPress installation and any internal links may cease to work.</p>
<p>At this point you want to enable Keepalive requests on Nginx and crank their timeout to as high as you dare. This will offset the slow down you experienced by turning off Keepalive requests on Apache.</p>
<p><img src="http://cdn.mattkirman.com/wp-content/uploads/2011/05/reverse_proxy.png?fc97e560cdbaa65334cc4d45c90e5f6b" /></p>
<p>The beauty of this setup means that the time Apache now takes to handle a request is due solely to the amount of CPU time it takes to actually handle the request &#8211; there&#8217;s zero latency from a loopback request.</p>
<p>Child processes are now no longer tied up by clients with slow connections meaning that each child can process many more requests per second. It&#8217;s therefore possible to handle a huge amount of traffic without having to increase the number of processes and RAM.</p>
<h3>Step 3. Configure WordPress</h3>
<p>There are a few modules in WordPress (mostly based around the comment system and plugins such as Akismet) that use the client remote IP address. Unfortunately, with our current configuration <code class="codecolorer php solarized-light"><span class="php"><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REMOTE_ADDR'</span><span style="color: #009900;">&#93;</span></span></code> will always return <code class="codecolorer text solarized-light"><span class="text">127.0.0.1</span></code>.</p>
<p>In order to fix this we just need to set <code class="codecolorer php solarized-light"><span class="php"><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REMOTE_ADDR'</span><span style="color: #009900;">&#93;</span></span></code> to the value of the <code class="codecolorer text solarized-light"><span class="text">X-Forwarded-For</span></code> header that we set in our Nginx config. You can do this by adding the following code to the top of your <code class="codecolorer text solarized-light"><span class="text">wp-config.php</span></code>.</p>
<div class="codecolorer-container php solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'HTTP_X_FORWARDED_FOR'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000088;">$ips</span> <span style="color: #339933;">=</span> <span style="color: #990000;">explode</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">','</span><span style="color: #339933;">,</span> <span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'HTTP_X_FORWARDED_FOR'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REMOTE_ADDR'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$ips</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>Why <code class="codecolorer text solarized-light"><span class="text">wp-config.php</span></code>? It&#8217;s because it&#8217;s one of the only files that isn&#8217;t effected by WordPress updates. Deploy your <code class="codecolorer text solarized-light"><span class="text">wp-config.php</span></code> to your server, sit back and enjoy your new speedy WordPress blog.</p>
<h3>Tl;dr:</h3>
<ul>
<li>Install mod_php</li>
<li>Disable Apache Keepalive connections</li>
<li>Make Apache listen on <code class="codecolorer text solarized-light"><span class="text">127.0.0.1:81</span></code></li>
<li>Install Nginx</li>
<li>Configure Nginx as a reverse proxy to Apache</li>
<li>Update <code class="codecolorer text solarized-light"><span class="text">wp-config.php</span></code> to work with our new setup</li>
<li>Epic win</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://mattkirman.com/2011/06/01/how-to-speed-up-wordpress-with-nginx/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Introducing Spotio: A Spotify Remote</title>
		<link>http://mattkirman.com/2011/04/18/introducing-spotio-a-spotify-remote/</link>
		<comments>http://mattkirman.com/2011/04/18/introducing-spotio-a-spotify-remote/#comments</comments>
		<pubDate>Mon, 18 Apr 2011 21:14:03 +0000</pubDate>
		<dc:creator>Matt</dc:creator>
				<category><![CDATA[Spotio]]></category>
		<category><![CDATA[spotify]]></category>
		<category><![CDATA[spotio]]></category>

		<guid isPermaLink="false">http://mattkirman.com/?p=499</guid>
		<description><![CDATA[Spotio is an open-source, web-based, multi-user Spotify remote. It features support for viewing the currently playing track, skipping tracks and, most importantly, the ability to control playback. Spotio is optimised for use in a modern WebKit browser (such as Google Chrome and Mobile Safari). As such it&#8217;s possible for multiple people using multiple devices to [...]]]></description>
			<content:encoded><![CDATA[<p>Spotio is an open-source, web-based, multi-user Spotify remote. It features support for viewing the currently playing track, skipping tracks and, most importantly, the ability to control playback.</p>
<p>Spotio is optimised for use in a modern WebKit browser (such as Google Chrome and Mobile Safari). As such it&#8217;s possible for multiple people using multiple devices to control the playback of a Spotify playlist with <em>realtime</em> feedback.</p>
<p><span id="more-499"></span></p>
<p><img src="http://cdn.mattkirman.com/wp-content/uploads/2011/04/spotio-comp.jpg?572f3472050365387537b7c861946b04" width="460" height="300" /></p>
<p>The need for a Spotify remote with multi-user support reared it&#8217;s head whilst working at the office. Spotify is an excellent tool for allowing many people to collaborate on a playlist, but actually controlling what&#8217;s played is an area that hasn&#8217;t been fully explored yet.</p>
<p>As such, the office is now using a Mac Mini as a dedicated jukebox with our copy of Spotify running on it. This is in turn driving a 5.1 surround sound setup (courtesy of <a href="http://twitter.com/adamrhoades" target="_blank">Adam Rhoades</a>) with a central volume control. The final piece of the jigsaw is Spotio &#8211; this is installed as an application shortcut on everyone&#8217;s PC and iPhone allowing full control of the playlist as long as they&#8217;re connected to the office network.</p>
<p>Despite the fact that Spotio is far from finished, I&#8217;ve decided to start promoting it so that people can start playing with it, finding bugs and adding features.</p>
<p>Documentation is non-existent (unless you count a readme as documentation) but there isn&#8217;t really that much code so it shouldn&#8217;t take too much time to rectify matters (in theory).</p>
<h3>How It Works</h3>
<p>There are two distinct parts to Spotio. First there is the SIMBL bundle that provides us with a very simple API that can be used to control Spotify remotely. Ideally there should only be one connection to the API so that we minimise our impact on the Spotify process. Part two is little more than a proxy server written in Node.js and CoffeeScript that can easily scale to thousands of clients on one server.</p>
<p>The two parts are completely independent, however it&#8217;s important to realise that the SIMBL bundle can be used without Node but <em>not</em> vice-versa.</p>
<h3>Requirements</h3>
<ul>
<li>Mac OS X 10.6 &#8211; 10.5 might work, but it will never be officially supported</li>
<li><a href="http://www.culater.net/software/SIMBL/SIMBL.php" target="_blank">SIMBL</a></li>
<li><a href="http://nodejs.org/" target="_blank">Node</a></li>
<li><a href="http://npmjs.org/" target="_blank">Npm</a> for CoffeeScript support</li>
</ul>
<p>If you want to compile Spotio from source you will also need:</p>
<ul>
<li><a href="http://git-scm.org" target="_blank">Git VCS</a></li>
<li>Xcode 4</li>
<li><a href="http://rake.rubyforge.org/" target="_blank">Rake</a></li>
</ul>
<h3>Installation</h3>
<p>First, make sure you&#8217;ve installed the various dependencies. You can then <a href="https://github.com/mattkirman/spotio/downloads" target="_blank">download the latest copy</a> of the Spotio SIMBL bundle and Node server from GitHub. You will then need to move the Spotio bundle into your <code class="codecolorer text solarized-light"><span class="text">~/Library/Application Support/SIMBL/Plugins</span></code> directory for a single user installation or <code class="codecolorer text solarized-light"><span class="text">/Library/Application Support/SIMBL/Plugins</span></code> for all users.</p>
<p>Alternatively, if you like living on the edge, you can build the latest version of Spotio from source:</p>
<div class="codecolorer-container text solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ git clone git://github.com/mattkirman/spotio.git<br />
$ cd spotio<br />
$ rake plugin:build plugin:install</div></div>
<p>Rake will spit out the build results and then copy the compiled bundle into <code class="codecolorer text solarized-light"><span class="text">~/Library/Application Support/SIMBL/Plugins</span></code>.</p>
<p>Once you have installed Spotio you will need to restart Spotify for changes to take effect.</p>
<h3>Usage</h3>
<ol>
<li>Start Spotify</li>
<li>Open the Spotio Node directory in Finder</li>
<li>Open a terminal (<code class="codecolorer text solarized-light"><span class="text">/Applications/Utilities/Terminal</span></code>), type <code class="codecolorer text solarized-light"><span class="text">coffee</span></code> and drag <code class="codecolorer text solarized-light"><span class="text">server.coffee</span></code> into the terminal window. Hit enter.</li>
<li>Open <a href="http://127.0.0.1:8080" target="_blank"><code class="codecolorer text solarized-light"><span class="text">127.0.0.1:8080</span></code></a> (change this IP address for the one on your computer) in Chrome (or another WebKit browser).</li>
</ol>
<p>By default Spotio binds to all available IP addresses on port 8080. It&#8217;s fully compatible with DNS.</p>
<h3>Contributing</h3>
<p>This project was created as a way for me to learn Node/CoffeeScript and Objective-C. Without doubt things can be improved, so if you would like to lend a hand simply fork the repository and send me a pull request.</p>
<p>If you&#8217;re not on GitHub feel free to email me at <a href="mailto:matt@mattkirman.com">matt@mattkirman.com</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://mattkirman.com/2011/04/18/introducing-spotio-a-spotify-remote/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Super Secret Preferences in Twitter for Mac without the Nanobundle</title>
		<link>http://mattkirman.com/2011/01/13/super-secret-preferences-in-twitter-for-mac-without-the-nanobundle/</link>
		<comments>http://mattkirman.com/2011/01/13/super-secret-preferences-in-twitter-for-mac-without-the-nanobundle/#comments</comments>
		<pubDate>Thu, 13 Jan 2011 07:39:09 +0000</pubDate>
		<dc:creator>Matt</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://mattkirman.com/?p=379</guid>
		<description><![CDATA[It annoyed my slightly that simple things such as hitting escape to close the new tweet window were only available to people who&#8217;d purchased the MacHeist Nanobundle. You can enable these preferences yourself with only a small amount of command line tinkering. To disable the preference that you&#8217;ve just enabled change true to false and [...]]]></description>
			<content:encoded><![CDATA[<p>It annoyed my slightly that simple things such as hitting escape to close the new tweet window were only available to people who&#8217;d purchased the MacHeist Nanobundle. You can enable these preferences yourself with only a small amount of command line tinkering.</p>
<div class="gist-container"><script src="https://gist.github.com/768609.js?file=Twitter%20MacHeist%20Preferences"></script></div>
<p>To disable the preference that you&#8217;ve just enabled change <code class="codecolorer text solarized-light"><span class="text">true</span></code> to <code class="codecolorer text solarized-light"><span class="text">false</span></code> and vice versa.</p>
]]></content:encoded>
			<wfw:commentRss>http://mattkirman.com/2011/01/13/super-secret-preferences-in-twitter-for-mac-without-the-nanobundle/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>What I Learned from Zuckerberg’s Mistakes</title>
		<link>http://mattkirman.com/2011/01/01/what-i-learned-from-zuckerberg%e2%80%99s-mistakes/</link>
		<comments>http://mattkirman.com/2011/01/01/what-i-learned-from-zuckerberg%e2%80%99s-mistakes/#comments</comments>
		<pubDate>Sat, 01 Jan 2011 22:16:50 +0000</pubDate>
		<dc:creator>Matt</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[facebook]]></category>

		<guid isPermaLink="false">http://mattkirman.com/?p=374</guid>
		<description><![CDATA[I&#8217;ve been an avid reader of Jason Calacanis&#8216; various newsletters for some time, not least for the sheer amount of work he puts into each and every one. In his latest newsletter he offers a suggestion as to why Facebook is perceived as either evil, clueless or just plain unlucky when it comes to releasing new [...]]]></description>
			<content:encoded><![CDATA[<div>
<p>I&#8217;ve been an avid reader of <a href="http://twitter.com/jason"><cite>Jason Calacanis</cite>&#8216;</a> various newsletters for some time, not least for the sheer amount of work he puts into each and every one.</p>
<p>In his latest newsletter he offers a suggestion as to why Facebook is perceived as either evil, clueless or just plain unlucky when it comes to releasing new products:</p>
<blockquote><p>Facebook&#8217;s success &#8212; and mistakes &#8212; are based on its developer-driven culture, not because Zuckerberg is some evil mastermind.</p>
<p>The Zuckerberg Doctrine: Developers design products with significantly improved speed and functionality compared to product managers and designers, outweighing potential mistakes and drawbacks.</p></blockquote>
<p>And in this world, speed is everything. We shouldn&#8217;t be afraid of making mistakes at the cost of innovation. New Year Resolution anyone?</p>
<p>You can sign up for Jason&#8217;s free newsletter <a href="http://launch.is/">here</a>.</p>
</div>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://mattkirman.com/2011/01/01/what-i-learned-from-zuckerberg%e2%80%99s-mistakes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Facebook Places launches in the UK</title>
		<link>http://mattkirman.com/2010/09/17/facebook-places-launches-in-the-uk/</link>
		<comments>http://mattkirman.com/2010/09/17/facebook-places-launches-in-the-uk/#comments</comments>
		<pubDate>Fri, 17 Sep 2010 06:29:10 +0000</pubDate>
		<dc:creator>Matt</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[geolocation]]></category>
		<category><![CDATA[places]]></category>

		<guid isPermaLink="false">http://mattkirman.com/?p=333</guid>
		<description><![CDATA[Well it looks like Facebook Places has just launched in the UK. Worryingly this was brought to my attention by my newsfeed showing that one of my distant friends (who shall remain nameless) has just checked-in to his house. Let&#8217;s just hope that place isn&#8217;t publicly available, though I doubt it as it&#8217;s listed as [...]]]></description>
			<content:encoded><![CDATA[<p>Well it looks like Facebook Places has just launched in the UK. Worryingly this was brought to my attention by my newsfeed showing that one of my distant friends (who shall remain nameless) has just checked-in to his house. Let&#8217;s just hope that place isn&#8217;t publicly available, though I doubt it as it&#8217;s listed as a &#8220;Local Business&#8221;. Way to go Facebook.</p>
]]></content:encoded>
			<wfw:commentRss>http://mattkirman.com/2010/09/17/facebook-places-launches-in-the-uk/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>My Git Workflow; Introducing Flit</title>
		<link>http://mattkirman.com/2010/08/27/my-git-workflow-introducing-flit/</link>
		<comments>http://mattkirman.com/2010/08/27/my-git-workflow-introducing-flit/#comments</comments>
		<pubDate>Fri, 27 Aug 2010 21:42:19 +0000</pubDate>
		<dc:creator>Matt</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[Downloads]]></category>
		<category><![CDATA[flit]]></category>
		<category><![CDATA[git]]></category>

		<guid isPermaLink="false">http://mattkirman.com/?p=306</guid>
		<description><![CDATA[I&#8217;ve been a Git convert, and version control geek, for over a year now so I&#8217;ve sort of become the unofficial Git consultant at the office. If anythings breaks or something weird happens I&#8217;m usually the one called in to sort it out. In order to preserve at least some of the remnants of our [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been a Git convert, and version control geek, for over a year now so I&#8217;ve sort of become the unofficial Git consultant at the office. If anythings breaks or something weird happens I&#8217;m usually the one called in to sort it out.</p>
<p>In order to preserve at least some of the remnants of our sanity I decided, after my colleague managed to corrupt his entire local repository, that I needed to enforce some sort of system. What I finished up with is this fairly typical workflow:</p>
<ul>
<li>Find a feature (or bugfix, ticket, etc.) to work on</li>
<li><code class="codecolorer text solarized-light"><span class="text">git checkout -b my_new_feature</span></code></li>
<li>Hack away at some code</li>
<li><code class="codecolorer text solarized-light"><span class="text">git commit</span></code> early and often. Small diffs are the key.</li>
<li>When I&#8217;ve finished <code class="codecolorer text solarized-light"><span class="text">git checkout master</span></code></li>
<li><code class="codecolorer text solarized-light"><span class="text">git pull</span></code> any changes</li>
<li><code class="codecolorer text solarized-light"><span class="text">git checkout my_new_feature</span></code></li>
<li><code class="codecolorer text solarized-light"><span class="text">git rebase master</span></code></li>
<li>Fix any merge conflicts that I may have. If there are conflicts, fix them and keep going. Merge conflicts should be kept off the master branch if at all possible.</li>
<li><code class="codecolorer text solarized-light"><span class="text">git rebase -i</span></code> so that I squash all the commits in my branch down into one. This keeps the master branch nice and tidy.</li>
<li><code class="codecolorer text solarized-light"><span class="text">git checkout master</span></code> once the code is ready</li>
<li><code class="codecolorer text solarized-light"><span class="text">git merge my_new_feature</span></code></li>
<li><code class="codecolorer text solarized-light"><span class="text">git push</span></code></li>
</ul>
<p><span id="more-306"></span></p>
<p>Once our code is ready for staging we push our code to the <code class="codecolorer text solarized-light"><span class="text">staging</span></code> branch, and likewise to the <code class="codecolorer text solarized-light"><span class="text">production</span></code> branch. The <code class="codecolorer text solarized-light"><span class="text">master</span></code> branch is reserved for bleeding edge code.</p>
<p>I then started thinking, surely there must be a much easier way to manage this workflow? A minimum of seven separate commands to merge my changes into <code class="codecolorer text solarized-light"><span class="text">master</span></code> and push it back to the server?</p>
<h3>Introducing Flit</h3>
<p>Flit is a command line utility that eases the typical Git workflow that I&#8217;ve outlined above. Setting up Flit to work with either a new or existing Git repository is a simple as <code class="codecolorer text solarized-light"><span class="text">flit init</span></code>. If you haven&#8217;t already created a Git repository then Flit will create one for you.</p>
<p>Then, whenever you want to start, or continue with, a feature or bugfix simply do <code class="codecolorer text solarized-light"><span class="text">flit start feature my_new_feature</span></code>. Flit will create, or switch, to your feature branch, ready for you to start hacking away.</p>
<p>You can then use Git as normal, committing your changes as and when you see fit. Once you&#8217;ve finished work for the day on your feature or bugfix, <code class="codecolorer text solarized-light"><span class="text">flit stop</span></code> will return you back to your development branch.</p>
<p>Once your feature is complete <code class="codecolorer text solarized-light"><span class="text">flit finish feature my_new_feature</span></code> will pull down changes in <code class="codecolorer text solarized-light"><span class="text">master</span></code>, rebase them into your feature branch and then merge your feature back into <code class="codecolorer text solarized-light"><span class="text">master</span></code>.</p>
<h3>Caveats</h3>
<p>Flit is an extremely early alpha. Features may be broken or just plain missing, but getting this code out into the open-source community where people can start hacking away with it is much more important.</p>
<p>To that end, the entire codebase is hosted on <a href="http://github.com/mattkirman/flit">GitHub</a>. If something&#8217;s missing just fork the code, add your fix and send me a pull request.</p>
<h3>Requirements</h3>
<ul>
<li>Git 1.6.4 or greater</li>
<li>Ruby 1.8.7 or greater</li>
<li>RubyGems</li>
</ul>
<h3>Installation</h3>
<p>The easiest way to install Flit is through RubyGems:<br />
<code class="codecolorer text solarized-light"><span class="text">gem install flit --pre</span></code></p>
<p>Alternatively you can install Flit from source:<br />
<code class="codecolorer text solarized-light"><span class="text">rake gem &amp;&amp; rake install</span></code></p>
]]></content:encoded>
			<wfw:commentRss>http://mattkirman.com/2010/08/27/my-git-workflow-introducing-flit/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>YUI Compressor TextMate Bundle</title>
		<link>http://mattkirman.com/2009/11/13/yui-compressor-textmate-bundle/</link>
		<comments>http://mattkirman.com/2009/11/13/yui-compressor-textmate-bundle/#comments</comments>
		<pubDate>Fri, 13 Nov 2009 13:14:25 +0000</pubDate>
		<dc:creator>Matt</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[Downloads]]></category>
		<category><![CDATA[compressor]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[textmate]]></category>
		<category><![CDATA[yui]]></category>

		<guid isPermaLink="false">http://mattkirman.com/?p=245</guid>
		<description><![CDATA[Even though the Google Closure Compiler is very useful for compressing JavaScript it has absolutely no support for CSS, something that the YUI Compressor excels at. I give you the YUI Compressor TextMate bundle, an almost direct port of the Google Closure Compiler TextMate bundle but with a different compression library. It has support for [...]]]></description>
			<content:encoded><![CDATA[<p>Even though the Google Closure Compiler is very useful for compressing JavaScript it has absolutely no support for CSS, something that the YUI Compressor excels at. I give you the YUI Compressor TextMate bundle, an almost direct port of the <a href="http://mattkirman.com/2009/11/10/google-closure-compiler-textmate-bundle/">Google Closure Compiler TextMate bundle</a> but with a different compression library.</p>
<p>It has support for compressing multiple JavaScript and CSS files at the same time; just select the files you want to compress and hit &#x21E7;&#8984;Y.</p>
<p><span id="more-245"></span></p>
<h3>Requirements</h3>
<p>The YUI Compressor bundle requires:</p>
<ul>
<li><a href="http://yuilibrary.com/downloads/#yuicompressor" target="_blank">The YUI Compressor</a></li>
<li><a href="http://www.ruby-lang.org/" target="_blank">Ruby</a> version 1.8.7 or greater (installed as default on Mac OS 10.5 and above)</li>
<li>and <a href="http://macromates.com/" target="_blank">TextMate</a> (obviously)</li>
</ul>
<p>Please make sure you read the <a href="http://github.com/mattkirman/YUI-Compressor-tmbundle/blob/master/README.md" target="_blank">README</a> before installing. The YUI Compressor TextMate bundle is licenced under the <a href="http://www.opensource.org/licenses/gpl-2.0.php" target="_blank">GPL Licence</a>. This bundle has only been tested with the latest versions of Mac OS X (v10.6.2) and TextMate (v1.5.8) but should work with earlier versions as long as the requirements above are met.</p>
<h3>Get It</h3>
<ul>
<li><a href="http://github.com/mattkirman/YUI-Compressor-tmbundle/downloads">Downloads</a></li>
<li><a href="http://github.com/mattkirman/YUI-Compressor-tmbundle">Source</a></li>
</ul>
<p>Using this bundle? Got any suggestions? Let me know in the comments!</p>
]]></content:encoded>
			<wfw:commentRss>http://mattkirman.com/2009/11/13/yui-compressor-textmate-bundle/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Google Closure Compiler TextMate Bundle</title>
		<link>http://mattkirman.com/2009/11/10/google-closure-compiler-textmate-bundle/</link>
		<comments>http://mattkirman.com/2009/11/10/google-closure-compiler-textmate-bundle/#comments</comments>
		<pubDate>Tue, 10 Nov 2009 15:51:12 +0000</pubDate>
		<dc:creator>Matt</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[Downloads]]></category>
		<category><![CDATA[closure-compiler]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[textmate]]></category>

		<guid isPermaLink="false">http://mattkirman.com/?p=212</guid>
		<description><![CDATA[I&#8217;ve been trying out the brand new Google Closure Compiler instead of the YUI Compressor. I&#8217;m not going to go into any detail about the Closure Compiler as there&#8217;s plenty of information out there already, but I can say that it looks like another solid offering from Google. Anyway, in an effort to make a [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been trying out the brand new <a href="http://code.google.com/closure/compiler/" target="_blank">Google Closure Compiler</a> instead of the <a href="http://yuilibrary.com/downloads/#yuicompressor" target="_blank">YUI Compressor</a>. I&#8217;m not going to go into any detail about the Closure Compiler as there&#8217;s plenty of information out there already, but I can say that it looks like another solid offering from Google.</p>
<p>Anyway, in an effort to make a pretty good piece of software even better I decided to make a <a href="http://macromates.com/" target="_blank">TextMate</a> bundle for it so that it&#8217;s never more than a keystroke away (defaults to &#x21E7;&#8984;G).</p>
<p><span id="more-212"></span></p>
<h3>Requirements</h3>
<p>The Google Closure Compiler bundle requires:</p>
<ul>
<li><a href="http://closure-compiler.googlecode.com/files/compiler-latest.zip">The Google Closure Compiler</a> (not included in the bundle)</li>
<li><a href="http://www.ruby-lang.org/" target="_blank">Ruby</a> version 1.8.7 or greater (installed as standard on Mac OS 10.5 and above)</li>
<li><a href="http://macromates.com/" target="_blank">TextMate</a> (obviously)</li>
</ul>
<p>Make sure you read the <a href="http://github.com/mattkirman/GoogleClosureCompiler-tmbundle/blob/master/README.md">README</a> file before installing. The Google Closure Compiler TextMate bundle is licenced under the <a href="http://www.opensource.org/licenses/gpl-2.0.php">GPL Licence</a>. This bundle has only been tested with the latest versions of Mac OS X (v10.6.2) and TextMate (v1.5.8) but should work with earlier versions as long as the requirements above are met.</p>
<h3>Get It</h3>
<ul>
<li><strong>[Update]</strong> The bundle is now available via the <a href="http://svn.textmate.org/trunk/Review/Bundles/GetBundles.tmbundle/" target="_blank">GetBundles</a> TextMate bundle. Simply search for &#8220;Google Closure Compiler&#8221; (Recommended)</li>
<li><a href="http://github.com/mattkirman/GoogleClosureCompiler-tmbundle/downloads">Downloads</a></li>
<li><a href="http://github.com/mattkirman/GoogleClosureCompiler-tmbundle">Source code</a></li>
</ul>
<p>Using this bundle? Got any suggestions? Let me know in the comments!</p>
]]></content:encoded>
			<wfw:commentRss>http://mattkirman.com/2009/11/10/google-closure-compiler-textmate-bundle/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Equal height columns with pure CSS</title>
		<link>http://mattkirman.com/2009/10/12/equal-height-columns-with-pure-css/</link>
		<comments>http://mattkirman.com/2009/10/12/equal-height-columns-with-pure-css/#comments</comments>
		<pubDate>Mon, 12 Oct 2009 11:46:36 +0000</pubDate>
		<dc:creator>Matt</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[html]]></category>

		<guid isPermaLink="false">http://mattkirman.com/?p=172</guid>
		<description><![CDATA[A common problem when designing for the web is how to create equal height columns. The usual solution is to either resort to JavaScript or CSS absolute positioning, here I will show you how to create equal height columns with pure CSS using the margin, padding and float properties. HTML The HTML of our page [...]]]></description>
			<content:encoded><![CDATA[<p>A common problem when designing for the web is how to create equal height columns. The usual solution is to either resort to JavaScript or CSS absolute positioning, here I will show you how to create equal height columns with pure CSS using the <code class="codecolorer text solarized-light"><span class="text">margin</span></code>, <code class="codecolorer text solarized-light"><span class="text">padding</span></code> and <code class="codecolorer text solarized-light"><span class="text">float</span></code> properties.</p>
<p><span id="more-172"></span></p>
<h2>HTML</h2>
<p>The HTML of our page is going to look something like this:</p>
<div class="codecolorer-container html4strict solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;wrapper&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;content&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ...<br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;sidebar&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ...<br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span></div></div>
<h2>CSS</h2>
<p>Our page is going to be 500px wide, with a 300px content area and a 200px sidebar. The CSS:</p>
<div class="codecolorer-container css solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="css codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #cc00cc;">#wrapper</span> <span style="color: #00AA00;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">margin</span><span style="color: #00AA00;">:</span> <span style="color: #cc66cc;">0</span> <span style="color: #993333;">auto</span><span style="color: #00AA00;">;</span> &nbsp; &nbsp;<span style="color: #808080; font-style: italic;">/* Center the wrapper horizontally */</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">overflow</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">hidden</span><span style="color: #00AA00;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">width</span><span style="color: #00AA00;">:</span> <span style="color: #933;">500px</span><span style="color: #00AA00;">;</span><br />
<span style="color: #00AA00;">&#125;</span><br />
<br />
<span style="color: #cc00cc;">#content</span><span style="color: #00AA00;">,</span> <span style="color: #cc00cc;">#sidebar</span> <span style="color: #00AA00;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">margin-bottom</span><span style="color: #00AA00;">:</span> <span style="color: #933;">-10000px</span><span style="color: #00AA00;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">padding-bottom</span><span style="color: #00AA00;">:</span> <span style="color: #933;">100000px</span><span style="color: #00AA00;">;</span><br />
<span style="color: #00AA00;">&#125;</span><br />
<br />
<span style="color: #cc00cc;">#content</span> <span style="color: #00AA00;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">float</span><span style="color: #00AA00;">:</span> <span style="color: #000000; font-weight: bold;">right</span><span style="color: #00AA00;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">width</span><span style="color: #00AA00;">:</span> <span style="color: #933;">300px</span><span style="color: #00AA00;">;</span><br />
<span style="color: #00AA00;">&#125;</span><br />
<br />
<span style="color: #cc00cc;">#sidebar</span> <span style="color: #00AA00;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">float</span><span style="color: #00AA00;">:</span> <span style="color: #000000; font-weight: bold;">left</span><span style="color: #00AA00;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">width</span><span style="color: #00AA00;">:</span> <span style="color: #933;">200px</span><span style="color: #00AA00;">;</span><br />
<span style="color: #00AA00;">&#125;</span></div></div>
<h2>The Demo</h2>
<p>Putting this together you end up with something like this:</p>
<div style="background:#fff;position:relative;margin:0 auto;overflow:hidden;width:500px">
<div style="float:right;padding-bottom:10000px;margin-bottom:-10000px;width:300px">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</p></div>
<div style="background:#ccc;float:left;padding-bottom:10000px;margin-bottom:-10000px;width:200px">
<ul>
<li>Page 1</li>
<li>Page 2</li>
<li>Page 3</li>
</ul></div>
</div>
<h2>Why does this work?</h2>
<p>The key to creating equal height columns using this method are the <code class="codecolorer text solarized-light"><span class="text">overflow: hidden</span></code> selector on the wrapper and the large <code class="codecolorer text solarized-light"><span class="text">padding-bottom</span></code> and negative <code class="codecolorer text solarized-light"><span class="text">margin-bottom</span></code>. Any padding is hidden when setting the overflow of the container to hidden. Basically, this means that by setting a large enough <code class="codecolorer text solarized-light"><span class="text">padding-bottom</span></code> then we can effectively stretch the background colour of the element to the bottom of the page. If 10000px isn&#8217;t enough then just make it even larger.</p>
<p>The large negative <code class="codecolorer text solarized-light"><span class="text">margin-bottom</span></code> then tells the browser where to render the bottom of the box (I think. Don&#8217;t quote me on that). If we had set a <code class="codecolorer text solarized-light"><span class="text">height</span></code> of the container this wouldn&#8217;t have worked, and without the negative <code class="codecolorer text solarized-light"><span class="text">margin-bottom</span></code> we would have ended up with a container over 10000px tall.</p>
<p><strong>When using this method always make sure that you set the <code class="codecolorer text solarized-light"><span class="text">margin-bottom</span></code> to be equal and negative of the <code class="codecolorer text solarized-light"><span class="text">padding-bottom</span></code>.</strong></p>
<p>And the best bit of this method? If you decide that you now want your sidebar on the right, simply set <code class="codecolorer text solarized-light"><span class="text">float: right</span></code> on the <code class="codecolorer text solarized-light"><span class="text">#sidebar</span></code> and <code class="codecolorer text solarized-light"><span class="text">float: left</span></code> on the <code class="codecolorer text solarized-light"><span class="text">#content</span></code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://mattkirman.com/2009/10/12/equal-height-columns-with-pure-css/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Blog redesign #4 (and why the WordPress Plugin API needs fixing)</title>
		<link>http://mattkirman.com/2009/10/08/blog-redesign-4-and-why-the-wordpress-plugin-api-needs-fixing/</link>
		<comments>http://mattkirman.com/2009/10/08/blog-redesign-4-and-why-the-wordpress-plugin-api-needs-fixing/#comments</comments>
		<pubDate>Thu, 08 Oct 2009 14:18:18 +0000</pubDate>
		<dc:creator>Matt</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[Downloads]]></category>
		<category><![CDATA[Thoughts]]></category>
		<category><![CDATA[glimmer]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[mootools]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://mattkirman.com/?p=136</guid>
		<description><![CDATA[Whilst I was redesigning my blog (what do you think by the way) I decided that what I really needed to finish it off was an ajaxy live search. Now normally I would have looked for a jQuery version, but as I&#8217;ve been trying my hand at a bit of MooTools recently I decided to [...]]]></description>
			<content:encoded><![CDATA[<p>Whilst I was redesigning my blog (what do you think by the way) I decided that what I really needed to finish it off was an ajaxy live search. Now normally I would have looked for a <a href="http://jquery.com/">jQuery</a> version, but as I&#8217;ve been trying my hand at a bit of <a href="http://mootools.net/">MooTools</a> recently I decided to write my own plugin. By the way, if you want to use it on your own site it&#8217;s available for <a href="http://github.com/mattkirman/wp-live-search">download</a> on GitHub.</p>
<p>After a few minutes hacking it together on my local web-server I had a pretty good implementation, even if I say so myself. However, once I&#8217;d installed it onto my live server it stopped returning any results. The reason for this? I had WP Super Cache installed on my live server, but not on my local server, and was messing up the JSON output by putting a comment at the bottom. Obviously, the JavaScript function refused to parse it as valid JSON. When I turned WP Super Cache off everything returned to normal.</p>
<p>As a developer this was simple enough to debug and fix, but for the average user who just wants to use WordPress, install some plugins and then start blogging away this incompatibility simply isn&#8217;t good enough. Before you know it you&#8217;ll end up with your support forums full of posts such as &#8220;<em>Your plugin doesn&#8217;t work with xxxx, please fix it</em>&#8220;, even if you have already stated this issue in your readme and installation guides.</p>
<p><span id="more-136"></span></p>
<p>Then it struck me: <strong>the WordPress Plugin API is broken</strong>.  As developers we shouldn&#8217;t have to rely on users checking that their plugins play nicely together, the plugin should know <em>before</em> it has even been activated. An excellent example of this is the <a href="http://docs.rubygems.org/">RubyGems</a> framework. I propose, therefore, <a href="http://glimmer.redflex.co.uk/">Glimmer</a> &#8211; the next-generation plugin manager for WordPress. Now, that&#8217;s a pretty bold claim to make, but I strongly believe that this is the route that WordPress ought to be going down. But just don&#8217;t take my word for it, let&#8217;s have a look at what&#8217;s planned for Glimmer Alpha 1:</p>
<dl>
<dt>Dependency checking</dt>
<dd>Utilise the hours of work carried out by other developers by building on their plugins. The user is prompted if a required plugin is missing. Glimmer can then, in some cases, automatically install missing plugins. Glimmer can even check to make sure that the correct WordPress version in installed and that certain PHP functions and extensions are available.</dd>
<dt>Incompatibility checking</dt>
<dd>Known issues with a third party plugin? Don&#8217;t rely on the user, Glimmer can warn them about possible incompatibilities before they have even activated the plugin on their site.</dd>
<dt>Easy distribution</dt>
<dd>You are no longer forced to use the WordPress hosted SVN if you want to provide automatic updates of your plugin. Glimmer uses <a href="http://connectedflow.com/appcasting/">Appcasts</a>, a RSS variant, to distribute your code from any web server. If users have already installed Glimmer they can ask it to install from the <tt>your-plugin-name.glimmer</tt> file which gets distributed with your plugin, saving them the need to upload your plugin via FTP (and potentially getting it wrong).</dd>
<dt>Awesome updates</dt>
<dd>Glimmer automatically checks for plugin updates. Better still, Glimmer supports multiple development branches (e.g. providing a legacy branch for a previous version of WordPress) and scheduling future updates via the RSS <tt>pubDate</tt> element. You can also embed any release notes in the feed to be displayed to the user <em>before</em> they update.</dd>
<dt>Glimmer is an extension, not a replacement</dt>
<dd>Users who haven&#8217;t got Glimmer installed will still be able to use your plugin but just without all the fancy features and improvements that Glimmer provides. If you want to Glimmer-ise an existing plugin simply add a <tt>your-plugin-name.glimmer</tt> file to the plugin directory.</dd>
</dl>
<p>Glimmer is open-source, it&#8217;s licensed under the <a href="http://www.opensource.org/licenses/gpl-2.0.php">GPL Licence</a>, and is <a href="http://github.com/mattkirman/glimmer">available on GitHub</a>. If you would like to contribute to Glimmer please get in touch, by leaving a comment here, messaging me on <a href="http://twitter.com/mattkirman">Twitter</a> or just send me a pull request on GitHub.</p>
]]></content:encoded>
			<wfw:commentRss>http://mattkirman.com/2009/10/08/blog-redesign-4-and-why-the-wordpress-plugin-api-needs-fixing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using Capistrano to deploy PHP (or anything else in a Git repository)</title>
		<link>http://mattkirman.com/2009/09/17/using-capistrano-to-deploy-php/</link>
		<comments>http://mattkirman.com/2009/09/17/using-capistrano-to-deploy-php/#comments</comments>
		<pubDate>Thu, 17 Sep 2009 21:56:32 +0000</pubDate>
		<dc:creator>Matt</dc:creator>
				<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://mattkirman.com/?p=122</guid>
		<description><![CDATA[Recently I&#8217;ve been looking at a way to ease the path of deploying PHP applications to my servers. I eventually settled on the excellent Ruby tool Capistrano which is very popular with the Rails crowd. Now, I&#8217;m aware of the irony of using Ruby to deploy PHP but please bare with me. All of my [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I&#8217;ve been looking at a way to ease the path of deploying <a href="http://php.net/">PHP</a> applications to my servers. I eventually settled on the excellent <a href="http://www.ruby-lang.org/">Ruby</a> tool <a href="http://www.capify.org/">Capistrano</a> which is very popular with the <a href="http://rubyonrails.org/">Rails</a> crowd. Now, I&#8217;m aware of the irony of using Ruby to deploy PHP but please bare with me.</p>
<p>All of my code is stored in the <a href="http://git-scm.com/">Git</a> VCS with a bare repository on the server, which is what you should be doing as well. Once you&#8217;ve got used to managing your code with Git over SSH you will never want to go back to FTP again. Seriously, try it.</p>
<p>My work-flow is fairly typical: clone the repository onto my local machine; hack away; commit the changes and push the commit back to the server. The problem arises when it comes to deploying this code &#8211; I could either set up a post-update hook in the bare repository to pull the changes into the web root or do it manually.</p>
<p><span id="more-122"></span></p>
<p>Using a post-update hook is not ideal. For one, I might not want to trigger a <code class="codecolorer text solarized-light"><span class="text">git pull</span></code> every time I push a commit to the server. Furthermore, how would I go about differentiating between staging and production servers? And manually SSH-ing into the server, changing to the correct directory and running a <code class="codecolorer text solarized-light"><span class="text">git pull</span></code> every time is just too long winded and time consuming.</p>
<p>Instead, I looked at a way to automate the process. I&#8217;m quite a fan of Ruby, so I naturally turned to a Ruby solution, Capistrano. Plus the blurb on their home page described the exact tool that I was looking for. That&#8217;s some really great copy writing. So, without any hesitation, I quickly ran <code class="codecolorer text solarized-light"><span class="text">sudo gem install capistrano</span></code> and started to have a play around.</p>
<p>The first thing you want to do is to create a <tt>capfile</tt> in the root of your web application. This is to capistrano as a rakefile is to rake and a makefile is to make. Once you&#8217;ve got your capfile you can run <code class="codecolorer text solarized-light"><span class="text">cap -T</span></code> to see a list of your Capistrano recipes. By default Capistrano includes the <code class="codecolorer text solarized-light"><span class="text">invoke</span></code> and <code class="codecolorer text solarized-light"><span class="text">shell</span></code> recipes. I&#8217;m not going to explain what these do as they are documented well enough elsewhere.</p>
<p>The next thing you want to do is to create your <code class="codecolorer text solarized-light"><span class="text">deploy</span></code> namespace:</p>
<div class="codecolorer-container ruby solarized-dark" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">set <span style="color:#ff3333; font-weight:bold;">:web_directory</span>, <span style="color:#996600;">&quot;the deployed file location&quot;</span><br />
set <span style="color:#ff3333; font-weight:bold;">:branch</span>, <span style="color:#996600;">&quot;origin/master&quot;</span><br />
<br />
role <span style="color:#ff3333; font-weight:bold;">:server</span>, <span style="color:#996600;">&quot;your server address&quot;</span><br />
<br />
namespace <span style="color:#ff3333; font-weight:bold;">:deploy</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; desc <span style="color:#996600;">&quot;Updates the code on the server&quot;</span><br />
&nbsp; &nbsp; task <span style="color:#ff3333; font-weight:bold;">:default</span>, <span style="color:#ff3333; font-weight:bold;">:roles</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:server</span>, <span style="color:#ff3333; font-weight:bold;">:except</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#ff3333; font-weight:bold;">:no_release</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span> <span style="color:#006600; font-weight:bold;">&#125;</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; run <span style="color:#006600; font-weight:bold;">&#91;</span> <span style="color:#996600;">&quot;cd #{web_directory}&quot;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#996600;">&quot;git fetch origin&quot;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#996600;">&quot;git reset --hard #{branch}&quot;</span> <span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;; &quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; &nbsp; desc <span style="color:#996600;">&quot;Rollback a single commit on the server&quot;</span><br />
&nbsp; &nbsp; task <span style="color:#ff3333; font-weight:bold;">:rollback</span>, <span style="color:#ff3333; font-weight:bold;">:roles</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:server</span>, <span style="color:#ff3333; font-weight:bold;">:except</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#ff3333; font-weight:bold;">:no_release</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span> <span style="color:#006600; font-weight:bold;">&#125;</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; set <span style="color:#ff3333; font-weight:bold;">:branch</span>, <span style="color:#996600;">&quot;HEAD^&quot;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; default<br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></div>
<p>Then once you decide that your code is at the right point to be deployed to your web server, simply call <code class="codecolorer text solarized-light"><span class="text">cap deploy</span></code>. That&#8217;s it! No more messing around with Git commands on a remote server.</p>
<p>This isn&#8217;t an ideal configuration, obviously there ought to be a way to decide which branch/tag is checked out. But, as a 2 minute fix, this&#8217;ll do for now.</p>
]]></content:encoded>
			<wfw:commentRss>http://mattkirman.com/2009/09/17/using-capistrano-to-deploy-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Page Caching using apc
Database Caching using apc
Object Caching 4158/4350 objects using apc

Served from: mattkirman.com @ 2012-05-18 17:33:47 -->
