<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Hello, I am Sean Murphy</title>
	<atom:link href="http://iamseanmurphy.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://iamseanmurphy.com</link>
	<description>Thoughts, news, code by Sean Murphy</description>
	<lastBuildDate>Wed, 19 Aug 2009 17:40:26 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Binary Search for Javascript Arrays</title>
		<link>http://iamseanmurphy.com/2009/04/29/binary-search-for-javascript-arrays/</link>
		<comments>http://iamseanmurphy.com/2009/04/29/binary-search-for-javascript-arrays/#comments</comments>
		<pubDate>Wed, 29 Apr 2009 21:41:12 +0000</pubDate>
		<dc:creator>Sean Murphy</dc:creator>
				<category><![CDATA[Code Snippets]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[array]]></category>
		<category><![CDATA[binary search]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[search]]></category>

		<guid isPermaLink="false">http://iamseanmurphy.com/2009/04/29/binary-search-for-javascript-arrays/</guid>
		<description><![CDATA[If you need to search through a large array, or you search arrays frequently in your Javascript code, or if you do both, chances are a binary search will give you better performance than a linear search (read: for loop). One caveat, however, is that binary search algorithms only work on sorted arrays. Here is [...]


Related posts:<ol><li><a href='http://iamseanmurphy.com/2007/11/15/javascript-for-in-loops/' rel='bookmark' title='Permanent Link: Javascript For-in Loops'>Javascript For-in Loops</a></li><li><a href='http://iamseanmurphy.com/2008/10/10/longurl-integration-for-your-website/' rel='bookmark' title='Permanent Link: LongURL Integration For Your Website'>LongURL Integration For Your Website</a></li></ol>]]></description>
			<content:encoded><![CDATA[<p>If you need to search through a large array, or you search arrays frequently in your Javascript code, or if you do both, chances are a binary search will give you better performance than a linear search (read: for loop). One caveat, however, is that binary search algorithms only work on sorted arrays. Here is a binary search function I sometimes use in my code:</p>
<p><span id="more-34"></span></p>
<pre name="code" class="js">Array.prototype.binSearch = function(needle, case_insensitive) {
    if (!this.length) return -1;

	var high = this.length - 1;
	var low = 0;
	case_insensitive = (typeof(case_insensitive) !== 'undefined' &amp;&amp; case_insensitive) ? true:false;
	needle = (case_insensitive) ? needle.toLowerCase():needle;

	while (low &lt;= high) {
		mid = parseInt((low + high) / 2)
		element = (case_insensitive) ? this[mid].toLowerCase():this[mid];
		if (element &gt; needle) {
			high = mid - 1;
		} else if (element &lt; needle) {
			low = mid + 1;
		} else {
			return mid;
		}
	}

	return -1;
};</pre>


<p>Related posts:<ol><li><a href='http://iamseanmurphy.com/2007/11/15/javascript-for-in-loops/' rel='bookmark' title='Permanent Link: Javascript For-in Loops'>Javascript For-in Loops</a></li><li><a href='http://iamseanmurphy.com/2008/10/10/longurl-integration-for-your-website/' rel='bookmark' title='Permanent Link: LongURL Integration For Your Website'>LongURL Integration For Your Website</a></li></ol></p>]]></content:encoded>
			<wfw:commentRss>http://iamseanmurphy.com/2009/04/29/binary-search-for-javascript-arrays/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Better HAProxy Health Check For Dynamic Websites</title>
		<link>http://iamseanmurphy.com/2009/04/22/a-better-haproxy-health-check-for-dynamic-websites/</link>
		<comments>http://iamseanmurphy.com/2009/04/22/a-better-haproxy-health-check-for-dynamic-websites/#comments</comments>
		<pubDate>Wed, 22 Apr 2009 16:14:50 +0000</pubDate>
		<dc:creator>Sean Murphy</dc:creator>
				<category><![CDATA[Scalability]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[fastcgi]]></category>
		<category><![CDATA[fcgi]]></category>
		<category><![CDATA[haproxy]]></category>
		<category><![CDATA[high availablity]]></category>
		<category><![CDATA[load balancing]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[web server]]></category>

		<guid isPermaLink="false">http://iamseanmurphy.com/2009/04/22/a-better-haproxy-health-check-for-dynamic-websites/</guid>
		<description><![CDATA[Nobody wants their website to go down, or worse, for users to notice the site is down. Because of this most larger websites will run on multiple servers to provide some level of high availability. In a multi-server architecture there is typically a load balancer (or cluster of load balancers) to distribute the load among [...]


Related posts:<ol><li><a href='http://iamseanmurphy.com/2009/03/02/high-performance-comet-on-a-shoestring/' rel='bookmark' title='Permanent Link: High Performance Comet on a Shoestring'>High Performance Comet on a Shoestring</a></li></ol>]]></description>
			<content:encoded><![CDATA[<p>Nobody wants their website to go down, or worse, for users to <em>notice</em> the site is down. Because of this most larger websites will run on multiple servers to provide some level of high availability. In a multi-server architecture there is typically a load balancer (or cluster of load balancers) to distribute the load among a pool of web servers. When a server goes down it&#8217;s taken out of the pool until it is once again ready to handle requests. HAProxy (a software load balancer) has the ability to perform this task by doing periodic health checks on all the servers in a cluster. The default settings, though, could give false positives in some cases, and thus create a bad user experience by allowing ill application servers to continue receiving requests.</p>
<p><span id="more-33"></span><br />
When in HTTP mode HAProxy&#8217;s default health check is a simple OPTIONS request. This has the advantage of being a very lightweight request, and is easy to identify and filter from server logs. Consider this scenario though: HAProxy balances the load between several web servers running nginx and PHP-FastCGI. If nginx is up but PHP-FastCGI goes down, nginx will still properly handle the OPTIONS request from HAProxy, giving the impression that all is well. HAProxy continues sending requests to the ill server which in turn get a 504 Gateway Timeout (or similar) response. Not a very good situation.</p>
<p>A solution would be to use a deeper health check, one that goes beyond nginx to the PHP-FastCGI process. That way if PHP-FastCGI goes down, the whole server is presumed &#8216;down&#8217;.</p>
<pre>
backend appservers

 mode http

 option httpchk HEAD /health_check.php HTTP/1.1\r\nHost:\ example.com

 server web1 x.x.x.x:80 weight 5 check inter 2000

 server web2 x.x.x.x:80 weight 5 check inter 2000

 server web3 x.x.x.x:80 weight 5 check inter 2000</pre>
<p>In the above example I&#8217;m using a custom health check request which will be processed by PHP-FastCGI. health_check.php is a lightweight script that contains simply <code>&lt;?php echo "I'm healthy"; ?&gt;</code>. I also added a host header so that the health check will be handled by a specific nginx virtual host. The nginx vhost config has this in it:</p>
<pre>
location = /health_check.php {

 access_log		off;

 fastcgi_pass	127.0.0.1:9000;

 fastcgi_index	index.php;

 include	/etc/nginx/fastcgi_params;

}</pre>
<p>And there you have it&#8211;a better HAProxy health check for dynamic websites.</p>


<p>Related posts:<ol><li><a href='http://iamseanmurphy.com/2009/03/02/high-performance-comet-on-a-shoestring/' rel='bookmark' title='Permanent Link: High Performance Comet on a Shoestring'>High Performance Comet on a Shoestring</a></li></ol></p>]]></content:encoded>
			<wfw:commentRss>http://iamseanmurphy.com/2009/04/22/a-better-haproxy-health-check-for-dynamic-websites/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Recursive Find and Replace With grep and Perl</title>
		<link>http://iamseanmurphy.com/2009/04/11/recursive-find-and-replace-with-grep-and-perl/</link>
		<comments>http://iamseanmurphy.com/2009/04/11/recursive-find-and-replace-with-grep-and-perl/#comments</comments>
		<pubDate>Sat, 11 Apr 2009 20:51:56 +0000</pubDate>
		<dc:creator>Sean Murphy</dc:creator>
				<category><![CDATA[Code Snippets]]></category>
		<category><![CDATA[find/replace]]></category>
		<category><![CDATA[grep]]></category>
		<category><![CDATA[perl]]></category>
		<category><![CDATA[search]]></category>

		<guid isPermaLink="false">http://iamseanmurphy.com/2009/04/11/recursive-find-and-replace-with-grep-and-perl/</guid>
		<description><![CDATA[I thought it might be a nice idea to start posting useful little commands and bits of code every now and then&#8211;ones I&#8217;ve found to be particularly useful. So here&#8217;s the first one, recursive find and replace. A masterfully crafted regular expression paired with this command can save you hours of tedious work.

This will search [...]


No related posts.]]></description>
			<content:encoded><![CDATA[<p>I thought it might be a nice idea to start posting useful little commands and bits of code every now and then&#8211;ones I&#8217;ve found to be particularly useful. So here&#8217;s the first one, recursive find and replace. A masterfully crafted regular expression paired with this command can save you hours of tedious work.</p>
<p><span id="more-32"></span><br />
This will search all files recursively for SEARCH_STRING and replace all occurrences of SEARCH_STRING with REPLACE_STRING throughout each unique file found. It also creates a backup of each modified file so that FILE is backed-up as FILE~ (with a tilde).</p>
<pre name="code" class="python">grep -R --files-with-matches 'SEARCH_STRING' . | sort | uniq | xargs perl -pi~ -e 's/SEARCH_STRING/REPLACE_STRING/'</pre>


<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://iamseanmurphy.com/2009/04/11/recursive-find-and-replace-with-grep-and-perl/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Taking The Pain Out Of Domain Hunting</title>
		<link>http://iamseanmurphy.com/2009/03/30/taking-the-pain-out-of-domain-hunting/</link>
		<comments>http://iamseanmurphy.com/2009/03/30/taking-the-pain-out-of-domain-hunting/#comments</comments>
		<pubDate>Mon, 30 Mar 2009 17:22:45 +0000</pubDate>
		<dc:creator>Sean Murphy</dc:creator>
				<category><![CDATA[Work]]></category>
		<category><![CDATA[domains]]></category>
		<category><![CDATA[search]]></category>
		<category><![CDATA[trionym]]></category>
		<category><![CDATA[whois]]></category>

		<guid isPermaLink="false">http://iamseanmurphy.com/2009/03/30/taking-the-pain-out-of-domain-hunting/</guid>
		<description><![CDATA[
Coming up with a suitable name for a business, product, or website is something I do on a fairly regular basis. In brainstorming a name I often make lists of words I&#8217;d like to use, like adjectives and nouns than relate the product. Then I start combining the words to create a unique name and [...]


Related posts:<ol><li><a href='http://iamseanmurphy.com/2009/04/22/a-better-haproxy-health-check-for-dynamic-websites/' rel='bookmark' title='Permanent Link: A Better HAProxy Health Check For Dynamic Websites'>A Better HAProxy Health Check For Dynamic Websites</a></li></ol>]]></description>
			<content:encoded><![CDATA[<p><img src="http://iamseanmurphy.com/wp-content/uploads/2009/04/screenshot.jpg" alt="Trionym Screenshot" /></p>
<p>Coming up with a suitable name for a business, product, or website is something I do on a fairly regular basis. In brainstorming a name I often make lists of words I&#8217;d like to use, like adjectives and nouns than relate the product. Then I start combining the words to create a unique name and check to see if the related domain is taken or not. The problem is that even though I may have come up with a name I really like, if the domain name is taken, it isn&#8217;t worth keeping.</p>
<p><span id="more-29"></span><br />
These days a LOT of domains are taken, either by people using them or companies squatting them. So to make this whole process a little easier I built a website that takes most of the work out of hunting for a good domain: <a href="http://trionym.org" onclick="javascript:pageTracker._trackPageview ('/outbound/trionym.org');">Trionym</a>.The idea is fairly simple: enter up to three lists of words, choose which Top-Level Domains you&#8217;re willing to use, and search. Trionym will then create all the possible word combinations and check whois databases to see if the domains are registered. It&#8217;s relatively simple for now, but I&#8217;m considering adding more options, so if there&#8217;s a feature you&#8217;d like to see just let me know.</p>


<p>Related posts:<ol><li><a href='http://iamseanmurphy.com/2009/04/22/a-better-haproxy-health-check-for-dynamic-websites/' rel='bookmark' title='Permanent Link: A Better HAProxy Health Check For Dynamic Websites'>A Better HAProxy Health Check For Dynamic Websites</a></li></ol></p>]]></content:encoded>
			<wfw:commentRss>http://iamseanmurphy.com/2009/03/30/taking-the-pain-out-of-domain-hunting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>High Performance Comet on a Shoestring</title>
		<link>http://iamseanmurphy.com/2009/03/02/high-performance-comet-on-a-shoestring/</link>
		<comments>http://iamseanmurphy.com/2009/03/02/high-performance-comet-on-a-shoestring/#comments</comments>
		<pubDate>Tue, 03 Mar 2009 03:34:33 +0000</pubDate>
		<dc:creator>Sean Murphy</dc:creator>
				<category><![CDATA[Performance]]></category>
		<category><![CDATA[Scalability]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[comet]]></category>
		<category><![CDATA[haproxy]]></category>
		<category><![CDATA[ip addresses]]></category>
		<category><![CDATA[meteor]]></category>
		<category><![CDATA[network load balancing]]></category>
		<category><![CDATA[ports]]></category>
		<category><![CDATA[servers]]></category>

		<guid isPermaLink="false">http://iamseanmurphy.com/2009/03/02/high-performance-comet-on-a-shoestring/</guid>
		<description><![CDATA[I&#8217;ve had my eye on the advances that are being made in the Comet arena for a while now, but it was only this past weekend that I finally sat down and used it for a project. In doing so, there was a particular configuration problem I needed to address, and that was&#8230;uh, addressing.
Introducing Comet [...]


Related posts:<ol><li><a href='http://iamseanmurphy.com/2009/04/22/a-better-haproxy-health-check-for-dynamic-websites/' rel='bookmark' title='Permanent Link: A Better HAProxy Health Check For Dynamic Websites'>A Better HAProxy Health Check For Dynamic Websites</a></li></ol>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve had my eye on the advances that are being made in the Comet arena for a while now, but it was only this past weekend that I finally sat down and used it for a project. In doing so, there was a particular configuration problem I needed to address, and that was&#8230;uh, addressing.</p>
<p>Introducing Comet to an existing architecture assumes there is already a web server in the neighborhood, and that it is, in one way or another, receiving traffic from port 80. Due to the fact that many site visitors will likely be positioned behind a firewall unwilling to accept connections on ports other than 80 or 443, we also need to get our Comet server running on port 80 as well. This normally wouldn&#8217;t be much of a problem at all, unless you don&#8217;t want to fork over the money for an extra IP address. I don&#8217;t &amp; I didn&#8217;t. So let me show you how I did so.</p>
<p><span id="more-28"></span><br />
As I eluded to above, to solve this problem of running two services on the same port in the same server environment you would normally have two different IP addresses assigned to the same front-end server. This is typically a load balancer or firewall, but these could also be running on the same machine as a web server and Comet server. The load balancer would then accept requests for x.x.x.1:80 and send them to the web server, and requests for x.x.x.2:80 would go to the Comet server. However if we only have one IP address that means we have to route requests based on a higher network layer, the Application Layer (7). Now we route by domain name.</p>
<p>In fact, that is something most web servers can handle using name-based virtual hosts. &#8220;So why not set-up Apache to reverse-proxy requests to the Comet server?&#8221;, you ask. Well, that would work. The reason Comet servers even exists though, is because web server connection threads are too heavy to support the level of concurrency Comet requires (for a decent number of users). This is where the &#8220;high performance&#8221; part comes in. HAProxy is a fantastic high performance layer 7 load balancer. Using HAProxy&#8217;s ACL feature we can basically mimic Apache virtual hosts. Consider this example snippet from haproxy.cfg:</p>
<pre name="code">
frontend www *:80
    mode http
    acl comet hdr_beg(host) comet.
    use_backend meteor if comet

default_backend apachebackend meteor
    mode http
    server server1 127.0.0.1:4670

backend apache
    mode http
    server server2 127.0.0.1:8080</pre>
<p>As you can see, I set up a front-end to accept all connections on port 80. Then I use an ACL to examine the HOST header and see if it begins with comet. (e.g. http://comet.example.com). If it does, the request is sent to the comet server on port 4670, and if not, requests go to Apache on port 8080. And there you have it, a high performance Comet installation with no money out-of-pocket.</p>


<p>Related posts:<ol><li><a href='http://iamseanmurphy.com/2009/04/22/a-better-haproxy-health-check-for-dynamic-websites/' rel='bookmark' title='Permanent Link: A Better HAProxy Health Check For Dynamic Websites'>A Better HAProxy Health Check For Dynamic Websites</a></li></ol></p>]]></content:encoded>
			<wfw:commentRss>http://iamseanmurphy.com/2009/03/02/high-performance-comet-on-a-shoestring/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>.htaccess File Causes 500 Internal Server Error on Network Solutions</title>
		<link>http://iamseanmurphy.com/2009/02/21/htaccess-file-causes-500-internal-server-error-on-network-solutions/</link>
		<comments>http://iamseanmurphy.com/2009/02/21/htaccess-file-causes-500-internal-server-error-on-network-solutions/#comments</comments>
		<pubDate>Sat, 21 Feb 2009 20:16:19 +0000</pubDate>
		<dc:creator>Sean Murphy</dc:creator>
				<category><![CDATA[Work]]></category>
		<category><![CDATA[500]]></category>
		<category><![CDATA[cgi]]></category>
		<category><![CDATA[htaccess]]></category>
		<category><![CDATA[mod_php]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://iamseanmurphy.com/2009/02/21/htaccess-file-causes-500-internal-server-error-on-network-solutions/</guid>
		<description><![CDATA[How&#8217;s that for a search engine friendly title, eh?
This is just a quick note for anyone who has to deal with Network Solutions hosting (for clients or otherwise). Apperantly Network Solutions doesn&#8217;t run PHP with Apache&#8217;s mod_php, but rather as a CGI application. That means if you try to put PHP configuration directives in a [...]


Related posts:<ol><li><a href='http://iamseanmurphy.com/2009/03/02/high-performance-comet-on-a-shoestring/' rel='bookmark' title='Permanent Link: High Performance Comet on a Shoestring'>High Performance Comet on a Shoestring</a></li></ol>]]></description>
			<content:encoded><![CDATA[<p>How&#8217;s that for a search engine friendly title, eh?</p>
<p>This is just a quick note for anyone who has to deal with Network Solutions hosting (for clients or otherwise). Apperantly Network Solutions doesn&#8217;t run PHP with Apache&#8217;s mod_php, but rather as a CGI application. That means if you try to put PHP configuration directives in a .htaccess file it will cause a 500 Internal Server Error. My helpful reference: <a href="http://www.nerdliness.com/article/2008/07/29/because-network-solutions-sucks#comment-4925" onclick="javascript:pageTracker._trackPageview ('/outbound/www.nerdliness.com');">Because Network Solutions Sucks</a>.</p>
<p>You have been warned.</p>


<p>Related posts:<ol><li><a href='http://iamseanmurphy.com/2009/03/02/high-performance-comet-on-a-shoestring/' rel='bookmark' title='Permanent Link: High Performance Comet on a Shoestring'>High Performance Comet on a Shoestring</a></li></ol></p>]]></content:encoded>
			<wfw:commentRss>http://iamseanmurphy.com/2009/02/21/htaccess-file-causes-500-internal-server-error-on-network-solutions/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Auto-Linking URLs with PHP</title>
		<link>http://iamseanmurphy.com/2008/12/01/auto-linking-urls-with-php/</link>
		<comments>http://iamseanmurphy.com/2008/12/01/auto-linking-urls-with-php/#comments</comments>
		<pubDate>Mon, 01 Dec 2008 23:54:30 +0000</pubDate>
		<dc:creator>Sean Murphy</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[auto-linking]]></category>
		<category><![CDATA[laconica]]></category>
		<category><![CDATA[links]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[regex]]></category>
		<category><![CDATA[urls]]></category>

		<guid isPermaLink="false">http://iamseanmurphy.com/2008/12/01/auto-linking-urls-with-php/</guid>
		<description><![CDATA[A week or so ago I was working on a bug in the auto-linking code for Laconica, the software that powers Indenti.ca. Squashing that particular bug wasn&#8217;t too hard, but I wanted to take the functionality a step further (closer to the calibre of Gmail) and it turns out, writing robust auto-linking code is more [...]


No related posts.]]></description>
			<content:encoded><![CDATA[<p>A week or so ago I was working on a bug in the auto-linking code for <a href="http://laconi.ca" onclick="javascript:pageTracker._trackPageview ('/outbound/laconi.ca');">Laconica</a>, the software that powers <a href="http://identi.ca" onclick="javascript:pageTracker._trackPageview ('/outbound/identi.ca');">Indenti.ca</a>. Squashing that particular bug wasn&#8217;t too hard, but I wanted to take the functionality a step further (closer to the calibre of Gmail) and it turns out, writing robust auto-linking code is more difficult than it initially seems. So I played with it a little at a time here and there, testing as many edge cases as I could think of. The result is a function that&#8217;s more robust than most URL auto-linking code I&#8217;ve come across.</p>
<p>I still need to add support of internationalized TLDs and HTML. So, although it only works with plain text for now, I think it&#8217;s off to a good start. Check out the <a href="http://iamseanmurphy.com/autolinking/demo.php">demo</a> or <a href="http://iamseanmurphy.com/autolinking/demo.php?download">download the source</a>.</p>


<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://iamseanmurphy.com/2008/12/01/auto-linking-urls-with-php/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>LongURL Integration For Your Website</title>
		<link>http://iamseanmurphy.com/2008/10/10/longurl-integration-for-your-website/</link>
		<comments>http://iamseanmurphy.com/2008/10/10/longurl-integration-for-your-website/#comments</comments>
		<pubDate>Fri, 10 Oct 2008 05:26:42 +0000</pubDate>
		<dc:creator>Sean Murphy</dc:creator>
				<category><![CDATA[Work]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[integration]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[longurl]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[tinyurl]]></category>

		<guid isPermaLink="false">http://iamseanmurphy.com/2008/10/10/longurl-integration-for-your-website/</guid>
		<description><![CDATA[I wasn&#8217;t sure it could be done, but I&#8217;ve done it. I&#8217;m happy to say that I&#8217;ve made it even easier to use the LongURL web service, specifically on your own site. Today I wrote a jQuery plugin that allows you to add LongURL support to a website in like, I don&#8217;t know, 30 seconds?! [...]


Related posts:<ol><li><a href='http://iamseanmurphy.com/2008/08/28/longurlrestoring-order-to-the-universe/' rel='bookmark' title='Permanent Link: LongURL&mdash;Restoring Order to the Universe'>LongURL&mdash;Restoring Order to the Universe</a></li></ol>]]></description>
			<content:encoded><![CDATA[<p>I wasn&#8217;t sure it could be done, but I&#8217;ve done it. I&#8217;m happy to say that I&#8217;ve made it <em>even easier</em> to use the LongURL web service, specifically on your own site. Today I wrote a jQuery plugin that allows you to add LongURL support to a website in like, I don&#8217;t know, 30 seconds?! It really depends on how fast you are, but the point is that it&#8217;s really easy.</p>
<p>I noticed that Twitter search lets you expand URLs from some of the most popular shortening services (though, if they used LongURL they could support a whole lot more <img src='http://iamseanmurphy.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  ). I liked their UI approach; it&#8217;s clear, simple, and effective. So I pretty much mimicked their UI for my plugin.</p>
<p><span id="more-21"></span><br />
So here it is, you can add support for LongURL to your site in just a few lines of code:</p>
<pre name="code" class="js">&lt;script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="http://longurl.org/static/jquery.longurl.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
$(function() {
    $('a').longurl();
});
&lt;/script&gt;</pre>
<p>Yup, that&#8217;s it. Also, if you don&#8217;t like the Ajax working indicator that I chose, you can use your own like so:</p>
<pre name="code" class="js">$(function() {
    $('a').longurl({working_image: 'http://example.com/images/ajaxy_animation.gif'});
});</pre>
<p>So, that&#8217;s how you use the plugin. You can see a <a href="http://longurl.org/static/jquery_demo.html" onclick="javascript:pageTracker._trackPageview ('/outbound/longurl.org');">demo</a> of it in action, and <a href="http://plugins.jquery.com/project/longurl" onclick="javascript:pageTracker._trackPageview ('/outbound/plugins.jquery.com');">download it</a> from the jQuery site. Hope you find it useful.</p>


<p>Related posts:<ol><li><a href='http://iamseanmurphy.com/2008/08/28/longurlrestoring-order-to-the-universe/' rel='bookmark' title='Permanent Link: LongURL&mdash;Restoring Order to the Universe'>LongURL&mdash;Restoring Order to the Universe</a></li></ol></p>]]></content:encoded>
			<wfw:commentRss>http://iamseanmurphy.com/2008/10/10/longurl-integration-for-your-website/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CouchDB View Generation</title>
		<link>http://iamseanmurphy.com/2008/09/08/couchdb-view-generation/</link>
		<comments>http://iamseanmurphy.com/2008/09/08/couchdb-view-generation/#comments</comments>
		<pubDate>Tue, 09 Sep 2008 03:38:16 +0000</pubDate>
		<dc:creator>Sean Murphy</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Scalability]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[benchmarks]]></category>
		<category><![CDATA[couchdb]]></category>
		<category><![CDATA[import]]></category>
		<category><![CDATA[views]]></category>

		<guid isPermaLink="false">http://iamseanmurphy.com/2008/09/08/couchdb-view-generation/</guid>
		<description><![CDATA[An alternative technology quickly gaining popularity these days is CouchDB, a document-based database system for semi-structured data. I wasn&#8217;t sure what that meant at first, so I read as much as I could about it. The result? I couldn&#8217;t wait to use it.
I decided CouchDB would be a good fit for my next project (which [...]


No related posts.]]></description>
			<content:encoded><![CDATA[<p>An alternative technology quickly gaining popularity these days is <a href="http://incubator.apache.org/couchdb/" onclick="javascript:pageTracker._trackPageview ('/outbound/incubator.apache.org');">CouchDB</a>, a document-based database system for semi-structured data. I wasn&#8217;t sure what that meant at first, so I read as much as I could about it. The result? I couldn&#8217;t wait to use it.</p>
<p>I decided CouchDB would be a good fit for my next project (which I should be releasing sometime this week BTW) and rolled up my sleeves. Because of the amount of data I&#8217;m working with, I hit a few snags along the way with regard to CouchDB view performance. Some of the things I learned, although they make sense, were not what I was expecting initially (even after reading all the docs). So for the benefit of others, I thought it&#8217;d be a good idea to share my current understanding of the way views work in CouchDB, and share some of the tips &amp; tricks <a href="http://jan.prima.de/" onclick="javascript:pageTracker._trackPageview ('/outbound/jan.prima.de');">Jan</a>, <a href="http://jchris.mfdz.com/" onclick="javascript:pageTracker._trackPageview ('/outbound/jchris.mfdz.com');">Chris</a>, and others have given me along the way.</p>
<p><span id="more-20"></span></p>
<h2>Importing Data for Speed and Glory</h2>
<p>Most of the work I&#8217;ve done with CouchDB this past week has been related to importing a fair amount of data (600k+ documents). Initially I tried creating one document at a time. This worked, but each request has associated with it a certain amount of overhead and latency. For example, creating 33,847 documents, one at a time, took 726 seconds (~12 min). Thankfully CouchDB has a bulk create mode. Creating the same documents 1,000 at a time took 58 seconds. That&#8217;s a 1,250% improvement! An added benefit of using bulk create is that it consumes less hard disk space (28.2MB vs 213.2MB).</p>
<h2>CouchDB Views vs RDBMS Tables</h2>
<p>Now that I could get my data in the database in a decent amount of time, I wanted to aggregate some of it together in a view. Before I get into too many details, let me explain how I think about CouchDB views. I&#8217;m a very spatial thinker, and so visualizing the similarities and differences between CouchDB views and traditional RDBMS tables helps me to understand how they work. It may be stupid, it may be naive, it may even be wrong, but here goes: Imagine a RDBMS database. Imagine a handful of tables in that database, each with different columns. Now imagine that <em>every</em> row in <em>every</em> one of those tables is just a document in CouchDB, all lumped into the same bucket (database) and with no hierarchy. <em>Views</em> are what filter and aggregate documents together to create (in a very limited sense) the equivalent of a <em>table</em>.</p>
<p>You don&#8217;t join views with each other because you&#8217;re already essentially <a href="http://www.cmlenz.net/archives/2007/10/couchdb-joins" onclick="javascript:pageTracker._trackPageview ('/outbound/www.cmlenz.net');">&#8220;joining&#8221; documents</a> (rows) to create the view. This might get you thinking that CouchDB views relate better to RDBMS views. In some ways that is true, but RDBMS views are a one-time snapshot of the underlying tables, and so for the sake of this discussion I&#8217;m leaving RDBMS views out.</p>
<h2>Indexing, the  Slowdown</h2>
<p>CouchDB view indexes are generated when the view is first called. More than one view can be stored inside a design document, but as long as they&#8217;re in the same doc they get generated (and updated) at the same time. After that initial creation, updating the view indexes is incremental based on what documents in the database are added, edited, or deleted. Notice I said indexes are updated based on what documents are modified in the <em>database</em>. <em>This is an important point!</em>, something that wasn&#8217;t obvious to me initially.  There are no tables. This is no hierarchy. No isolation. Modifying any documents in the database means that <em>all</em> view indexes in all design documents have to be updated.</p>
<p>The only time view generation is isolated is when a new design document is created or updated. In this case, though, the process is <em>not</em> incremental. For this reason, if you plan to store a large number of documents I strongly suggest that you work out and create your design documents before populating your database. Although CouchDB is a schema-less database, creating views for a large data set is currently much like designing a schema: you mostly do it before filling your database with data, and you generally don&#8217;t change it often. Why? Because generating views is currently a slow process, and gets slower the more documents you have. As a point of reference, for my example of 33,847 documents it took me 6,705 seconds (~1.86 hours) to generate a view for the first time. Retrieving the view after that took 0.006 seconds.</p>
<h2>Improving Speed Now, and in the Future</h2>
<p>In some cases it is possible speed up view generation by priming the view as you create documents. This method has great results. For example, if I create 33,847 documents in batches of 1,000, calling my view after every bulk create, the whole process takes 219 seconds (~3.65 min). If we compare the time it takes to insert the documents and then generate a view separately vs doing them at the same time, the latter is 3,088% faster (58 + 6,705 / 219 = 30.88).</p>
<p>CouchDB uses an implementation of <a href="http://en.wikipedia.org/wiki/MapReduce" onclick="javascript:pageTracker._trackPageview ('/outbound/en.wikipedia.org');">MapReduce</a> for generating views. Currently though, view generation cannot be distributed across several nodes. I&#8217;ve been told this feature is on the development roadmap, and so chances are view generation will get much, much faster in the (hopefully) not too distant future. Also worth noting, is that CouchDB has not yet been optimized, and <a href="http://damienkatz.net/2007/12/thoughts_on_opt.html" onclick="javascript:pageTracker._trackPageview ('/outbound/damienkatz.net');">Damien is quite optimistic</a> about its potential, as am I.</p>
<p>Now, I have only been working with CouchDB for a week, so it&#8217;s quite possible my understanding of something might be off. If so, please correct me. Working with CouchDB has been a load of fun (and education). I&#8217;m really looking forward to where it goes in the future, and I hope to do what I can get help get it there.</p>
<p><strong>UPDATE: </strong>For anyone that might be interested, you can get the import script I&#8217;m using from my <a href="http://bazaar.launchpad.net/~seanmurphy/otherwords/trunk/annotate/head%3A/libs/load_thesaurus.php" onclick="javascript:pageTracker._trackPageview ('/outbound/bazaar.launchpad.net');">Launchpad.net repository</a>. Depending on what you&#8217;re doing it might be a decent start. The script has a few nice features like resuming interrupted imports, bulk inserts with priming, and graceful handling of failed bulk inserts.</p>


<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://iamseanmurphy.com/2008/09/08/couchdb-view-generation/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>LongURL&#8212;Restoring Order to the Universe</title>
		<link>http://iamseanmurphy.com/2008/08/28/longurlrestoring-order-to-the-universe/</link>
		<comments>http://iamseanmurphy.com/2008/08/28/longurlrestoring-order-to-the-universe/#comments</comments>
		<pubDate>Fri, 29 Aug 2008 02:41:22 +0000</pubDate>
		<dc:creator>Sean Murphy</dc:creator>
				<category><![CDATA[Community]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[longurl]]></category>
		<category><![CDATA[short urls]]></category>
		<category><![CDATA[tinyurl]]></category>
		<category><![CDATA[ubiquity]]></category>

		<guid isPermaLink="false">http://iamseanmurphy.com/2008/08/28/longurlrestoring-order-to-the-universe/</guid>
		<description><![CDATA[It&#8217;s been two weeks since I conceptualized LongURL, and a productive two weeks at that! Last Monday I officially launched the service (which provides a handy REST API) with support for a dozen or so shortening services like TinyURL.com. Once I stepped away from the problem for a little while I realized there was a [...]


Related posts:<ol><li><a href='http://iamseanmurphy.com/2008/10/10/longurl-integration-for-your-website/' rel='bookmark' title='Permanent Link: LongURL Integration For Your Website'>LongURL Integration For Your Website</a></li></ol>]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s been two weeks since I conceptualized <a href="http://longurl.org" title="The Universal Way to Expand Shortened URLs" onclick="javascript:pageTracker._trackPageview ('/outbound/longurl.org');">LongURL</a>, and a productive two weeks at that! Last Monday I officially launched the service (which provides a handy REST API) with support for a dozen or so shortening services like TinyURL.com. Once I stepped away from the problem for a little while I realized there was a better way to go about solving it. Thankfully the way I designed the service didn&#8217;t make it very difficult to swap out that bit of business logic, so this week I rolled-out an update that adds support for <strong>all</strong> shortening services.</p>
<p>After getting feedback from some helpful beta testers (thanks <a href="http://marjoleinkatsma.com/personal/cv.html" onclick="javascript:pageTracker._trackPageview ('/outbound/marjoleinkatsma.com');">Marjolein</a> and <a href="http://forteller.net" onclick="javascript:pageTracker._trackPageview ('/outbound/forteller.net');">Børge</a>!) and making a few tweaks I was happy yesterday to release the LongURL Mobile Expander <a href="http://userscripts.org/scripts/show/32115" onclick="javascript:pageTracker._trackPageview ('/outbound/userscripts.org');">Greasemokey script</a> and <a href="https://addons.mozilla.org/en-US/firefox/addon/8636" onclick="javascript:pageTracker._trackPageview ('/outbound/addons.mozilla.org');">Firefox extension</a> which use the LongURL API to expand shortened URLs on <strong>any</strong> web page. I haven&#8217;t had much feedback from others yet, but for me personally, the extension tremendously improves my user experience. Sorry guys, no more rickrolling <em>me</em>!</p>
<p><span id="more-19"></span><br />
Also, with the release of the incredibly awesome <a href="http://labs.mozilla.com/2008/08/introducing-ubiquity/" onclick="javascript:pageTracker._trackPageview ('/outbound/labs.mozilla.com');">Ubiquity</a> extension from Mozilla Labs, I started work on a LongURL command which <strike>I hope to finish/release in the next day or so</strike> I just released. You can subscribe to the command from the <a href="http://longurl.org/tools" onclick="javascript:pageTracker._trackPageview ('/outbound/longurl.org');">LongURL Tools</a> page. Does that sound like something that would be of interest to you? Have any ideas on how you&#8217;d like it to work? If so, leave a comment.</p>
<p>I would like to mention too that this has been the first time I&#8217;ve really used the <a href="http://launchpad.net" onclick="javascript:pageTracker._trackPageview ('/outbound/launchpad.net');">launchpad.net</a> platform for managing my project. It&#8217;s been a super experience; I don&#8217;t know why I didn&#8217;t start using it sooner, especially since I&#8217;ve been so <a href="http://elliotmurphy.com" onclick="javascript:pageTracker._trackPageview ('/outbound/elliotmurphy.com');">close to it</a>. And bazaar? Well, let me just say that I&#8217;ll no longer be using Subversion as my VCS of choice. Bazaar rocks, and if you haven&#8217;t given it a try, I strongly suggest you do so. You won&#8217;t regret it.</p>
<p>A final note: as you can tell, I don&#8217;t always get around to blogging about cool stuff I&#8217;m working on right away (if at all), so if you&#8217;d like to get updates as soon as possible I suggest following me on Twitter (<a href="http://twitter.com/iamseanmurphy" onclick="javascript:pageTracker._trackPageview ('/outbound/twitter.com');">iamseanmurphy</a>) and/or identi.ca (<a href="http://identi.ca/seanmurphy" onclick="javascript:pageTracker._trackPageview ('/outbound/identi.ca');">seanmurphy</a>). 140 characters just seems so much more digestible to me.</p>


<p>Related posts:<ol><li><a href='http://iamseanmurphy.com/2008/10/10/longurl-integration-for-your-website/' rel='bookmark' title='Permanent Link: LongURL Integration For Your Website'>LongURL Integration For Your Website</a></li></ol></p>]]></content:encoded>
			<wfw:commentRss>http://iamseanmurphy.com/2008/08/28/longurlrestoring-order-to-the-universe/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
