<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>Rex // web + graphic design</title><link>http://soyrex.com/</link><description>Syndication of new articles on my blog http://soyrex.com/</description><language>en-us</language><lastBuildDate>Thu, 30 Apr 2009 06:22:28 -0000</lastBuildDate><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/soyrex/design" type="application/rss+xml" /><feedburner:emailServiceId>soyrex/design</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item><title>Making the switch to GMail</title><link>http://feedproxy.google.com/~r/soyrex/design/~3/vsOJlUOxD-c/</link><description>&lt;span style="color: #666"&gt;Posted: Thu 30 Apr 2009 
| By: Alex Holt  
| &lt;a href="http://soyrex.com/blog/making-switch-gmail/"&gt;Read this post in context&lt;/a&gt;
&lt;/span&gt;
&lt;p&gt;For ages i've been wishing i could use my Google Apps account as my primary email without having to step outside their interface at all. Well, i've made the switch.
&lt;/p&gt;

&lt;h2&gt;Why did I wait so long?&lt;/h2&gt;
&lt;p&gt;GMail is a far better way to organise email and helps me keep my inbox zeroed :) So why have a had a Google Apps account for like 2 years and not switched to JUST the web interface?
&lt;/p&gt;

&lt;h4&gt;Dependancy on my Browser&lt;/h4&gt;
&lt;p&gt;I work as a web developer alot. I often break my web browser.. it hangs because of bad JS code, or I forget and have like 7 million tabs open - whatever. The problem is, if i have my mail in ONE of those tabs and the browser crashes.. my mail goes away.. annoying (not a deal breaker.. but irritating).
&lt;/p&gt;

&lt;h4&gt;Notifications&lt;/h4&gt;
&lt;p&gt;I like the Apple Mail dock badges that tell me how much unread mail i have - mostly so I can happily tell myself I've got everything under control (since the count badge is almost never there :) ).
&lt;/p&gt;
&lt;p&gt;Also, i like having growl notifications for my mail, and again this isn't possible with a web browser instance.
&lt;/p&gt;

&lt;h4&gt;The Interface&lt;/h4&gt;
&lt;p&gt;The UI for GMail has always been impressively functional, however not really that pretty (in fact - until recently it was ugly as sin). However a few months back Google rolled out themes for Gmail, and a few months later than that the update finally got pushed through to Google Apps accounts (including mine) - so now the Gmail interface isn't ugly anymore.
&lt;/p&gt;

&lt;h4&gt;Offline Mail Access&lt;/h4&gt;
&lt;p&gt;Well, we all know that Google Gears has been around for a while. Well you can now activate offline mail syncing for your gmail account using Gears.. which is perfect. I'm almost never offline, but I like to think that if for some reason I am, I can still refer to my mail - since half my life revolves around it.
&lt;/p&gt;

&lt;h2&gt;So, the solution? Fluid and Google Notifier&lt;/h2&gt;
&lt;p&gt;The latest version of &lt;a href="http://fluidapp.com"&gt;Fluid&lt;/a&gt; supports dock badges for GMail internally and also has a greasemonkey userscript that supports Growl notifications. If you combine that with Google Notifier you have badges on the icon, sound alerts AND growl notifications - perfect.
&lt;/p&gt;
&lt;p&gt;Fluid also has a nice Black HUD theme that makes my client look all pretty ;) Coupled with the new themes, it fits in with my desktop almost perfectly. 
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=vsOJlUOxD-c:AMsVs5uVoQo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=vsOJlUOxD-c:AMsVs5uVoQo:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=vsOJlUOxD-c:AMsVs5uVoQo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=vsOJlUOxD-c:AMsVs5uVoQo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=vsOJlUOxD-c:AMsVs5uVoQo:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=vsOJlUOxD-c:AMsVs5uVoQo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=vsOJlUOxD-c:AMsVs5uVoQo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=vsOJlUOxD-c:AMsVs5uVoQo:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/soyrex/design/~4/vsOJlUOxD-c" height="1" width="1"/&gt;</description><pubDate>Thu, 30 Apr 2009 06:22:28 -0000</pubDate><guid isPermaLink="false">http://soyrex.com/blog/making-switch-gmail/</guid><feedburner:origLink>http://soyrex.com/blog/making-switch-gmail/</feedburner:origLink></item><item><title>T&amp;amp;T #1: Digital Color Meter</title><link>http://feedproxy.google.com/~r/soyrex/design/~3/WHg4O4j0Ve4/</link><description>&lt;span style="color: #666"&gt;Posted: Sat 17 Jan 2009 
| By: Alex Holt  
| &lt;a href="http://soyrex.com/blog/tt-1-digital-color-meter/"&gt;Read this post in context&lt;/a&gt;
&lt;/span&gt;
&lt;p&gt;&lt;strong&gt;The new Tips&amp;amp;Tools section of my blog is where I will try to share tips and tricks that I use every day - expect sporadic updates.&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;Design Helper Tools that never make it to design blogs.. In no particular order, these are the few things that I've noticed never get written up in lists of tools that people use every day. 
&lt;/p&gt;
&lt;p&gt;I think it's safe to say that between TextMate and Coda 90% of the mac web development community is accounted for... but what about all the tools we use every day to help us with our work that never get any recognition?
&lt;/p&gt;

