<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/rss2full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><rss xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="0.92"><channel><title>The Watchmaker Project</title>
<link>http://www.thewatchmakerproject.com/</link>

<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/thewatchmakerproject" type="application/rss+xml" /><feedburner:browserFriendly>This is an XML content feed. It is intended to be viewed in a newsreader or syndicated to another site, subject to copyright and fair use.</feedburner:browserFriendly><item><title>iPhone Apps - what's the point?</title>
<description>&lt;p&gt;Maybe I’m just dumb, but I really can’t see the point of many of the new applications available to download through Apple’s new App Store. If your app needs to be online to work, and doesn’t do anything clever with Core Animation or similar—why not just run it as a web app?&lt;/p&gt;
	&lt;p&gt;Why do I want to run NetNewsWire as an application (and tie up the rest of the iPhone) when it’s doing &lt;em&gt;exactly&lt;/em&gt; the same thing as the mobile NewsGator web app?&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=dCYoqJ"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=dCYoqJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=nZG5rJ"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=nZG5rJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/thewatchmakerproject/~4/332752714" height="1" width="1"/&gt;</description>
<link>http://www.thewatchmakerproject.com/journal/472/iphone-apps-whats-the-point</link><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=thewatchmakerproject&amp;itemurl=http%3A%2F%2Fwww.thewatchmakerproject.com%2Fjournal%2F472%2Fiphone-apps-whats-the-point</feedburner:awareness></item>
<item><title>Adding it up with AddItUp</title>
<description>&lt;p&gt;Non-Twitter followers might be interested to know that I’ve just launched &lt;a href="http://letsadditup.com/"&gt;a new site&lt;/a&gt; and &lt;a href="http://blog.letsadditup.com/"&gt;accompanying blog&lt;/a&gt; to discuss and track progress on a web application I’m building.&lt;/p&gt;
	&lt;p&gt;Entirely coincidentally, Drew launched &lt;a href="http://projectdogfood.wordpress.com/"&gt;Project Dog Food&lt;/a&gt; at almost exactly the same time—it will be interesting to compare our respective progress as the summer goes on.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=dtBjXJ"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=dtBjXJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=9UysfJ"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=9UysfJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/thewatchmakerproject/~4/328891393" height="1" width="1"/&gt;</description>
<link>http://www.thewatchmakerproject.com/journal/471/adding-it-up-with-additup</link><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=thewatchmakerproject&amp;itemurl=http%3A%2F%2Fwww.thewatchmakerproject.com%2Fjournal%2F471%2Fadding-it-up-with-additup</feedburner:awareness></item>
<item><title>Refresh Cambridge July - PPC management</title>
<description>&lt;p&gt;&lt;a href="http://www.refreshcambridge.org/"&gt;Refresh Cambridge&lt;/a&gt; (which by my reckoning is entering its third year right about now) met last week for a discussion on Pay-Per-Click (PPC) management, led by Rob from local agency &lt;a href="http://www.dbpractice.com/"&gt;db|design&lt;/a&gt;.&lt;/p&gt;
	&lt;p&gt;Due to the varying levels of experience in the audience, the Q&amp;A covered everything from the basics of how PPC works through to using Google’s Adwords and Analytics tools together to monitor, tweak, and improve your ad performance.&lt;/p&gt;
	&lt;p&gt;I wasn’t taking any notes, but here (to the best of my recollection) are some of the areas we talked about:&lt;/p&gt;
	&lt;ul&gt;
		&lt;li&gt;The simplest definition of Pay-Per-Click is that it is paying to have your advert show up at the top or on the right of Google’s search results pages. There are other search companies that operate PPC, but for the amount of effort needed to gain the small amount of traffic they deliver it’s usually better to just concentrate on Google.&lt;/li&gt;
		&lt;li&gt;Ad spaces are ‘sold’ in an auction system—advertisers bid for spots, and the amount you are willing to pay determines where in the sponsored results your ad will appear.&lt;/li&gt;
		&lt;li&gt;There are benefits to appearing in the first sponsored result, even if you also show up in the regular (“organic”) listings as well.&lt;/li&gt;
		&lt;li&gt;The best position in which to appear is around the fourth or fifth on the right-hand side of search pages. (YMMV)&lt;/li&gt;
		&lt;li&gt;The biggest mistake made by beginners is not having enough keywords. You should have a few thousand at least.&lt;/li&gt;
		&lt;li&gt;Once your campaign is running, you can see which keyword combinations perform best, and tweak your bids or keywords correspondingly.&lt;/li&gt;
		&lt;li&gt;By using &lt;a href="http://analytics.google.com/"&gt;Analytics&lt;/a&gt; you can see the performance of your Adword campaigns/keywords, allowing you to make decisions based on conversion as well as the number of clicks.&lt;/li&gt;
	&lt;/ul&gt;
	&lt;p&gt;Rob also shared a little trick with us. There is the option to set a daily limit on your ad spend within Adwords, but setting this to a sensible limit (e.g. you have a £100 monthly budget, so you set a daily budget of £3) will make Google severely restrict how many times your ads appear. Rob recommended setting the daily limit to an extremely large figure—say £10,000—so that your ads are shown much more frequently; you can control your actual spend by manipulating the maximum bids on your keywords.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=NinkPJ"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=NinkPJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=Q1fNhJ"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=Q1fNhJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/thewatchmakerproject/~4/327994635" height="1" width="1"/&gt;</description>
