<?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>Chris Chandler</title>
	<atom:link href="http://chrischandler.name/feed/" rel="self" type="application/rss+xml" />
	<link>http://chrischandler.name</link>
	<description>Squandering time as a raving egomaniac</description>
	<lastBuildDate>Thu, 03 Jun 2010 23:16:54 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Code Kata 19 as a MapReduce job for Hadoop</title>
		<link>http://chrischandler.name/java/code-kata-19-as-a-mapreduce-job-for-hadoop/</link>
		<comments>http://chrischandler.name/java/code-kata-19-as-a-mapreduce-job-for-hadoop/#comments</comments>
		<pubDate>Mon, 19 Apr 2010 03:08:34 +0000</pubDate>
		<dc:creator>Chris Chandler</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[hadoop]]></category>
		<category><![CDATA[kata]]></category>
		<category><![CDATA[mapreduce]]></category>

		<guid isPermaLink="false">http://chrischandler.name/?p=80</guid>
		<description><![CDATA[A discussion of one of the possible solution's to Dave Thomas's 19th code kata.  I formulated it as a fully-distributed MapReduce job for Hadoop. Excessive?  You bet.]]></description>
			<content:encoded><![CDATA[<p>I wanted to do a brief discussion of Dave Thomas&#8217;s <a href="http://codekata.pragprog.com/2007/01/kata_nineteen_w.html">19th Code Kata</a>.  The gist of the problem is that given a wordlist of words can you determine a path from a source word to an end word, changing only one letter at a time, such that every intermediate step is also a valid word in the dictionary.  For instance, the supplied example from &#8216;cat&#8217; to &#8216;dog&#8217; is: cat, cot, cog, dog.</p>
<p>The general idea behind these code katas is that they are designed to be well-formed coding exercises to give programmers a chance to stretch and develop new skills.  I&#8217;ve written more graph algorithms that run in a single-process space than I&#8217;d care to discuss (here&#8217;s a simple graph implementation I wrote to learn Google&#8217;s Go for instance <a href="http://github.com/cchandler/golang-datastructures">Go-lang datastructures</a> ), so I wanted to solve this one using a different paradigm of problem solving.</p>
<p>For this one I wanted to write it as a <a href="http://hadoop.apache.org/common/docs/current/mapred_tutorial.html">MapReduce job</a>.  I&#8217;m familiar with <a href="http://couchdb.apache.org/">CouchDB</a> and it&#8217;s built-in MapReduce implementation, but I wanted to go with something that worked in a fully-distributed mode as well as serve as practice for Hadoop.  I love all my NoSQL options.</p>
<p>The code for this discussion, as well as instructions to setup and run, is available at : <a href="http://github.com/cchandler/codekata19-mapreduce">codekata19-mapreduce</a>.</p>
<p>For the sake of discussion, let&#8217;s decompose the problem into two subproblems: graph construction and graph traversal.</p>
<p><strong>Problem 1 &#8211; Graph construction</strong></p>
<p>Given a list of words, we need to construct a graph such that every vertex is a valid word and every edge represents a valid single-letter transform to get to the next vertex.  To solve this using MapReduce we make the input set of data the wordlist.  The only &#8220;global&#8221; information that we need to pass around with the actual processing job is the dictionary so each JVM/Mapper in the system knows what constitutes a valid word (this is done using Hadoop&#8217;s DistributedCache mechanism).  The Map function will emit a key for every valid, single-step transform we can determine as valid.  So the output is essentially the edge-set of our graph.</p>
<p>The reduce function&#8217;s only job in this case is to make sure we don&#8217;t have duplicates and to format the data in a way such that we can use this MapReduce job&#8217;s output as the input to the next phase.  The final results of this will look something like:</p>
<pre>
cat   cog,<other words>|-1|WHITE|
</pre>
<p>with an intentional trailing pipe.</p>
<p>The code for this MapReduce job is available here: <a href="http://github.com/cchandler/codekata19-mapreduce/blob/master/src/main/java/codekata19/CodeKata19.java">CodeKata19.java</a>.</p>
<p><strong>Problem 2 &#8211; Graph traversal</strong></p>
<p>Graph traversal in this case is a brute-force breadth-first search of the entire graph.  Cailin has done an excellent writeup of parallel, distributed breadth-first search at (<a href="http://www.johnandcailin.com/blog/cailin/breadth-first-graph-search-using-iterative-map-reduce-algorithm">Breadth-first graph search using iterative map reduce algorithm</a>).  The only modification I made to the proposed setup was including a complete path after the last pipe.  The algorithm will run until no more GRAY nodes exist in the network, meaning all reachable nodes from a selected start point have been reached.</p>
<p>It&#8217;s worth noting that instead of being the &#8220;fastest&#8221; implementation, which could easily fit inside a single-process space, this is more of an exercise in distributed algorithms.  One of the key advantages is that once this completes running we have the single-source, all-destination pair shortest path result.  The final result contains <strong>all</strong> shortest paths to all feasible solutions.</p>
<p>The code for this MapReduce job is available here: <a href="http://github.com/cchandler/codekata19-mapreduce/blob/master/src/main/java/codekata19/CodeKata19Search.java">CodeKata19Search.java</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://chrischandler.name/java/code-kata-19-as-a-mapreduce-job-for-hadoop/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using HBase&#8217;s Thrift interface with Ruby</title>
		<link>http://chrischandler.name/ruby/using-hbases-thrift-interface-with-ruby/</link>
		<comments>http://chrischandler.name/ruby/using-hbases-thrift-interface-with-ruby/#comments</comments>
		<pubDate>Fri, 23 Oct 2009 03:46:33 +0000</pubDate>
		<dc:creator>Chris Chandler</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[hbase]]></category>
		<category><![CDATA[thrift]]></category>

		<guid isPermaLink="false">http://chrischandler.name/?p=76</guid>
		<description><![CDATA[Using HBase's Thrift interface with Ruby the language and some basic examples.]]></description>
			<content:encoded><![CDATA[<p>In my continued fooling around with various key-value stores I&#8217;ve finally come across <a href="http://hadoop.apache.org/hbase/">HBase</a>.  Naturally, since I do my day-to-day programming in <a href="http://chrischandler.name/ruby/">Ruby</a> I wanted to setup some basic examples.  Though HBase does support a RESTful interface I thought I would get the <a href="http://incubator.apache.org/thrift/">Thrift</a> interface working for some better throughput.</p>
<p>If you need help Thrift running take a look at my post on <a href="http://chrischandler.name/ruby/using-cassandras-thrift-interface-with-ruby/">Cassandra&#8217;s thrift interface</a> that has all the prerequisites listed.</p>
<p>The example assumes a table &#8220;t1&#8243; and a column &#8220;f1&#8243;.</p>
<p><script src="http://gist.github.com/216619.js"></script></p>
]]></content:encoded>
			<wfw:commentRss>http://chrischandler.name/ruby/using-hbases-thrift-interface-with-ruby/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using Cassandra&#8217;s Thrift interface with Ruby</title>
		<link>http://chrischandler.name/ruby/using-cassandras-thrift-interface-with-ruby/</link>
		<comments>http://chrischandler.name/ruby/using-cassandras-thrift-interface-with-ruby/#comments</comments>
		<pubDate>Mon, 12 Oct 2009 03:47:35 +0000</pubDate>
		<dc:creator>Chris Chandler</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[cassandra]]></category>
		<category><![CDATA[snow leopard]]></category>
		<category><![CDATA[thrift]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://chrischandler.name/?p=70</guid>
		<description><![CDATA[A quick example of how to use Cassandra's Thrift interface to connect with Ruby]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;ve been trying to figure out how to work with <a href="incubator.apache.org/cassandra">Cassandra</a> then you&#8217;ve probably come across <a href="http://incubator.apache.org/thrift">Thrift</a>.  Thrift is a library written in the spirit of <a href="http://code.google.com/apis/protocolbuffers/">Google&#8217;s protocol buffers</a>, but developed by Facebook and then open-sourced in 2007.  The quick and short of it is that Thrift enables you to create RPC style calls in a platform-independent and XML-free way that is extremely efficient and surprisingly easy to work with once you get all the pieces working.</p>
<p><a href="http://jetfar.com">Rich Atkinson</a> already has a great blog post on how to get up and running with Thrift on <a href="http://jetfar.com/installing-cassandra-and-thrift-on-snow-leopard-a-quick-start-guide/">Snow Leopard</a>.  So if that&#8217;s what you&#8217;re running, I&#8217;m going to suggest you check it out.  If you&#8217;re running Ubuntu you&#8217;ll need to satisfy the following dependencies:</p>
<pre>sudo aptitude -q -y install libexpat1-dev libboost1.37-dev g++ autoconf automake libtool</pre>
<p>and the source can be obtained with:</p>
<pre>svn co http://svn.apache.org/repos/asf/incubator/thrift/trunk thrift</pre>
<p>and then you can proceed with the standard &#8220;configure &#038;&#038; make &#038;&#038; make install&#8221;.</p>
<p>Hopefully at this point you have the Thrift native libraries installed.  Since this is about Ruby, you should also install the Thrift gem that will take advantage of the native libraries.</p>
<pre>sudo gem install thrift</pre>
<p>Armed with both native library and gem, let&#8217;s go ahead and navigate to your Cassandra install&#8217;s interface directory (cassandra/interface) and build the ruby code:</p>
<pre>thrift --gen rb:new_style cassandra.thrift</pre>
<p>This will generate (as of this writing&#8230;) three files: gen-rb/cassandra.rb, gen-rb/cassandra_constants.rb, and gen-rb/cassandra_types.rb.  At this point you can create a temp.rb file in the gen-rb folder to play around with connections.  Here&#8217;s a short example of how to make a GET request for a specific key:</p>
<p><script src="http://gist.github.com/208103.js"></script></p>
<p>It&#8217;s worth noting that there *is* a gem available on github from <a href="http://github.com/fauna/cassandra">fauna/cassandra</a> that creates a much easier-to-work-with client, but since the interface for Cassandra is still evolving and changing the client is broken at the moment.  As far as I know this only applies to Cassandra 0.4.1 DEV and newer.  I&#8217;m very much looking forward to a working update.</p>
]]></content:encoded>
			<wfw:commentRss>http://chrischandler.name/ruby/using-cassandras-thrift-interface-with-ruby/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Provisioning script for Ubuntu Intrepid and Ruby 1.9.1</title>
		<link>http://chrischandler.name/ruby/provisioning-script-for-ubuntu-intrepid-and-ruby-1-9-1/</link>
		<comments>http://chrischandler.name/ruby/provisioning-script-for-ubuntu-intrepid-and-ruby-1-9-1/#comments</comments>
		<pubDate>Sat, 03 Oct 2009 01:16:28 +0000</pubDate>
		<dc:creator>Chris Chandler</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[easy]]></category>
		<category><![CDATA[ec2]]></category>
		<category><![CDATA[provisioning]]></category>
		<category><![CDATA[setup]]></category>
		<category><![CDATA[slicehost]]></category>
		<category><![CDATA[ubuntu intrepid]]></category>

		<guid isPermaLink="false">http://chrischandler.name/?p=66</guid>
		<description><![CDATA[A simple provisioning script for setting up a standard Rails stack based on Ruby 1.9.1 for Ubuntu Intrepid.]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a simple gist I use to provision either <a href="http://aws.amazon.com/ec2/">Amazon EC2</a> AMIs or <a href="http://slicehost.com">Slicehost</a> images running Ubuntu Intrepid.  It&#8217;ll setup all the requirements to build Ruby 1.9.1 from source since the official Ubuntu package isn&#8217;t due out until <a href="https://wiki.ubuntu.com/KarmicKoala">Karmic Koala</a> is released.</p>
<p>It has a handful of constants at the top of the file you need to define for everything to work right.  Of note are the application name and the machine&#8217;s FQDN it should answer on.  If your using EC2 you might have to tweak some configuration afterward since the FQDN in DNS probably won&#8217;t match the IP of the machine&#8217;s interface.</p>
<p>Also, if you plan on using authorized_keys and deploying from a git repository it makes things a lot easier if you tar and gzip the relevant files and put them in an S3 bucket to pull from.  The script handles this case as well.</p>
<p><script src="http://gist.github.com/200289.js"></script></p>
<p>As always, make sure you understand what a provisioning script does before you accept it with blind faith.  At <a href="http://flatterline.com">Flatterline</a> we use this as our base template.</p>
]]></content:encoded>
			<wfw:commentRss>http://chrischandler.name/ruby/provisioning-script-for-ubuntu-intrepid-and-ruby-1-9-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symmetric indices to make JOINs faster</title>
		<link>http://chrischandler.name/ruby/symmetric-indices-to-make-joins-faster/</link>
		<comments>http://chrischandler.name/ruby/symmetric-indices-to-make-joins-faster/#comments</comments>
		<pubDate>Wed, 23 Sep 2009 08:10:03 +0000</pubDate>
		<dc:creator>Chris Chandler</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[btrees]]></category>
		<category><![CDATA[explain]]></category>
		<category><![CDATA[index]]></category>
		<category><![CDATA[join]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[rails]]></category>

		<guid isPermaLink="false">http://chrischandler.name/?p=57</guid>
		<description><![CDATA[Has-and-belongs-to-many relationships are quite common, but they require some special database/index love to make sure their performance stays up as data volume increases.]]></description>
			<content:encoded><![CDATA[<p>I am frequently asked how to increase the performance of Rails, and here&#8217;s a great starting point.  This advice generalizes to just about any database or platform that relies on B-Tree indices.  If your using MySQL out of the box, then this definitely applies.</p>
<p>Consider the following three models which are a very basic &#8220;has and belongs to many&#8221; setup:</p>
<p><script src="http://gist.github.com/191818.js"></script></p>
<p>So as you can see, a user can be in many groups and a group can have many users, all by way of the memberships join relationship.</p>
<p>The two example use cases I&#8217;m going to work with are:</p>
<ol>
<li>Given a user, what groups is he/she in?, and</li>
<li>Given a group, who are the members? </li>
</ol>
<p>Both of these are pretty typical, but can yield surprisingly different results from the database&#8217;s perspective.  If we try and get this data from the console we either start with a user and navigate to group, or the reverse.  Here&#8217;s the MySQL EXPLAIN output from the console ( I recommend viewing the RAW output unless I can figure out how to make github display it correctly):</p>
<p><script src="http://gist.github.com/191820.js"></script></p>
<p>Totally understanding the output of the EXPLAIN syntax is well outside the scope of this post, but we&#8217;re going to need to cover the basics.  The first thing you should notice is the word ALL in the type column and the NULL in possible_keys.  This indicates that MySQL&#8217;s query optimizer has no index to read from and will be forced to perform a table scan to return the result.  In general, this will kill your performance.  Note the rows value of 100.  This value will be whatever the size of your table is.  If you have 500,000 records, then the database will check all 500,000 rows.</p>
<p><em>It&#8217;s worth noting that for small datasets you&#8217;ll see ALL and a possible_keys value.  This means the optimizer believes that scanning the table will be faster than actually loading the index into memory.  This is generally fine.</em></p>
<p>So let&#8217;s go ahead and add a composite index on [user_id,group_id].  The SQL is:</p>
<pre>ALTER TABLE memberships ADD INDEX test_index(user_id,group_id)</pre>
<p>Now let&#8217;s repeat the previous queries.</p>
<p><script src="http://gist.github.com/191821.js"></script></p>
<p>This is where I see most people stop when it comes to performance optimization.  Note though that these tables aren&#8217;t the same!  If you join from users to groups (the first query) you see a massive speedup.  Only one row is consulted (instead of 100) and it&#8217;s in the index.  A further benefit we see in both queries is the &#8220;Using index&#8221; in the Extra column.  This means that MySQL can determine the query result without ever checking the actual table because all required info is in the index (ie no extra disk hits).  Unfortunately, joining from groups to users (second query) still (sorta) sucks.  It says index instead of ALL, but that just means it will have to scan the entire index rather than scan the entire table on disk.  This is a marginal improvement at best, so 50% of our use cases still suck.</p>
<p>Here&#8217;s the explanation: B-Tree indices are unidimensional structures.  That means that the interior nodes of the index tree are strongly ordered, and thus cannot be arbitrarily accessed out of order.  If that doesn&#8217;t make any sense, it means that joining from users to groups is not an equivalent operation to joining groups to users because of the ordering of the index elements.</p>
<p>So let&#8217;s cleanup the second use case by adding an additional index, exactly like the first, except the order of the elements is reversed.  Here&#8217;s the SQL: </p>
<pre>ALTER TABLE memberships ADD INDEX test_index1(group_id,user_id)</pre>
<p>Now we have symmetric indices.  Let&#8217;s run our queries again with our second index in place:</p>
<p><script src="http://gist.github.com/191823.js"></script></p>
<p>Voila!  Now it doesn&#8217;t matter which way we join the tables because we have an index that is correctly ordered based on the directionality of the join.  You can even see that the optimizer selects a different index (key) depending on which direction you join the tables, exactly as expected.  Also, both queries now only require consulting the exact number of rows necessary and won&#8217;t involve any further disk hits as both queries can be satisfied with data available entirely within the index.</p>
]]></content:encoded>
			<wfw:commentRss>http://chrischandler.name/ruby/symmetric-indices-to-make-joins-faster/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Ubuntu JeOS</title>
		<link>http://chrischandler.name/linux/ubuntu-jeos/</link>
		<comments>http://chrischandler.name/linux/ubuntu-jeos/#comments</comments>
		<pubDate>Sat, 19 Sep 2009 00:35:53 +0000</pubDate>
		<dc:creator>Chris Chandler</dc:creator>
				<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://chrischandler.name/?p=54</guid>
		<description><![CDATA[Ubuntu JeOS is a ridiculously handy little VM-specialized server installation for creating super simple virtual machines for specific purposes.]]></description>
			<content:encoded><![CDATA[<p>If you do anything on virtual machines, linux or not, then you should definitely checkout <a href="http://www.ubuntu.com/products/whatisubuntu/serveredition/jeos">Ubuntu JeOS</a> (pronounced &#8220;juice&#8221;).</p>
<p>JeoS is shorthand for &#8220;just enough operating system.&#8221;  It&#8217;s a simple short install process that&#8217;s hidden in the server installation ISO.  On the startup you just have to press F4 and select &#8220;Minimal virtual machine&#8221;.  Rather than installing the entire Ubuntu server package you get an extremely pruned-down version that only includes the absolute bare essentials to get a server running.  If your like me and believe that VMs should be created for a singular purpose only, then it will make your life even easier to create a bunch of small VMs.  According to their specs you should expect something like 380MB disk images running in about 128MB of RAM.</p>
]]></content:encoded>
			<wfw:commentRss>http://chrischandler.name/linux/ubuntu-jeos/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Entrepreneurs: regarding equity to developers</title>
		<link>http://chrischandler.name/culture/entrepreneurs-regarding-equity-to-developers/</link>
		<comments>http://chrischandler.name/culture/entrepreneurs-regarding-equity-to-developers/#comments</comments>
		<pubDate>Mon, 10 Aug 2009 23:40:49 +0000</pubDate>
		<dc:creator>Chris Chandler</dc:creator>
				<category><![CDATA[Culture]]></category>
		<category><![CDATA[entrepreneurship]]></category>
		<category><![CDATA[equity]]></category>
		<category><![CDATA[startups]]></category>

		<guid isPermaLink="false">http://chrischandler.name/?p=43</guid>
		<description><![CDATA[An open letter to would-be entrepreneurs everywhere about why shouldn't be offering equity out of the gate to new developers.]]></description>
			<content:encoded><![CDATA[<p>Dear enthusiastic entrepreneur,</p>
<p>I would like first and foremost to wish you well on your endeavor.<br />
Starting a business is no small feat and you will certainly need all<br />
the help you can get to bring your idea to life. That being said,<br />
let&#8217;s talk about money.</p>
<p>You will require money if you plan on developing software. If you&#8217;ve<br />
considered finding and asking a developer for his or her time in<br />
exchange for sweat equity, I&#8217;m going to strongly advise you against<br />
it. Not only are these requests often derided, they are often<br />
insulting to the developer. Worse yet, they make you appear an amateur<br />
with little understanding of how the technology field and development<br />
works.</p>
<p>In the words of the Joker, &#8220;If you&#8217;re good at something, never do it<br />
for free.&#8221; All the engineers I trust to execute a project swiftly,<br />
professionally and with quality, especially under startup conditions,<br />
will not touch an upfront equity deal with a 10-foot pole. They<br />
understand not only the value of their abilities, but that they could<br />
just as easily band together and make their own startup. A common<br />
trait among these engineers is an understanding of their own<br />
entrepreneurial value. Investing time in your goals, when they could<br />
be developing their own, comes across as a high opportunity cost with<br />
an extremely unlikely payoff. As great as you think your idea may be,<br />
90% of startups still fail.</p>
<p>If you&#8217;ve ever tried to secure external business funding, whether it<br />
be angel or venture based, then you know that there&#8217;s most likely<br />
weeks of negotiation coupled with presentations, milestones and the<br />
unmistakable feeling that you&#8217;re in a fish bowl being watched. This<br />
shouldn&#8217;t come as a surprise since you&#8217;re asking someone for a large<br />
sum of money. The lender wants to see mitigated risk as well as<br />
receive some ownership for their money. Equity to a developer works<br />
the same way, except it&#8217;s often approached as hiring an employee<br />
instead of bringing on an investor. Be prepared with your business<br />
plan, term sheet, and probably a beer. An &#8220;I&#8217;m giving you the<br />
opportunity to get in on the ground floor&#8221; attitude is going to make<br />
you the target of contempt.</p>
<p>So when is equity OK? It will vary depending on the unique situation<br />
of the developer, but a good rule of thumb would be to not offer it<br />
until AFTER you&#8217;ve developed a successful working relationship in<br />
which you have demonstrated your ability to execute your business<br />
plan. Your stock options are worth zero until you successfully exit<br />
and, even then, only if the strike price is better than market value.<br />
Proof of execution is what matters today, not ideas. It&#8217;s not that<br />
somebody is working for free, it&#8217;s that they&#8217;re working for a better<br />
long-term payoff. A payoff which you must prove is likely to happen.<br />
Also, just like an investment, the more risk that&#8217;s on the table at<br />
the time of the offer, the more of your company you should be prepared<br />
to part with. If you offer a fractional percentage, don&#8217;t expect a<br />
call back.</p>
<p>It&#8217;s going to be a rough road, as it is with all startups, and I wish<br />
you the best of luck in your venture.</p>
<p>-Chris</p>
]]></content:encoded>
			<wfw:commentRss>http://chrischandler.name/culture/entrepreneurs-regarding-equity-to-developers/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Converting latitude and longitude to timezones</title>
		<link>http://chrischandler.name/ruby/converting-latitude-and-longitude-to-timezones/</link>
		<comments>http://chrischandler.name/ruby/converting-latitude-and-longitude-to-timezones/#comments</comments>
		<pubDate>Wed, 29 Jul 2009 07:16:04 +0000</pubDate>
		<dc:creator>Chris Chandler</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[geolocation]]></category>
		<category><![CDATA[l10n]]></category>
		<category><![CDATA[timezones]]></category>

		<guid isPermaLink="false">http://chrischandler.name/?p=39</guid>
		<description><![CDATA[A quick method for converting a latitude and longitude coordinate pair into a timezone.]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;ve fought it out with <a href="http://en.wikipedia.org/wiki/Internationalization_and_localization">localization</a>(l10n) of timezones then you know it can be a pain in the ass.  Further, suppose your localizing arbitrary information where all you&#8217;ve really been given is an address.  The relevant information isn&#8217;t necessarily in your system and the user might be in the wrong timezone anyway, so no sense in using that.</p>
<p>Here&#8217;s a quick Ruby means to convert latitude and longitude into a timezone <a title="ActiveSupport" href="http://as.rubyonrails.org/">ActiveSupport</a> recognizes.  This snippet only relies on <a title="Hpricot" href="http://wiki.github.com/why/hpricot/hpricot-xml">Hpricot</a> and the freely available <a title="Geonames" href="http://www.geonames.org/">Geonames</a> API:</p>
<p><script src="http://gist.github.com/157902.js"></script></p>
<p>GMT offsets are a convenient way for moving time data in and out of UTC as well as for not having to deal with arbitrary string names.</p>
]]></content:encoded>
			<wfw:commentRss>http://chrischandler.name/ruby/converting-latitude-and-longitude-to-timezones/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>basic erlang clustering</title>
		<link>http://chrischandler.name/erlang/basic-erlang-clustering/</link>
		<comments>http://chrischandler.name/erlang/basic-erlang-clustering/#comments</comments>
		<pubDate>Sat, 25 Jul 2009 23:34:10 +0000</pubDate>
		<dc:creator>Chris Chandler</dc:creator>
				<category><![CDATA[Erlang]]></category>
		<category><![CDATA[clustering]]></category>
		<category><![CDATA[magic cookie]]></category>
		<category><![CDATA[nodes]]></category>

		<guid isPermaLink="false">http://chrischandler.name/?p=27</guid>
		<description><![CDATA[Clustering is one of the most compelling reasons to use Erlang.  Take a look at this basic example showing what it takes to connect multiple Erlang nodes to distribute work.]]></description>
			<content:encoded><![CDATA[<p>One of the strongest reasons to consider <a title="Erlang" href="http://chrischandler.name/erlang">Erlang</a> for a programming project is concurrency.  Erlang makes concurrency and distributed work dead simple.</p>
<p>If you have two nodes, <em>nodex</em> and <em>nodey</em> , and you want to be able to do something on both you can start the Erlang shell on nodex with the following:</p>
<pre>erl -setcookie someFormOfPreSharedSecret -name nodex</pre>
<p>and a similar command on nodey</p>
<pre>erl -setcookie someFormOfPreSharedSecret -name nodey</pre>
<p>The key here is to make sure that both nodes have the same magic cookie value, otherwise they won&#8217;t be able to communicate.</p>
<p>From nodex issue <em>net_adm:ping(&#8216;nodey@your_domain_here.com&#8217;)</em>.  If the connection was successful you&#8217;ll see the result pong, if something didn&#8217;t go right, you&#8217;ll see pang.  From this point, you can run:</p>
<pre>nodes().</pre>
<p>and see every node your currently connected with.</p>
<p>Now for the magic, let&#8217;s say you want to start a particular task running on all of your nodes.  We&#8217;re going to achieve this by using the lists:foldl function:</p>
<p><script src="http://gist.github.com/155217.js"></script> Foldl takes 3 arguments: an anonymous function to call for every element of the third parameter, an accumulator to pass to the anonymous function, and the the list of things to iterate over.  If your more familiar with Ruby this would hypothetically look like:  <script src="http://gist.github.com/155225.js"></script></p>
<p>The key difference being Ruby doesn&#8217;t return Pids to later refer back to those concurrent processes we started.</p>
<p>After running the Erlang example every node will run io:format and print a simple message.  That&#8217;s really all there is to distributing Erlang processing power.  By retaining a list of the remote Pids you can do neat tricks with firing up a good number of initial processes and then sending them subsequent messages.  I&#8217;ll make a valiant effort to write about this more.</p>
]]></content:encoded>
			<wfw:commentRss>http://chrischandler.name/erlang/basic-erlang-clustering/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>View collation for join-like behavior in CouchDB</title>
		<link>http://chrischandler.name/couchdb/view-collation-for-join-like-behavior-in-couchdb/</link>
		<comments>http://chrischandler.name/couchdb/view-collation-for-join-like-behavior-in-couchdb/#comments</comments>
		<pubDate>Sun, 18 Jan 2009 23:53:50 +0000</pubDate>
		<dc:creator>Chris Chandler</dc:creator>
				<category><![CDATA[CouchDB]]></category>
		<category><![CDATA[collation]]></category>
		<category><![CDATA[nosql]]></category>

		<guid isPermaLink="false">http://squanderingtime.com/?p=19</guid>
		<description><![CDATA[Quick overview of document collation in CouchDB for combining heterogeneous documents in the reduce phase.]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;ve been playing with CouchDB then you have probably run into the problem of having multiple documents that share a relationship, yet are complex enough that denormalizing them together doesn&#8217;t make sense.</p>
<p>For the sake of example let&#8217;s assume we have <em>Authors</em> and <em>Posts</em>.  Further, let&#8217;s assume that an Author has many Posts and that these are represented as independent documents.  The goal here is to find posts created by a specific author.</p>
<p>In SQL, this would probably be represented as a table of authors and a table posts.  Getting the aggregate result would be something along the lines of:</p>
<p><code>SELECT * from authors join posts ON authors.id = posts.author_id</code></p>
<p>This is just a simple standard JOIN, nothing very interesting about it.  However, in a document oriented system this &#8220;join&#8221; operation doesn&#8217;t really exist.  Enter view collation.</p>
<p>View collation allows us to define a map/reduce function pair that takes in multiple document types, aggregates them onto a single key value, and gives us a means to search on author id.</p>
<p>Let&#8217;s say we have an author document like the following:</p>
<p><code><br />
{'type' : 'author', 'name' : 'Chris Chandler', '_id' : '22d43eaa7e06c9c37ed3e0489401a506' }<br />
</code></p>
<p>and some  number of post documents similar to:</p>
<p><code><br />
{'type' : 'post', 'title' : 'Hello world', 'Body' : 'body text', 'Author' : '22d43eaa7e06c9c37ed3e0489401a506'  }<br />
</code></p>
<p>In this case our &#8220;foreign key&#8221; is 22d43eaa7e06c9c37ed3e0489401a506.  The mapping function would need to connect these records based on that key is something like the following:<br />
<code><br />
function(doc) {<br />
if(doc.type == 'author')<br />
{<br />
emit(doc._id , doc);<br />
}<br />
else if(doc.type == 'post')<br />
{<br />
emit(doc.author, doc);<br />
}<br />
}<br />
</code></p>
<p>This view will generate an intermediate hash table containing entries with the author&#8217;s key.  In essence we have one key (the author&#8217;s) pointing to either a post the author has created, or the author&#8217;s record itself.  To make this view answer the question &#8216;Show me all posts created by a certain author&#8217; we need to write a reduce function that removes the unnecessary author records so the final table will only contain author keys pointing to lists of posts.</p>
<p><code><br />
function(keys, values, rereduce)<br />
{<br />
var posts = [];<br />
for(var i = 0; i &lt; values.length; i++)<br />
{<br />
if(values[i].type == 'post')<br />
{<br />
posts.push(values[i]);<br />
}<br />
}</code></p>
<p><code><br />
return posts;<br />
}<br />
</code></p>
<p>The final result set appears as:<br />
<code><br />
"22d43eaa7e06c9c37ed3e0489401a506"<br />
[{_id: "d0d0ea6de45c9f4ff983f12a9fed9008", _rev: "2624588756", body: "Weee!", title: "Hello world 2", author: "22d43eaa7e06c9c37ed3e0489401a506", type: "post"}, {_id: "9de65ae955ecc2ea35055b9339f1651c", _rev: "2347078231", body: "Weee!", title: "Hello world", author: "22d43eaa7e06c9c37ed3e0489401a506", type: "post"}, {_id: "5d1ad3eed26f84879835fd47e44f7f55", _rev: "1163133569", body: "Weee!", title: "Hello world 2", author: "22d43eaa7e06c9c37ed3e0489401a506", type: "post"}, {_id: "0717ae0da9bf5919da0957268667c3f4", _rev: "1063237208", body: "Weee!", title: "Hello world 3", author: "22d43eaa7e06c9c37ed3e0489401a506", type: "post"}]</code></p>
]]></content:encoded>
			<wfw:commentRss>http://chrischandler.name/couchdb/view-collation-for-join-like-behavior-in-couchdb/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>