&lt;h2&gt;Tips &amp;amp; Tools 1: Digital Color Meter..&lt;/h2&gt;
&lt;p&gt;Digital Color Meter is basically your Photoshop colour picker for your entire mac desktop. Gone are the days where I needed to open a PSD just to work out the hex codes for a colour off a site.
&lt;/p&gt;
&lt;p&gt;DCM lives in the Applications/Utilities folder on your mac When you open it you are presented with a small window, the left of which shows a small zoomed image of what's under your mouse and the right allows you to choose the type of colours you are interested in. For our purposes as a web developer we want hex codes, so we choose RGB in Hexadecimal (8bit).
&lt;/p&gt;
&lt;p&gt;The true secret to working this tool into your workflow is the keyboard shortcut to copy the colour as text. To do this, you just hit Apple-Shift-C while the correct colour is shown, this will copy the text of the hexadecimal colour into your clipboard.. something like:  "#186231". This can be pasted directly into your CSS or HTML. It's somewhat annoying that it copies with quote marks... but still a real time saver.
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=WHg4O4j0Ve4:uHOOtJoBdQk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=WHg4O4j0Ve4:uHOOtJoBdQk:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=WHg4O4j0Ve4:uHOOtJoBdQk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=WHg4O4j0Ve4:uHOOtJoBdQk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=WHg4O4j0Ve4:uHOOtJoBdQk:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=WHg4O4j0Ve4:uHOOtJoBdQk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=WHg4O4j0Ve4:uHOOtJoBdQk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=WHg4O4j0Ve4:uHOOtJoBdQk:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/soyrex/design/~4/WHg4O4j0Ve4" height="1" width="1"/&gt;</description><pubDate>Sun, 18 Jan 2009 00:14:10 -0000</pubDate><guid isPermaLink="false">http://soyrex.com/blog/tt-1-digital-color-meter/</guid><feedburner:origLink>http://soyrex.com/blog/tt-1-digital-color-meter/</feedburner:origLink></item><item><title>I Hate Web Form Spambots</title><link>http://feedproxy.google.com/~r/soyrex/design/~3/VnXEgr-Gwvs/</link><description>&lt;span style="color: #666"&gt;Posted: Mon 05 Jan 2009 
| By: Alex Holt  
| &lt;a href="http://soyrex.com/blog/i-hate-web-form-spambots/"&gt;Read this post in context&lt;/a&gt;
&lt;/span&gt;
&lt;p&gt;I posted a message a while back about &lt;a href="http://soyrex.com/blog/akismet-django-stop-comment-spam/"&gt;spam in comments and Django&lt;/a&gt;. I don't agree with a lot of the opinions I held at the time, however one point I raised that I believe holds true is that the responsibility for spam provention should be the developers, not the user. In short, I hate and completely disagree with "captcha" style spam protection on forms. As a user I find sometimes, in attempt to make the image in unreadable by a computer that the text is so obscure I find it difficult to read myself. This isn't good enough. 
&lt;/p&gt;
&lt;p&gt;This point holds especially true for the project I am currently working on, which has only a simple email contact form. I do not want a valid, human client to have to tackle entering a captcha image or solving a math problem just o send the company a contact. So I set about reading about ways to catch spam on the server side. 
&lt;/p&gt;

&lt;h2&gt;My Solution&lt;/h2&gt;
&lt;p&gt;The solution that i've come up with marries two fairly old concepts together with some fairly simple logic (the success of this is untested, however I think it should be fairly effective - time will tell.. and i'll keep people posted here)
&lt;/p&gt;
&lt;p&gt;The two techniques I will be using are: timestamping and honeypots.
&lt;/p&gt;

&lt;h2&gt;So what are they?&lt;/h2&gt;

&lt;h4&gt;Timestamping&lt;/h4&gt;
&lt;p&gt;The concept of timestamping involves sending a timestamp to the form and storing it in a hidden field, effectively allowing us to know when the form was rendered. This is useful for two reasons:
&lt;/p&gt;
&lt;p&gt;1) We can check that the user spent a reasonable amount of time filling out hte form. The theory here is that the user is unlikely to instantly post the form, however a  spam bot that has scraped the data down will &lt;em&gt;very&lt;/em&gt; quickly be able to scrape out the form fields and post the page. So: for example in this current project, my contact form is asking for a name, email, subject and message. A human cant type these into a form in less than say 5-10 seconds, so when the form is submitted i can check the timestamp in the hidden field against the current time and thus reject a submission that is too rapid.
&lt;/p&gt;
&lt;p&gt;2) We can force the form to expire after say 1 hour, provide the user with a simple message that says something like "sorry, the form has expired.. please try again".
&lt;/p&gt;
&lt;p&gt;Obviously the too fast time would depend on the size of the form that you are requiring them to fillout. 
&lt;/p&gt;
&lt;p&gt;The secret here also is to NOT redirect to the form page, but to store the form values they have created into session, so that we can provide a link saying click here to re-submit the form, and explaining that the client needs to wait 10 seconds before sending the form. 
&lt;/p&gt;

&lt;h4&gt;Honeypots&lt;/h4&gt;
&lt;p&gt;Honeypots are used to trick spambot engines into telling us they are a spam bot. Basicallly the logic is as follows: a spambot tries to guess the values for the inputs in a form when it submits it. SO: if we use CSS to completely hide a honeypot text field, then the spambot is likely to try and guess a value for that field - then we assume that any submission with a value in that field is a bot, and display a message suggesting as much, if they are not a bot, we allow them to click a button to submit the form - this should in theory prevent a bot successfully submitting the form.
&lt;/p&gt;
&lt;p&gt;Time will tell how well these two techniques will work together to cut back on spam. If anyone is interested, i could probably tidy up the django code and release it as an app for people to play with... 
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=VnXEgr-Gwvs:rsi1NGbh8uc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=VnXEgr-Gwvs:rsi1NGbh8uc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=VnXEgr-Gwvs:rsi1NGbh8uc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=VnXEgr-Gwvs:rsi1NGbh8uc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=VnXEgr-Gwvs:rsi1NGbh8uc:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=VnXEgr-Gwvs:rsi1NGbh8uc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=VnXEgr-Gwvs:rsi1NGbh8uc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=VnXEgr-Gwvs:rsi1NGbh8uc:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/soyrex/design/~4/VnXEgr-Gwvs" height="1" width="1"/&gt;</description><pubDate>Tue, 06 Jan 2009 05:19:47 -0000</pubDate><guid isPermaLink="false">http://soyrex.com/blog/i-hate-web-form-spambots/</guid><feedburner:origLink>http://soyrex.com/blog/i-hate-web-form-spambots/</feedburner:origLink></item><item><title>The state of play..</title><link>http://feedproxy.google.com/~r/soyrex/design/~3/ErSeJgehIX0/</link><description>&lt;span style="color: #666"&gt;Posted: Fri 02 Jan 2009 
| By: Alex Holt  
| &lt;a href="http://soyrex.com/blog/state-play/"&gt;Read this post in context&lt;/a&gt;
&lt;/span&gt;
&lt;p&gt;So, after 2 years living and working freelance in Barcelona we've decided to move on and try something completely different. My girlfriend and I have packed our stuff, left Barcelona (a city that i miss already) and are on an extended working holiday until the end of January. From there, we are going to Honduras to complete our scuba divemasters course on the island of Roatan.
&lt;/p&gt;
&lt;p&gt;During the next 3-4 months, I will obviously not be taking any new projects (unless they are uber-interesting and slow-internet friendly), however the plan is not to be idle..
&lt;/p&gt;