<link>http://www.thewatchmakerproject.com/journal/470/refresh-cambridge-july-ppc-management</link><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=thewatchmakerproject&amp;itemurl=http%3A%2F%2Fwww.thewatchmakerproject.com%2Fjournal%2F470%2Frefresh-cambridge-july-ppc-management</feedburner:awareness></item>
<item><title>How To Make An IP-To-Country Tool With PHP and MySQL</title>
<description>&lt;p&gt;When it comes to creating web applications, there is no guarantee where your audience will hail from. You might be in sunny California, but in today’s global community it is almost certain that an English-language application will attract visitors from Canada, the UK, Australia, and probably many other countries as well.&lt;/p&gt;
	&lt;p&gt;With that in mind, it would be nice to offer your users location-sensitive content. This is true whether your app is built around country-specific features (a shopping site, for example) or simply for pre-filling the country and timezone dropdowns on your registration form.&lt;/p&gt;
	&lt;p&gt;In this tutorial, we will create a database that allows us to map an IP address to a country, and use that information to serve up location-specific content.&lt;/p&gt;
	&lt;h2&gt;Creating the database&lt;/h2&gt;
	&lt;p&gt;Your database structure will depend, in part, on the data you intend to use to populate it. I am using the &lt;a href="http://software77.net/cgi-bin/ip-country/geo-ip.pl"&gt;free IP to Country database from Webnet77&lt;/a&gt; so my structure is based on that file, but most (if not all) ip-to-country datasets contain the following fields:&lt;/p&gt;
	&lt;ul&gt;
		&lt;li&gt;A lower numeric bound&lt;/li&gt;
		&lt;li&gt;An upper numeric bound&lt;/li&gt;
		&lt;li&gt;The registry in charge of that range of IPs&lt;/li&gt;
		&lt;li&gt;The date the IP range was last updated&lt;/li&gt;
		&lt;li&gt;A two-character code for the country&lt;/li&gt;
		&lt;li&gt;A three-character code for the country&lt;/li&gt;
		&lt;li&gt;The full name of the country&lt;/li&gt;
	&lt;/ul&gt;
	&lt;p&gt;In your chosen MySQL database, create the table, mapping fields to data columns in the order in which they appear:&lt;/p&gt;
 &lt;ol class="code"&gt;