&lt;h2&gt;So what will I be doing?&lt;/h2&gt;
&lt;p&gt;I really want to put some time and effort into personal projects, something I'm sure many of my fellow developers and designers can sympathise with - it just never happens when you've got client work. So with that problem in mind, I've saved enough cash to cover my time in Honduras, so that I can focus on what i want to do, instead of what i need to do. So hopefully there'll be something to show for it at the end of this time.
&lt;/p&gt;
&lt;p&gt;2008 was a year where I tried to complete personal projects as well as client work, and I REALLY pushed for allocating time weekly to working on them, however I am still left with many half finished web sites and other works. On the flip side, I did complete &lt;a href="http://monitter.com"&gt;monitter.com&lt;/a&gt; - a live twitter search engine and also &lt;a href="http://trekkingnepaltours.com"&gt;Nepal Trek Tours&lt;/a&gt; - a trekking business website for a friend in Nepal - both of which have been quite successful.
&lt;/p&gt;

&lt;h2&gt;What will I be working on?&lt;/h2&gt;
&lt;p&gt;I have a couple of new website projects in the pipeline, some gimmicky and some less so. So as they come to fruition (hopefully) you will be the second to know (after twitter: &lt;a href="http://twitter.com/soyrex"&gt;@soyrex&lt;/a&gt;)
&lt;/p&gt;
&lt;p&gt;Also, I am 95% finished with a complete overhaul of &lt;a href="http://monitter.com"&gt;monitter.com&lt;/a&gt; that will support moving columns and logins for tweet bookmarking. Again, once this is complete I'll make a post here to let people know - also follow &lt;a href="http://twitter.com/monitter"&gt;@monitter&lt;/a&gt; on twitter for updates and info.
&lt;/p&gt;
&lt;p&gt;I would like to redevelop this site, to further separate my blog from my portfolio work, since I feel that in the past year the blog has become more of an interest blog than an engine for me to win work. I no longer seek work (it seems to find me ;) ) - which is a lovely place to be at the moment.
&lt;/p&gt;
&lt;p&gt;So, enough rambling.. happy new year everyone.
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=ErSeJgehIX0:7M50ghRbSsY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=ErSeJgehIX0:7M50ghRbSsY:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=ErSeJgehIX0:7M50ghRbSsY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=ErSeJgehIX0:7M50ghRbSsY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=ErSeJgehIX0:7M50ghRbSsY:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=ErSeJgehIX0:7M50ghRbSsY:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=ErSeJgehIX0:7M50ghRbSsY:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=ErSeJgehIX0:7M50ghRbSsY:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/soyrex/design/~4/ErSeJgehIX0" height="1" width="1"/&gt;</description><pubDate>Fri, 02 Jan 2009 18:58:40 -0000</pubDate><guid isPermaLink="false">http://soyrex.com/blog/state-play/</guid><feedburner:origLink>http://soyrex.com/blog/state-play/</feedburner:origLink></item><item><title>Coda Plugin: Html Word Counter</title><link>http://feedproxy.google.com/~r/soyrex/design/~3/xUYTOZ3sVPk/</link><description>&lt;span style="color: #666"&gt;Posted: Thu 13 Nov 2008 
| By: Alex Holt  
| &lt;a href="http://soyrex.com/blog/coda-16-plugin-support/"&gt;Read this post in context&lt;/a&gt;
&lt;/span&gt;
&lt;p&gt;&lt;strong&gt; Updated! Version 2 supports reading thousands in correct english.&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt; &lt;a href="http://soyrex.com/sitemedia/HtmlWordCount2.zip"&gt;Download the plugin here - 8.5Kb&lt;/a&gt;&lt;br /&gt;

&lt;/p&gt;
&lt;p&gt;So Coda 1.6 has been released. The major change appears to be the addition of a plugin system for adding functionality. Basically this allows developers to write small scripts that manipulate text from Coda. These plugins are then displayed inside Coda in the Plug-ins menu (or with keyboard shortcuts), so that they can be called easily.
&lt;/p&gt;
&lt;p&gt;Now, since i spend half my life in Coda, i wanted to play around with this and see if there was anything i could add to the community. Problem i found was, i dont really have many problems with Coda's interface - it already does pretty much everything i want. BUT.. while writing an &lt;a href="http://www.smashingmagazine.com/2008/09/16/jquery-examples-and-best-practices/"&gt;article for Smashing Magazine&lt;/a&gt; (which was required in HTML), i noticed that i didn't have a good way to count the words in my article (since it was in HTML - Coda didn't have a word count at all). Now, the whole beauty of Coda is in its all-in-one interface, so it kind of annoyed me that i couldn't get a word count for my article without either opening it in some other program, or copying the content into my terminal and using wc.
&lt;/p&gt;
&lt;p&gt;Anyways, in order to flex my proverbial developer muscles a little and play with the Coda plugin interface, i built a simple plugin that will strip HTML and count the words in a document - it's simple (like super-uber-simple).. but it does the trick.. and i figure there might be someone out there who might appreciate it. Basically, it strips the HTML tags out and then counts the words and then uses the OSX say command to read the word count out audibly - it supports either a selection block or the full document.
&lt;/p&gt;
&lt;p&gt;&lt;a href="http://soyrex.com/sitemedia/HtmlWordCount2.zip"&gt;Download the plugin here - 8.5Kb&lt;/a&gt;&lt;br /&gt;
Edit: now supports thousands properly.
&lt;/p&gt;
&lt;p&gt;Please leave a comment too :) 
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=xUYTOZ3sVPk:GbHucw7VbQA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=xUYTOZ3sVPk:GbHucw7VbQA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=xUYTOZ3sVPk:GbHucw7VbQA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=xUYTOZ3sVPk:GbHucw7VbQA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=xUYTOZ3sVPk:GbHucw7VbQA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=xUYTOZ3sVPk:GbHucw7VbQA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=xUYTOZ3sVPk:GbHucw7VbQA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=xUYTOZ3sVPk:GbHucw7VbQA:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/soyrex/design/~4/xUYTOZ3sVPk" height="1" width="1"/&gt;</description><pubDate>Thu, 13 Nov 2008 07:32:20 -0000</pubDate><guid isPermaLink="false">http://soyrex.com/blog/coda-16-plugin-support/</guid><feedburner:origLink>http://soyrex.com/blog/coda-16-plugin-support/</feedburner:origLink></item><item><title>Sí! Se puede! </title><link>http://feedproxy.google.com/~r/soyrex/design/~3/lOcYCBHbv_E/</link><description>&lt;span style="color: #666"&gt;Posted: Wed 05 Nov 2008 
| By: Alex Holt  
| &lt;a href="http://soyrex.com/blog/si-se-puede/"&gt;Read this post in context&lt;/a&gt;
&lt;/span&gt;
&lt;p&gt;Disclaimer: a break from my usual web oriented  ramblings to give my 2cents regarding the US election..
&lt;/p&gt;
&lt;p&gt;For a long time leading up to the most recent presidential elections in the US I tried my utmost to avoid even having an opinion... I can't vote in their election, I can't change it - so I resigned myself to trying to stay emotionally detached from it. The best way I could think of to achieve this was to NOT read about it, nor watch it.
&lt;/p&gt;
&lt;p&gt;Two things brought me around to following the elections: 1) Obama's super effective rhetoric coupled with 2) an overwhelming repulsion that someone as absurd as Sarah Palin had even a snowflakes chance in hell of being anywhere near a decision making position in the White House. These two factors convinced me to follow the election and as expected, I became somewhat emotionally attached to the idea of Obama being president. 
&lt;/p&gt;
&lt;p&gt;So, let's just say that waking up this morning (on my second last day in Barcelona) was a delight, due completely to the success of the Obama campaign. In a world like today's world, where there is so much going wrong, it is heartening to see a campaign focussed on change (and one might argue hope) successfully effecting this kind of landslide victory. 
&lt;/p&gt;
&lt;p&gt;To quote Obama from his acceptance speech, "this victory is not the change we seek" - Here's to hoping that over the next four years he really does effect some serious change in the policies that the US has perpetrated throughout the world &lt;strong&gt;and&lt;/strong&gt; in their own backyard. 
&lt;/p&gt;
&lt;p&gt;Sí! Se puede! Ahora esperamos que con el poder vengan los cambios.
&lt;/p&gt;
&lt;p&gt;Link bait:
&lt;/p&gt;
&lt;ul&gt;
 &lt;li&gt;
     &lt;a href="http://www.huffingtonpost.com/2008/11/05/kenya-declares-wednesday_n_141270.html"&gt;Celebrations in Kenya: great photo slideshow&lt;/a&gt;
 &lt;/li&gt;

 &lt;li&gt;
     &lt;a href="http://cosmos.bcst.yahoo.com/up/player/popup/?rn=3906861&amp;amp;cl=10539754&amp;amp;ch=4226716&amp;amp;src=news"&gt;Obama's acceptance speech&lt;/a&gt;
 &lt;/li&gt;

 &lt;li&gt;
     &lt;a href="http://monitter.com/?obama&amp;amp;mccain&amp;amp;exit%20poll&amp;amp;landslide"&gt;Monitter: Obama, Mccain, Exit Poll and Landslide&lt;/a&gt;
 &lt;/li&gt;