&lt;li&gt;&lt;code&gt;CREATE TABLE `iptocountry` (&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;  `lower_bound` int(11) unsigned NOT NULL default '0',&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;  `upper_bound` int(11) unsigned NOT NULL default '0',&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;  `owner` varchar(20) NOT NULL default '',&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;  `last_updated` int(11) default NULL,&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;  `two_char_code` char(2) NOT NULL default '',&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;  `three_char_code` char(3) NOT NULL default '',&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;  `country` varchar(100) NOT NULL default ''&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;);&lt;/code&gt;&lt;/li&gt;

&lt;/ol&gt;

	&lt;h3&gt;Importing the data&lt;/h3&gt;
	&lt;p&gt;The raw data is in the form of a 6MB .csv file containing over 80,000 lines of data. What we will do is upload it to our site and create a PHP script to read the file into the database, one line at a time.&lt;/p&gt;
	&lt;p&gt;With such a large dataset, it’s a good idea to spit out regular status messages to make sure our script is behaving—it’s better than waiting for some sort of response and not being sure whether it’s worked or not. Normally, PHP will only write content to the page when the entire script has finished, but by using the &lt;a href="http://www.php.net/flush"&gt;flush()&lt;/a&gt; function we can force the output buffer to print any output line-by-line. I use a handy wrapper function to accomplish this:&lt;/p&gt;
 &lt;ol class="code"&gt;
&lt;li&gt;&lt;code&gt;function status($str)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;echo $str . '&lt;br&gt;';&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flush();&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;}&lt;/code&gt;&lt;/li&gt;

&lt;/ol&gt;

	&lt;p&gt;Onto the script. We’ll upload it to the same folder as the .csv data file. First we need to connect to our MySQL database:&lt;/p&gt;
 &lt;ol class="code"&gt;
&lt;li&gt;&lt;code&gt;$db = mysql_connect('localhost', 'root', 'root') or die('Could not connect to database');&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mysql_select_db('iptocountry', $db) or die('Could not select database');&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;status('Connected to database successfully');&lt;/code&gt;&lt;/li&gt;

&lt;/ol&gt;

	&lt;p&gt;Next we open the data file for reading, using PHP’s &lt;a href="http://www.php.net/fopen"&gt;fopen()&lt;/a&gt; function:&lt;/p&gt;
 &lt;ol class="code"&gt;
&lt;li&gt;&lt;code&gt;$fh = fopen('./iptocountry.csv', 'r');&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;status('Opened csv file for reading');&lt;/code&gt;&lt;/li&gt;

&lt;/ol&gt;

	&lt;p&gt;We need to loop through the data file one line at a time (ignoring any commented lines). Each line needs to be stripped of the quotes that wrap each field; split into its component parts (separated by commas); and then inserted into the table. We’ll print the MySQL query used, and also any error messages thrown.&lt;/p&gt;
 &lt;ol class="code"&gt;
&lt;li&gt;&lt;code&gt;while (!feof($fh))&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;  $line = str_replace('"', '', fgets($fh));&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;  if (substr($line, 0, 1) != '#') // Ignore commented lines&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;  {&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;    $arr = explode(",", $line);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;    $sql = "INSERT INTO iptocountry VALUES ('" . implode("','", $arr) . "')";&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;    mysql_query($sql);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;    status($sql);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;    if(mysql_error())&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;    {&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;      status(mysql_error());&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;    }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;  }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;}&lt;/code&gt;&lt;/li&gt;

&lt;/ol&gt;

	&lt;p&gt;The handy &lt;a href="http://www.php.net/fgets"&gt;fgets() function&lt;/a&gt; reads through the file returning a single line each iteration. If the line doesn’t start with a #, we &lt;a href="http://www.php.net/explode"&gt;explode()&lt;/a&gt; it around the separating commas, and insert it into the database using &lt;a href="http://www.php.net/implode"&gt;implode()&lt;/a&gt; to recreate the query. (Note that the query assumes that the data appears in the same order as our fields—if you are using a different data source than me, make sure your data and table structure match up.)&lt;/p&gt;
	&lt;p&gt;Finally (and because we’re responsible developers) we close the two connections in use:&lt;/p&gt;
 &lt;ol class="code"&gt;
&lt;li&gt;&lt;code&gt;fclose($fh);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mysql_close($db);&lt;/code&gt;&lt;/li&gt;

&lt;/ol&gt;

	&lt;p&gt;Running the script should generate a huge page of status messages as each record is inserted into the database.&lt;/p&gt;
	&lt;h2&gt;Using the data—where am I&lt;/h2&gt;
	&lt;p&gt;So now we have a database that can translate an IP address into a country—how do we use it?&lt;/p&gt;
	&lt;p&gt;Your site visitor’s IP address can be retrieved from the &lt;code&gt;$_SERVER&lt;/code&gt; collection:&lt;/p&gt;
 &lt;ol class="code"&gt;
&lt;li&gt;&lt;code&gt;$ip = $_SERVER['REMOTE_ADDR'];&lt;/code&gt;&lt;/li&gt;

&lt;/ol&gt;

	&lt;p&gt;To translate the four-part IP address into a single numeric value, you need to convert the &lt;code&gt;a.b.c.d&lt;/code&gt; format into &lt;code&gt;d + (256 * c) + (256 * 256 * b) + (256 * 256 * 256 * a)&lt;/code&gt;. We can do this by splitting the IP address on the period:&lt;/p&gt;
 &lt;ol class="code"&gt;
&lt;li&gt;&lt;code&gt;$parts = explode('.', $ip);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$numeric_ip = $parts[3] + (256 * $parts[2]) + (256 * 256 * $parts[1]) + (256 * 256 * 256 * $parts[0]);&lt;/code&gt;&lt;/li&gt;

&lt;/ol&gt;

	&lt;p&gt;Now all that remains is to query the database for the row where &lt;code&gt;$numeric_ip&lt;/code&gt; is between the lower and upper bounds:&lt;/p&gt;
 &lt;ol class="code"&gt;
&lt;li&gt;&lt;code&gt;$db = mysql_connect('localhost', 'root', 'root') or die('Could not connect to database');&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mysql_select_db('iptocountry', $db) or die('Could not select database');&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$sql = "SELECT two_char_code FROM iptocountry WHERE lower_bound &lt;= $numeric_ip AND upper_bound &gt;= $numeric_ip LIMIT 1";&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$result = mysql_query($sql);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$row = mysql_result($result, 0);&lt;/code&gt;&lt;/li&gt;

&lt;/ol&gt;

	&lt;p&gt;The variable &lt;code&gt;$row&lt;/code&gt; now contains the two-character country code of your user.&lt;/p&gt;
	&lt;h3&gt;Potential applications&lt;/h3&gt;
	&lt;p&gt;There are plenty of ways that this information can now be used. Apart from the aforementioned pre-populating of country dropdowns, you could also:&lt;/p&gt;
	&lt;ul&gt;
		&lt;li&gt;Select the correct translations of your content&lt;/li&gt;
		&lt;li&gt;Include the correct static file for the country: &lt;code&gt;include(“sidebar-‘ . strtolower($row) . ‘.html”);&lt;/code&gt;
*Use the country code to query country-specific APIs, such as &lt;a href="http://aws.amazon.com/"&gt;Amazon’s&lt;/a&gt;
	&lt;p&gt;I will be making use of the latter, using the geo-aware script to query the correct Amazon API and generate links to the relevant site for my visitors.&lt;/p&gt;
	&lt;h2&gt;Maintenance&lt;/h2&gt;
	&lt;p&gt;IP address allocations &lt;em&gt;can&lt;/em&gt; change, so if you were using this technique in a mission-critical application it would be a good idea to clean and re-populate the database every now and then.&lt;/p&gt;
	&lt;p&gt;If you were particularly hardcore, I imagine it would be fairly easy to suck down the gzipped .csv file direct from the source, unzip it, and run the import script, all as a scheduled task on your server.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=lIqohI"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=lIqohI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=v2M42I"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=v2M42I" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/thewatchmakerproject/~4/313002808" height="1" width="1"/&gt;</description>