&lt;/ul&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=lOcYCBHbv_E:O4SjG4m2P8w:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=lOcYCBHbv_E:O4SjG4m2P8w:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=lOcYCBHbv_E:O4SjG4m2P8w:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=lOcYCBHbv_E:O4SjG4m2P8w:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=lOcYCBHbv_E:O4SjG4m2P8w:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=lOcYCBHbv_E:O4SjG4m2P8w:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=lOcYCBHbv_E:O4SjG4m2P8w:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=lOcYCBHbv_E:O4SjG4m2P8w:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/soyrex/design/~4/lOcYCBHbv_E" height="1" width="1"/&gt;</description><pubDate>Wed, 05 Nov 2008 15:49:32 -0000</pubDate><guid isPermaLink="false">http://soyrex.com/blog/si-se-puede/</guid><feedburner:origLink>http://soyrex.com/blog/si-se-puede/</feedburner:origLink></item><item><title>iPhone Web Apps: monitter.com</title><link>http://feedproxy.google.com/~r/soyrex/design/~3/oQvr35g67WQ/</link><description>&lt;span style="color: #666"&gt;Posted: Tue 21 Oct 2008 
| By: Alex Holt  
| &lt;a href="http://soyrex.com/blog/iphone-web-apps-monittercom/"&gt;Read this post in context&lt;/a&gt;
&lt;/span&gt;
&lt;p&gt;Ok. so &lt;a href="http://monitter.com"&gt;monitter.com&lt;/a&gt;  has received a few incremental updates since I first wrote it (&lt;a href="http://soyrex.com/blog/jquery-twitter-night-coding/"&gt;see previous post&lt;/a&gt;). 
&lt;/p&gt;
&lt;p&gt;The monitter site gets a pretty steady stream of visitors, which is somewhat gratifying - although it makes no money (just like it's counterpart: twitter). However, it has served as a great engine for me to test and experiment (without those experiments being totally pointless).
&lt;/p&gt;

&lt;h2&gt;So what's new with monitter?&lt;/h2&gt;
&lt;p&gt;As the post title suggests, I've created an iPhone web app for monitter. It's in very early alpha. The motivation behind this? Firstly, I want to build a native iPhone application and i figured that the best area to start in is one that I already know well - in this case, live twitter monitoring. However since I have almost no free time at the moment, I decided to build a web app first, to try and gauge whether people would be interested in a dedicated twitter monitor for their iPhones.
&lt;/p&gt;
&lt;p&gt;Also: through Gruber, i learned that the latest revision of the iPhone software supports fullscreen, chromeless web apps. Which means that on a 2.1 iPhone, the new monitter web app will in fact feel like a native application.
&lt;/p&gt;
&lt;p&gt;At the moment, the app doesn't even support all the features of the monitter.com site. You can't add columns (in fact you only get one). It doesn't currently remember your searches (the cookies are turned off - although I'm working re-activating this now.. so it might already work by the time you are reading this). I'm sure there are also a multitude of other bugs, which is why I'm calling it alpha testing.. so please, if you're an iphone user, give it a whirl. 
&lt;/p&gt;
&lt;p&gt;Just type in: http://monitter.com/iphoneapp/ into Mobile Safari and then use the + button down the bottom to make it into a Web Clip on your home screen (this allows you to experiment with the chromeless application).
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=oQvr35g67WQ:0b3AACW0qh4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=oQvr35g67WQ:0b3AACW0qh4:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=oQvr35g67WQ:0b3AACW0qh4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=oQvr35g67WQ:0b3AACW0qh4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=oQvr35g67WQ:0b3AACW0qh4:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=oQvr35g67WQ:0b3AACW0qh4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=oQvr35g67WQ:0b3AACW0qh4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=oQvr35g67WQ:0b3AACW0qh4:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/soyrex/design/~4/oQvr35g67WQ" height="1" width="1"/&gt;</description><pubDate>Wed, 22 Oct 2008 00:47:27 -0000</pubDate><guid isPermaLink="false">http://soyrex.com/blog/iphone-web-apps-monittercom/</guid><feedburner:origLink>http://soyrex.com/blog/iphone-web-apps-monittercom/</feedburner:origLink></item><item><title> Django, Nginx + Memcached </title><link>http://feedproxy.google.com/~r/soyrex/design/~3/h5GdlgMBnvY/</link><description>&lt;span style="color: #666"&gt;Posted: Wed 27 Aug 2008 
| By: Alex Holt  
| &lt;a href="http://soyrex.com/blog/django-nginx-and-memcached/"&gt;Read this post in context&lt;/a&gt;
&lt;/span&gt;
&lt;p&gt;Ok, so Django has a pretty good caching engine build right into the framework, right? So why would i be trying to implement a caching solution for my Django project? I'm a masochist. that's why.
&lt;/p&gt;
&lt;p&gt;My sites are hosted on a VPS (with very sparse memory allocation), so i'm looking to minimise memory usage wherever possible. I also had the joy of watching my Django FCGIs for http://the-hive-mind.com get completely annihilated by metafilter.org a few weeks ago - i think it stood up to the first 200-300 requests.. then completely died.
&lt;/p&gt;
&lt;p&gt;Anyway, I have just &lt;a href="http://trekkingnepaltours.com"&gt;launched a website&lt;/a&gt; for a friend in Nepal, who runs a trekking business (he comes highly recommended if you ever want to go hiking in that region). Basically, I decided to try and load test the Django instances on the site, to see how much traffic it could handle... i downloaded and installed siege.. which (as the name suggests) lays siege to your web server.
&lt;/p&gt;
&lt;p&gt;My out of the box Django FCGI being called by a &lt;a href="http://nginx.net"&gt;Nginx&lt;/a&gt; instance was only capable of reliably handling up to about 10 concurrent connections before it started dropping requests.. not really acceptable (caching, at this point.. was completely turned off).
&lt;/p&gt;
&lt;p&gt;So I set about sorting out caching. I read the &lt;a href="http://docs.djangoproject.com"&gt;Django documentation&lt;/a&gt;.. and quickly decided that the built in caching wasn't quite to my liking. I already knew a little about memcached, and wanted to use it to cache my generated responses, so the fact that Django supported it was nice. However the idea of using a the Django cache middleware doesn't really cut it. Nginx supports memcached.. so why would i want to fire the request off to my (inherently bulky and inneficient) python FCGI instance? just to use python's undoubtedly slower memcached library to return the cached content? I wouldn't.
&lt;/p&gt;
&lt;p&gt;The solution I've come up with is somewhat simplistic, however it DOES solve my immediate problem... and it's done wonders for the server's load capacity.
&lt;/p&gt;

&lt;h2&gt;The solution : Django creates the cache object, but Nginx retrieves it.&lt;/h2&gt;
&lt;p&gt;The Django caching middleware is halfway to the perfect model, it correctly creates cached objects, however it uses a strance combination of . separated python words, the URI and a md5 hexdigest. That all seems like a little much to expect Nginx to replicate (remembering that my goal here is to avoid hitting the FCGI at all for cached content).
&lt;/p&gt;
&lt;p&gt;So after some digging and background, I decided it would be fun to write a simple MiddleWare for Django that would allow me to cache out my content's responses with nice, Nginx friendly keys, so I could then implement my cache override directly in my Nginx config.
&lt;/p&gt;

&lt;h4&gt;Step 1: Creating the Cache Objects: MiddleWare&lt;/h4&gt;
&lt;p&gt;This is really very simple. I'd never written Django Middleware before, however it was surprisingly simple. A MiddleWare is just a Python object that implements any of a series of methods. My NginxMiddleWare looks like this:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from django.core.cache import cache
import re
import settings