<link>http://www.thewatchmakerproject.com/journal/469/how-to-make-an-ip-to-country-tool-with-php-and-mysql</link><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=thewatchmakerproject&amp;itemurl=http%3A%2F%2Fwww.thewatchmakerproject.com%2Fjournal%2F469%2Fhow-to-make-an-ip-to-country-tool-with-php-and-mysql</feedburner:awareness></item>
<item><title>Staying connected to home with LogMeIn</title>
<description>&lt;p&gt;Via &lt;a href="http://news.bbc.co.uk/1/hi/programmes/click_online/7404655.stm"&gt;the BBC&lt;/a&gt;, of all places, I read yesterday about the free remote desktop utility, &lt;a href="http://www.logmein.com/"&gt;LogMeIn&lt;/a&gt;. And after giving it a test-drive today, I’m smitten.&lt;/p&gt;
	&lt;p&gt;Available for both Mac and PC, LogMeIn is a remote control facility for your computers. After registering, you download and install an application on each machine that you want to be able to control. Then, when you suddenly realise you’ve left that important file on your home PC, you can log into the logmein.com site, select the relevant computer name, and take complete remote control of your other machine.&lt;/p&gt;
	&lt;p&gt;The site works over HTTPS, so even through a corporate firewall I was able to take control of the iMac sitting on my desk at home and blast out some unexpected heavy metal at my wife. It also syncs your clipboard, allowing copy+paste over the remote connection.&lt;/p&gt;
	&lt;p&gt;The screen updates slowly as you switch between applications—I wouldn’t want to attempt any actual work remotely—but for the kind of things I am likely to want to do (email stuff to myself, retrieve files, or manage downloads) the service is ideal.&lt;/p&gt;
	&lt;p&gt;They also offer a paid version from $13/month for 1 PC, which adds the ability to sync files, drag and drop files between machines, and share printer connections.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=txsUcH"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=txsUcH" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=FCXv5H"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=FCXv5H" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/thewatchmakerproject/~4/296529986" height="1" width="1"/&gt;</description>
<link>http://www.thewatchmakerproject.com/journal/467/staying-connected-to-home-with-logmein</link><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=thewatchmakerproject&amp;itemurl=http%3A%2F%2Fwww.thewatchmakerproject.com%2Fjournal%2F467%2Fstaying-connected-to-home-with-logmein</feedburner:awareness></item>
<item><title>1001s</title>
<description>&lt;p&gt;A couple of 1001 lists have been knocking about the internet recently. &lt;a href="http://www.berbecuta.com/2008/03/14/1001-movie-you-must-see-before-you-die/"&gt;1001 Movies You Must See Before You Die&lt;/a&gt; and &lt;a href="http://www.amazon.com/exec/obidos/ASIN/0789313707/ref=nosim/0sil8"&gt;1001 Books You Must Read Before You Die&lt;/a&gt; (&lt;a href="http://1morechapter.com/projects/1001-list/"&gt;list here&lt;/a&gt;) both demand you waste the best part of an hour scrutinising and checking off your own consumption.&lt;/p&gt;
	&lt;p&gt;My final tally was 265 films, but only 71 books. Must try harder—in particular, I am embarrassed to admit that I have never read any Dickens. I also seem to have watched precious few films from the 1940s, for some reason.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=SU0cGH"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=SU0cGH" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=Lsv1wH"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=Lsv1wH" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/thewatchmakerproject/~4/292166302" height="1" width="1"/&gt;</description>
<link>http://www.thewatchmakerproject.com/journal/466/1001s</link><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=thewatchmakerproject&amp;itemurl=http%3A%2F%2Fwww.thewatchmakerproject.com%2Fjournal%2F466%2F1001s</feedburner:awareness></item>
<item><title>Relaunched freelance site</title>
<description>&lt;p&gt;Yesterday I pushed out a new version of &lt;a href="http://www.29digital.com/"&gt;my freelance site&lt;/a&gt;, the first new design since 2005.&lt;/p&gt;
	&lt;h2&gt;Objectives&lt;/h2&gt;
	&lt;p&gt;When I originally launched the site, I intended to regularly update the ‘corporate’ blog, but in the end I only managed half-a-dozen posts before apathy set in. This redesign, then, relegates those few entries to an archive (maintaining the old URL structure to avoid broken links) and pushes the portfolio pieces front-and-centre, the latter now also featuring client testimonials.&lt;/p&gt;
	&lt;p&gt;In the four years since I started freelancing, I’ve also refocused the areas in which I work—before, the site had a generic web design focus, but I’m now highlighting the three areas in which I generally work: HTML/CSS templating, application development, and &lt;acronym title="Small and Medium Enterprises"&gt;SME&lt;/acronym&gt; site design/build. Add a contact form, and the site has everything it needs.&lt;/p&gt;
	&lt;h2&gt;Design and Inspiration&lt;/h2&gt;
	&lt;p&gt;Browsing design galleries might give me lots of inspiration, but when it comes to execution I struggle to translate my ideas into cohesive design mock-ups. After many failed attempts at creating a design that I liked, eventually I decided to strip the site back to a few simple blocks of content, with very little ‘design’ going on.&lt;/p&gt;
	&lt;p&gt;The final site uses a six-column grid and a strong baseline to align every element (notice how the screenshot thumbnails sit on the same line as the testimonial text).&lt;/p&gt;
	&lt;p&gt;There are a few sources of inspiration evident in the eventual design:&lt;/p&gt;
	&lt;ul&gt;
		&lt;li&gt;I borrowed the huge headers and attention to typography from &lt;a href="http://www.garrettdimon.com/"&gt;Garrett Dimon’s site&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;The colour strip with clipped corners and curled-up shadow effect is lifted wholesale from an earlier version of &lt;a href="http://www.erisfree.com/"&gt;Eris Free’s blog&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;The link colour is identical to that used on the &lt;a href="http://www.codeigniter.com/"&gt;CodeIgniter&lt;/a&gt; and &lt;a href="http://www.expressionengine.com/"&gt;ExpressionEngine&lt;/a&gt; sites, in homage to &lt;a href="http://www.31three.com/"&gt;Jesse Bennett Chamberlain’s&lt;/a&gt; influence on modern web design&lt;/li&gt;
	&lt;/ul&gt;
	&lt;h2&gt;Development&lt;/h2&gt;
	&lt;p&gt;I wanted to take this opportunity to have a play with some of the more advanced aspects of CSS—have a poke through the CSS file for a closer look; the site makes use of:&lt;/p&gt;
	&lt;ul&gt;
		&lt;li&gt;generated content&lt;/li&gt;
		&lt;li&gt;CSS columns&lt;/li&gt;
		&lt;li&gt;:first-child and :first-letter&lt;/li&gt;
		&lt;li&gt;adjacent sibling selectors&lt;/li&gt;
		&lt;li&gt;opacity&lt;/li&gt;
		&lt;li&gt;fixed positioning&lt;/li&gt;
		&lt;li&gt;text-shadow&lt;/li&gt;
	&lt;/ul&gt;
	&lt;p&gt;The few browser hacks that were necessary are included within the main CSS file. It seemed more sensible than downloading a whole extra stylesheet for IE6 and 7.&lt;/p&gt;
	&lt;p&gt;With the removal of the blog I no longer needed to stick with the &lt;a href="http://www.textpattern.com/"&gt;Textpattern&lt;/a&gt; backend of the old site, so I replaced it with a simple CMS built on &lt;a href="http://www.codeigniter.com/"&gt;CodeIgniter&lt;/a&gt;.&lt;/p&gt;
	&lt;h2&gt;Performance&lt;/h2&gt;
	&lt;p&gt;The site is also optimised for performance (or, at least, YSlow’s version of performance). The .htaccess file sets far-future expiry dates to encourage asset caching, and uses mod_gzip (or mod_deflate, if mod_gzip isn’t available) to reduce the filesize of pages.&lt;/p&gt;
	&lt;p&gt;All the JavaScript (&lt;a href="http://www.jquery.com/"&gt;jQuery&lt;/a&gt; and the jQuery &lt;a href="http://leandrovieira.com/projects/jquery/lightbox/"&gt;lightBox&lt;/a&gt;) and the CSS is also compressed using the &lt;a href="http://developer.yahoo.com/yui/compressor/"&gt;YUI Compressor&lt;/a&gt; before being uploaded.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=NQ0GJH"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=NQ0GJH" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=7Uu7qH"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=7Uu7qH" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/thewatchmakerproject/~4/292166303" height="1" width="1"/&gt;</description>