class NginxMemCacheMiddleWare:
    def process_response(self, request, response):
        cacheIt = True
        theUrl = request.get_full_path()

        # if it's a GET then store it in the cache:
        if request.method != 'GET':
            cacheIt = False

        # loop on our CACHE_INGORE_REGEXPS and ignore
        # certain urls.
        for exp in settings.CACHE_IGNORE_REGEXPS:
            if re.match(exp,theUrl):
                cacheIt = False

        if cacheIt:
            key = '%s-%s' % (settings.CACHE_KEY_PREFIX,theUrl)
            cache.set(key,response.content)     


        return response
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We also need to install our new MiddleWare into the site. I saved the above class definition into a file called NginxMiddleWare.py and installed it into my site-packages.. i intend to implement this caching scheme on my other Django sites (including this blog). So in my settings.py I add 'NginxMiddleWare.NginxMemCacheMiddleWare' to the MIDDLEWARE_CLASSES. 
&lt;/p&gt;
&lt;p&gt;Also in the Django projects settings file we add the following:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CACHE_BACKEND = 'memcached://127.0.0.1:11211/'
CACHE_KEY_PREFIX = '/your-site-name'
CACHE_IGNORE_REGEXPS = (
    r'/admin.*',
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Firstly we are telling Django to use memcached (I'm assumign you already have memcached set up - go here if you don't).
&lt;/p&gt;
&lt;p&gt;I have defined two new settings variables, CACHE_KEY_PREFIX and CACHE_IGNORE_REGEXPS. These allow me to control the caching. CACHE_KEY_PREFIX allows me to store multiple sites in the same memcached.. but creating a unique string key. And CACHE_IGNORE_REGEXPS allows me to define a set of regular expression URLS that I DO NOT want to cache - like the admin site.
&lt;/p&gt;

&lt;h4&gt;Step 2: Nginx Configuration&lt;/h4&gt;
&lt;p&gt;The configuration of Nginx was a bit fiddly. I really wanted my Django project to continue to run in exactly the same way as it was previously - ie no silly fake URL prefixes or other cruft to confuse my urls.py..
&lt;/p&gt;
&lt;p&gt;So I needed to get Nginx to firstly serve my Django pages off a fake, internal server, like so:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;server {
        listen 9004;
        location / {

                # host and port to fastcgi server
                # @fastcgi_pass unix:/var/www/trekkingnepaltours.com/django.sock;
                fastcgi_pass 127.0.0.1:8004;
                fastcgi_param PATH_INFO $fastcgi_script_name;
                fastcgi_param REQUEST_METHOD $request_method;
                fastcgi_param QUERY_STRING $query_string;
                fastcgi_param CONTENT_TYPE $content_type;
                fastcgi_param CONTENT_LENGTH $content_length;
                fastcgi_pass_header Authorization;
                fastcgi_intercept_errors off;
                   include /etc/nginx/fastcgi_params;
                }

}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Pick a high port, then configure your FCGI however you like it to be configured, above is what I use.. but I'm assuming if you've read this far that you know enough to configure your FCGI under Nginx.
&lt;/p&gt;
&lt;p&gt;Basically this creates us another server that we can talk to, allowing us to use Nginx like a proxy to server our Django pages. The logic is something like:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;check if url is cached
if url IS cached then
    return the cached response
else
    proxy the connection to our django server
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So the guts of the logic for hte Nginx config are as follows:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;   location / {
            if ($request_method = POST) {
                    proxy_pass http://localhost:9004;
                    break;
            }
            default_type  "text/html; charset=utf-8";
            set $memcached_key "/your-site-name-$uri";
            memcached_pass localhost:11211;
            error_page 404 502 = /django;
    }

    location = /django  {
            proxy_pass http://localhost:9004;
            break;
    }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Before this definition, i have a whole bunch of locations set to handle my static content, so it never reaches this stage. The / location first checks if it's a POST request, if so it will proxy the request off to django directly, we never cache POSTs. Then if we get past that point, we set the default type of our response to html and utf8. Then we set $memcached_key to the string that we used in our Django settings.py plus a dash plus the $uri from nginx. Next we pass off to memcached locally to check for the cached object, if it exists memcached will return it, otherwise we get an error. Errors are handled by our error_page directive, which farms them off to a virtual location called /django, which again sends the request to the internal Django instance.
&lt;/p&gt;
&lt;p&gt;So, if there is no cached object, then Nginx will get Django to render the page, and the MiddleWare we defined above will save off our cached objects with the correct keys.
&lt;/p&gt;

&lt;h2&gt;But Wait - what if I change data in the DB?&lt;/h2&gt;
&lt;p&gt;Of course, Django is a Content Management Framework and i make extensive use of the provided admin system.. so when I add a new trek to http://trekkingnepaltours.com i want the site to update itself. To achieve this we override the save methods on the relevant DB models and get them to clear the cache.
&lt;/p&gt;
&lt;p&gt;I assume here that you use the standard Django convention of defining a get_absolute_url method on your models, so we just override the save function and call our django cache delete function on the correct cache key, to remove if from memcached. Below is the save method off my Photo model:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def save(self):
    theUrl = self.trek.get_absolute_url()
    key = '%s-%s' % (settings.CACHE_KEY_PREFIX,theUrl)
    cache.delete(key)

    key = '%s-/' % (settings.CACHE_KEY_PREFIX)
    cache.delete(key)

    super(Photo, self).save()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As you can see, I'm removing the cache for the Trek model that this photo is associated to (since that's where the actual page is) and also the cache for the home page, the photos often get rendered there too - obviously we can be as granular as we like in this save method, removing whatever we need to in order to update the site. We could probably even write some code to wipe the entire cache..
&lt;/p&gt;

&lt;h2&gt;The end result&lt;/h2&gt;
&lt;p&gt;Siege now shows the site successfully handling 2000 odd concurrent connections on a constant load for 1 minute... while hardly registering any memory usage at all on my VPS - problem solved.
&lt;/p&gt;