<link>http://www.thewatchmakerproject.com/journal/465/relaunched-freelance-site</link><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=thewatchmakerproject&amp;itemurl=http%3A%2F%2Fwww.thewatchmakerproject.com%2Fjournal%2F465%2Frelaunched-freelance-site</feedburner:awareness></item>
<item><title>Odd jQuery gotcha: IE and .html()</title>
<description>&lt;p&gt;Here’s an odd one.&lt;/p&gt;
	&lt;p&gt;If you use jQuery’s &lt;code&gt;.html()&lt;/code&gt; method to find a string of HTML, beware if that HTML contains any elements that have events registered—you might get a little more than you bargained for.&lt;/p&gt;
	&lt;p&gt;Here’s a simple test case:&lt;/p&gt;
 &lt;code&gt;&lt;pre&gt;
&lt;div&gt;
&lt;button id="test"&gt;What is the magic number?&lt;/button&gt;
&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;
	&lt;p&gt;And the JavaScript to attach an event to the &lt;code&gt;button&lt;/code&gt; that alerts the HTML contained in its parent element (the &lt;code&gt;div&lt;/code&gt;):&lt;/p&gt;
 &lt;code&gt;&lt;pre&gt;
$('#test').click(function () {
var x = $(this).parent().html();
alert(x);
});
&lt;/code&gt;&lt;/pre&gt;
	&lt;p&gt;Run the code in Firefox, and you get the expected result—the HTML contained within the &lt;code&gt;div&lt;/code&gt;:&lt;/p&gt;
 &lt;img src="/images/43.png" title="Alert in Firefox, showing HTML text" alt="Alert in Firefox, showing HTML text" /&gt;
	&lt;p&gt;But try the same code in IE and you get a very different result:&lt;/p&gt;
 &lt;img src="/images/42.png" title="Alert in IE, showing random number" alt="Alert in IE, showing random number" /&gt;
	&lt;p&gt;What’s that all about, then? Given that I was trying to parse a number out of the content, this behaviour threw a rather large spanner in the works.&lt;/p&gt;
	&lt;p&gt;The alternative, if you don’t strictly need the tags, is to use &lt;code&gt;.text()&lt;/code&gt; instead—but it’s still an odd example of what can happen if you’re not careful about browser testing your scripts as well as your HTML and CSS.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=OzI1EG"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=OzI1EG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=Sc3UqG"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=Sc3UqG" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/thewatchmakerproject/~4/292166304" height="1" width="1"/&gt;</description>