&lt;h2&gt;Disclaimer..&lt;/h2&gt;
&lt;p&gt;I know this is probably not the most elegant solution, however it has solved my problem for me. Having said that, if you have ANY comments about how this could be made better, please leave a comment... also if Django can already do this out of the box... someone smarter than me needs to tell me how ;) 
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=h5GdlgMBnvY:OtFpxcNlHK8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=h5GdlgMBnvY:OtFpxcNlHK8:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=h5GdlgMBnvY:OtFpxcNlHK8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=h5GdlgMBnvY:OtFpxcNlHK8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=h5GdlgMBnvY:OtFpxcNlHK8:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=h5GdlgMBnvY:OtFpxcNlHK8:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=h5GdlgMBnvY:OtFpxcNlHK8:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=h5GdlgMBnvY:OtFpxcNlHK8:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/soyrex/design/~4/h5GdlgMBnvY" height="1" width="1"/&gt;</description><pubDate>Wed, 27 Aug 2008 06:35:46 -0000</pubDate><guid isPermaLink="false">http://soyrex.com/blog/django-nginx-and-memcached/</guid><feedburner:origLink>http://soyrex.com/blog/django-nginx-and-memcached/</feedburner:origLink></item><item><title>Expanding your reach with Twitter..</title><link>http://feedproxy.google.com/~r/soyrex/design/~3/-yXd48heCRQ/</link><description>&lt;span style="color: #666"&gt;Posted: Tue 05 Aug 2008 
| By: Alex Holt  
| &lt;a href="http://soyrex.com/blog/passive-twitter-monitoring/"&gt;Read this post in context&lt;/a&gt;
&lt;/span&gt;
&lt;p&gt;There are two camps in the web world regarding microblogging tools like Twitter. Half of us think they're great the other half are still scratching their heads wondering what possible purpose these tools can serve.
&lt;/p&gt;
&lt;p&gt;Plenty of arguments have been presented to show how Twitter can serve as a viral marketing platform and networking tool. Recently, as most people will know, Twitter acquired Summize, a search engine that accessed Twitter posts by keyword searches. While Summize had been around for a while, its purchase by Twitter has served to bring it (and it's concept) into the mainstream.
&lt;/p&gt;

&lt;h2&gt;What has this done for Twitter?&lt;/h2&gt;
&lt;p&gt;It has brought Twitter out of the social networking domain and made it into an extremely efficient research tool.
&lt;/p&gt;
&lt;p&gt;However, even with search.twitter.com live, it isn't quite efficient enough a tool for us to monitor the Twitter world effectively. So how do we solve this problem? Luckily, like Twitter itself, the search.twitter.com service provides a very simplistic API - and we are starting to see a few mashup technologies emerging to utilise the APIs to monitor and track particular topics in real-time.
&lt;/p&gt;

&lt;h2&gt;So where are these tools and how should I use them?&lt;/h2&gt;
&lt;p&gt;This is by no means an exhaustive list of tools for helping you maximise your results from Twitter (in fact it's deliberately a &lt;em&gt;very&lt;/em&gt; short list).
&lt;/p&gt;

&lt;h2&gt;Third Party Tools&lt;/h2&gt;

&lt;h4&gt;&lt;a href="http://monitter.com"&gt;monitter.com&lt;/a&gt; - Real-Time, Live Twitter Monitoring&lt;/h4&gt;
&lt;p&gt;Monitter is a new player in the Twitter mashup world and it basically allows you to "monitter" tweets off the public timeline. You input 3 search terms into the monitter site, and it will monitor Twitter and match those particular terms and display them to you in a nice clean, live streaming interface online - the interface is offered in dark and light mode - nice touch!
&lt;/p&gt;
&lt;p&gt;The beauty of this is: you don't NEED a Twitter account, you can just hit the &lt;a href="http://monitter.com"&gt;monitter.com site&lt;/a&gt; and passively monitor what is going on on Twitter. If you are a Twitter user, monitter can help you find more people to follow - people who are tweeting about topics you are interested in..
&lt;/p&gt;

&lt;h4&gt;&lt;a href="http://tweetdeck.com"&gt;tweetdeck.com&lt;/a&gt; - Revolutionising Twitter Desktop Clients&lt;/h4&gt;
&lt;p&gt;Tweetdeck is an Adobe AIR client for Twitter that also includes search integration. You'll need a Twitter account, but if you have one, Tweetdeck is a great client because it will follow your normal Twitter friends, but also allow you to monitor for relevant keywords. 
&lt;/p&gt;
&lt;p&gt;Currently in BETA, Tweetdeck is as stable as any AIR application I have used, and has recently replaced Twhirl as my desktop Twitter client.
&lt;/p&gt;

&lt;h2&gt;Twitter Tools&lt;/h2&gt;

&lt;h4&gt;&lt;a href="http://blog.twitter.com/2007/09/tracking-twitter.html"&gt;Twitter Track&lt;/a&gt; - Allows you to track Twitter concepts&lt;/h4&gt;
&lt;p&gt;Twitter track works from you IM or phone and allows you to track keyword searches from Twitter and have them sent to your mobile device. Personally I don't use Twitter passively while I'm on the move, so this one is of less interest to me.. but check it out nonetheless.
&lt;/p&gt;

&lt;h4&gt;&lt;a href="http://search.twitter.com"&gt;search.twitter.com&lt;/a&gt; - The Twitter Search API Itself&lt;/h4&gt;
&lt;p&gt;Formerly known as Summize (until Twitter acquired them), the Twitter search API also offers a web interface that allows you to search the Twitter timeline for keywords (this is the driving force behind the tools above). This is a little less sophisticated than Tweetdeck or Monitter, however it does allow you to find relevant tweets. 
&lt;/p&gt;

&lt;h2&gt;So what does it all mean?&lt;/h2&gt;
&lt;p&gt;If you market a product, fire up a Twitter monitor and enter your product name into the search box.. is anyone tweeting about it? No? Start marketing socially.
&lt;/p&gt;
&lt;p&gt;Imagine that you're writing an article about a particular topic.. type in relevant keywords and see if anyone is talking about it. I use monitter.com as a tool for my research on a fairly regular basis - in fact, this week it has been sitting perpetually in it's own Space on my desktop.
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=-yXd48heCRQ:HB4OCNV0-4Q:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=-yXd48heCRQ:HB4OCNV0-4Q:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=-yXd48heCRQ:HB4OCNV0-4Q:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=-yXd48heCRQ:HB4OCNV0-4Q:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=-yXd48heCRQ:HB4OCNV0-4Q:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=-yXd48heCRQ:HB4OCNV0-4Q:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=-yXd48heCRQ:HB4OCNV0-4Q:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=-yXd48heCRQ:HB4OCNV0-4Q:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/soyrex/design/~4/-yXd48heCRQ" height="1" width="1"/&gt;</description><pubDate>Tue, 05 Aug 2008 05:07:46 -0000</pubDate><guid isPermaLink="false">http://soyrex.com/blog/passive-twitter-monitoring/</guid><feedburner:origLink>http://soyrex.com/blog/passive-twitter-monitoring/</feedburner:origLink></item><item><title>jQuery + Twitter + a night of coding</title><link>http://feedproxy.google.com/~r/soyrex/design/~3/wX2vcTrcQtA/</link><description>&lt;span style="color: #666"&gt;Posted: Mon 28 Jul 2008 
| By: Alex Holt  
| &lt;a href="http://soyrex.com/blog/jquery-twitter-night-coding/"&gt;Read this post in context&lt;/a&gt;
&lt;/span&gt;
&lt;p&gt;I've always used prototype and scriptaculous to do JS stuff in the past. However I've been hearing a lot of good things about jQuery and i'd noticed that sites i'd seen using jQuery seemed to have much smoother animation etc.
&lt;/p&gt;
&lt;p&gt;So in the spirit of keeping an open mind (and continuing to learn.. something I don't find myself doing that often anymore) i set about building a simple JS based web app to test how jQuery would suit my programming etc..
&lt;/p&gt;
&lt;p&gt;After about 4 minutes of brainstorming, I found myself getting annoyed, and switched to my &lt;a href="http://tweetdeck.com"&gt;Tweetdeck&lt;/a&gt; to distract myself. In a semi-relevant aside, i have to say, tweetdeck makes my twitter usage about 100x as useful.. plug! 
&lt;/p&gt;
&lt;p&gt;So i decided it would be cool to try knocking upa simple Ajax application that emulated Tweetdeck's searching features - using the search.twitter.com api (previously summize).
&lt;/p&gt;
&lt;p&gt;So i downloaded jQuery, and set up 3 simple div based columns to hold the tweets i was going to be grabbing. The beautiful thing i discovered with jQuery is it can cross domain ajax requests, so i can talk directly to the search.twitter.com api without having to write a proxy script on my server - cool!
&lt;/p&gt;
&lt;p&gt;The twitter search API has an option to return JSON data, which is really great for building an app like this, since we end up receiving the data and handling it all in JS with no decoding necessary.. too easy.
&lt;/p&gt;
&lt;p&gt;So, we have our 3 divs and at this point I started to get my hands dirty in jQuery (i'm not a complete beginner, but i never really used it extensively.. so i was keen to see how it was compared to prototype). Turns out, within 10 minutes of starting, i had fallen in love with jQuery's selectors, they are so much simpler and more flexible than prototype.. coupled with the style of programming that jQuery promotes, using it's each() method to map responses to all the results of a selection, it turns out that writing relatively complex JS applications is a piece of cake.
&lt;/p&gt;
&lt;p&gt;Below is the code listing for the guts of the application it is the response to the Ajax call, it receives the JSON response from the twitter search api and turns each tweet into a div and prepends it into the relevant column of data.
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$.getJSON(url, function(json)
{

    // clean up old ones:
    $('#col'+x+' div.tweet:gt(10)').each(function(){$(this).fadeOut('slow')});

    $(json.results).reverse().each(function()
    {
        if($('#col'+x+' .tweets #tw'+this.id).length == 0)
        {

            var divstr = '&amp;lt;div id="tw'+this.id+'" class="tweet"&amp;gt;'+\
            '&amp;lt;img width="48" height="48" src="'+this.profile_image_url+'" &amp;gt;'+\
            '&amp;lt;p class="text"&amp;gt;'+this.text.linkify().linkuser().linktag()+\
            ' -&amp;amp;nbsp;&amp;lt;b&amp;gt;&amp;lt;a href="http://twitter.com/'+this.from_user+'"&amp;gt;'+\
            this.from_user+'&amp;lt;/a&amp;gt;&amp;lt;/b&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;';

            window.twitter['last_id'+x] = this.id;

            $('#col'+x+' .tweets').prepend(divstr);
            $('#col'+x+' .tweets #tw'+this.id).hide();
            $('#col'+x+' .tweets #tw'+this.id+' img').hide();
            $('#col'+x+' .tweets #tw'+this.id+' img').fadeIn(4000);
            $('#col'+x+' .tweets #tw'+this.id).fadeIn('slow');

        }
    });
    setTimeout('fetch_tweets('+x+')', 3000);
});
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There are a few more tricks in here, like linkify and linkuser, which have been prototyped into JS so that i can convert the links for twitter on the fly (if you're really interested, grab the JS source off the site and have a poke around).
&lt;/p&gt;
&lt;p&gt;So how did jQuery compare to Prototype? Once i got over my tendency to want to write Prototype JS into my files, i've actually come to prefer jQuery I find myself writing much prettier, more elegant code, without the iteration and procedural work I usually do in Prototype. jQuery is a definite winner, and i will slowly be moving all my sites over from using prototype to jQuery.
&lt;/p&gt;
&lt;p&gt;So i now had a single working HTML file that produced 3 twitter streams in ajax.. what should i do with this useless piece of concept code? I know, turn it into a site.. so at 4am I bought &lt;a href="http://monitter.com"&gt;http://monitter.com&lt;/a&gt; as a domain to host my twitter monitor (if you can't get the play on words, give up now).. Fired up photoshop and created a simple logo, favicon and a couple of simple textures.. tidied up the CSS a bit, added in some update-your-browser.com ie6 messages and uploaded the files.. voila Monitter is born... check it out: &lt;a href="http://monitter.com"&gt;http://monitter.com&lt;/a&gt; - tell your friends! be sure to give me feedback in the comments here.. and keep smiling.
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=wX2vcTrcQtA:ce77gw9e6rA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=wX2vcTrcQtA:ce77gw9e6rA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=wX2vcTrcQtA:ce77gw9e6rA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=wX2vcTrcQtA:ce77gw9e6rA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=wX2vcTrcQtA:ce77gw9e6rA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=wX2vcTrcQtA:ce77gw9e6rA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?i=wX2vcTrcQtA:ce77gw9e6rA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/soyrex/design?a=wX2vcTrcQtA:ce77gw9e6rA:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/soyrex/design?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/soyrex/design/~4/wX2vcTrcQtA" height="1" width="1"/&gt;</description><pubDate>Mon, 28 Jul 2008 08:05:21 -0000</pubDate><guid isPermaLink="false">http://soyrex.com/blog/jquery-twitter-night-coding/</guid><feedburner:origLink>http://soyrex.com/blog/jquery-twitter-night-coding/</feedburner:origLink></item></channel></rss>