<link>http://www.thewatchmakerproject.com/journal/464/odd-jquery-gotcha-ie-and-html</link><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=thewatchmakerproject&amp;itemurl=http%3A%2F%2Fwww.thewatchmakerproject.com%2Fjournal%2F464%2Fodd-jquery-gotcha-ie-and-html</feedburner:awareness></item>
<item><title>Is it time to re-introduce sound to the web?</title>
<description>&lt;p&gt;So why can’t web pages have sound effects?&lt;/p&gt;
	&lt;p&gt;It was probably one of the first things you did when you first started playing with HTML, but background music, and funny sound effects when you clicked buttons, went the way of the spacer gif—web design matured, and web standards took over.&lt;/p&gt;
	&lt;p&gt;But—now that “the web is the desktop”, and online applications become increasingly harder to tell apart from their OS-bound counterparts—can anyone remind me again just what is the compelling reason for not using sound effects on the web?&lt;/p&gt;
	&lt;p&gt;Desktop apps have always used sound as part of their UI. Sounds communicate change, error, or demand attention. As I type, Twitterific whistles at me; Word complains if I try to jump past the end of the current line; and Adium alerts me to the comings and going of my online friends. And yet, on the web, where we dissect and discuss every tiny nuance of &lt;em&gt;design’s&lt;/em&gt; ability for communication, &lt;em&gt;sound&lt;/em&gt; is all but ignored. (The only exception I can think of is 37signals’ &lt;a href="http://www.campfirenow.com/"&gt;Campfire&lt;/a&gt;, which gently ‘bongs’ at you when there is an updated message to read.)&lt;/p&gt;
	&lt;p&gt;“It’s an accessibility thing!” is a tempting argument, and certainly, allowing people to control embedded media would be an important concession. But there is no outcry over the inherent inaccessibility (or in-anything-else-ness) of sound effects in desktop applications, so it seems a rather weak argument.&lt;/p&gt;
	&lt;p&gt;A better one might be that sound effects can be large files, and thus slow down a web page—but if effects are part of the UI, and likely to be triggered by click or mouseover events, then the .wav files can be post-loaded in the same way as any other media to be revealed through user action.&lt;/p&gt;
	&lt;p&gt;It seems to me that there is no reason at all not to use &lt;a href="http://www.thewatchmakerproject.com/sound/demo/"&gt;appropriate sound effects&lt;/a&gt; as part of a web application—and, in fact, it might be a benefit to users who are used to audible as well as visual feedback.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=KiQPIG"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=KiQPIG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=orxMcG"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=orxMcG" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/thewatchmakerproject/~4/292166305" height="1" width="1"/&gt;</description>
<link>http://www.thewatchmakerproject.com/journal/463/is-it-time-to-re-introduce-sound-to-the-web</link><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=thewatchmakerproject&amp;itemurl=http%3A%2F%2Fwww.thewatchmakerproject.com%2Fjournal%2F463%2Fis-it-time-to-re-introduce-sound-to-the-web</feedburner:awareness></item>
<item><title>Internet semi-famous</title>
<description>&lt;p&gt;Yesterday saw a couple of spikes in site traffic. &lt;a href="http://www.hicksdesign.co.uk/"&gt;Jon Hicks&lt;/a&gt; mentioned my &lt;a href="http://www.29digital.net/grid/"&gt;grid calculator&lt;/a&gt; during his presentation at &lt;a href="http://www.futureofwebdesign.com/"&gt;FOWD&lt;/a&gt;, which instantly quadrupled the traffic to that page:&lt;/p&gt;
 &lt;img src="/images/40.png" title="Google Analytics graph showing spike in traffic" alt="Google Analytics graph showing spike in traffic" /&gt;
	&lt;p&gt;And, almost simultaneously, Smashing Magazine included my comment form in their &lt;a href="http://www.smashingmagazine.com/2008/04/17/web-form-design-modern-solutions-and-creative-ideas/"&gt;Web Form Design: Modern Solutions and Creative Ideas&lt;/a&gt; post, which pushed the daily visits over 1,000 for the first time:&lt;/p&gt;
 &lt;img src="/images/41.png" title="Google Analytics graph showing spike in traffic" alt="Google Analytics graph showing spike in traffic" /&gt;
	&lt;p&gt;Which was nice.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=Sp5CcqG"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=Sp5CcqG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/thewatchmakerproject?a=yWbmMqG"&gt;&lt;img src="http://feeds.feedburner.com/~f/thewatchmakerproject?i=yWbmMqG" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/thewatchmakerproject/~4/292166306" height="1" width="1"/&gt;</description>
<link>http://www.thewatchmakerproject.com/journal/462/internet-semi-famous</link><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=thewatchmakerproject&amp;itemurl=http%3A%2F%2Fwww.thewatchmakerproject.com%2Fjournal%2F462%2Finternet-semi-famous</feedburner:awareness></item><feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetFeedData?uri=thewatchmakerproject</feedburner:awareness></channel></rss>
