<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Daniel O'Shea Blog Posts</title>
 <link href="http://danieloshea.com/feed.xml" rel="self"/>
 <link href="http://danieloshea.com/"/>
 <updated>2012-01-22T10:37:43-08:00</updated>
 <id>http://danieloshea.com.com/</id>
 <author>
   <name>Daniel O'Shea</name>
   <email>hello+blog@danieloshea.com</email>
 </author>

 
 <entry>
   <title>Determining Changes in Data Across Machines Efficiently with a Merkle Tree</title>
   <link href="http://danieloshea.com/2011/12/07/merkle-tree.html"/>
   <updated>2011-12-07T00:00:00-08:00</updated>
   <id>http://danieloshea.com/2011/12/07/merkle-tree</id>
   <content type="html">&lt;h1 id='determining_changes_in_data_across_machines_efficiently_with_a_merkle_tree'&gt;Determining Changes in Data Across Machines Efficiently with a Merkle Tree&lt;/h1&gt;

&lt;h2 id='introduction'&gt;Introduction&lt;/h2&gt;

&lt;p&gt;When you have data distributed on multiple machines, you often want to be able to ensure that the data on one computer is the same as data on another. There are several scenarios where knowing the set of data across machines is in sync. In this article we will build a straight forward implementation of a Merkle tree that can be used to efficiently compute the differences in a set of data between multiple computers.&lt;/p&gt;

&lt;h2 id='a_what_tree'&gt;A What Tree?&lt;/h2&gt;

&lt;p&gt;A &lt;a href='http://www.google.com/patents?id=Dd4zAAAAEBAJ&amp;amp;printsec=abstract&amp;amp;zoom=4&amp;amp;source=gbs_overview_r&amp;amp;cad=0#v=onepage&amp;amp;q&amp;amp;f=false'&gt;Merkle Tree&lt;/a&gt; is a data structure that allows the efficient comparison of a series of elements to find differences. They are used in distributed systems when you need to be able to efficiently find differences between machines without having to transmit the entire data set. They can also be used to efficiently check that a set of files or one very large file has not been modified in transit. For example in a peer to peer scenario, you can query a trusted host to ensure that the data you are receiving from a peer has not been modified.&lt;/p&gt;

&lt;h2 id='how_do_they_work'&gt;How Do They Work&lt;/h2&gt;

&lt;p&gt;Let&amp;#8217;s start with a simple example. Suppose you have two computers each running the same program. You want modifications made to the data on one computer to be reflected on the other. You are happily transmitting changes from one machine to the other when one of the machines crashes, or goes offline due to networking issues. When the second machine is reachable again, you want to only transmit the data that is missing or different. A Merkle Tree will help you do just that.&lt;/p&gt;

&lt;p&gt;Before we dive into the actual Merkle tree implementation, let&amp;#8217;s do the simple naive implementation. You could compute a hash function for every element in the set and transmit those hashes between machines. This will result in transmitting the hash for every element in the set and for a large number of elements we would like to transmit the minimum amount of data.&lt;/p&gt;

&lt;p&gt;To do that, we will build a Merkle Tree. A Merkle tree is a special binary tree where only the leaf nodes hold values, the other nodes in the tree are for searching, but we&amp;#8217;ll get to that later.&lt;/p&gt;

&lt;p&gt;To construct the tree we will start with the root and then build a tree based on the number of leaf nodes we will have. For now, let&amp;#8217;s assume that eight leaves are sufficient, then we need a tree of height 3 (remember 2^3 = 8). We construct our balanced binary tree recursively at each level until we reach a leaf nodes. This results in a tree that looks like the one in the diagram below:&lt;/p&gt;
&lt;svg version='1.1' height='229pt' viewBox='125 256 327 229' xmlns:xl='http://www.w3.org/1999/xlink' xmlns='http://www.w3.org/2000/svg' width='327pt'&gt;&lt;metadata xmlns:dc='http://purl.org/dc/elements/1.1/'&gt;&lt;dc:date&gt;2011-12-19 03:46Z&lt;/dc:date&gt;&lt;!-- Produced by OmniGraffle Professional 5.3.6 --&gt;&lt;/metadata&gt;&lt;defs&gt;&lt;filter filterUnits='userSpaceOnUse' id='Shadow'&gt;&lt;feGaussianBlur result='blur' stdDeviation='3.488' in='SourceAlpha' /&gt;&lt;feOffset result='offset' in='blur' dx='0' dy='4' /&gt;&lt;feFlood result='flood' flood-opacity='.75' flood-color='black' /&gt;&lt;feComposite in2='offset' in='flood' operator='in' /&gt;&lt;/filter&gt;&lt;font-face font-size='12' units-per-em='1000' slope='0' font-weight='500' underline-position='-75.683594' underline-thickness='49.316406' font-family='Helvetica' cap-height='717.28516' ascent='770.01953' descent='-229.98047' x-height='522.94922'&gt;&lt;font-face-src&gt;&lt;font-face-name name='Helvetica' /&gt;&lt;/font-face-src&gt;&lt;/font-face&gt;&lt;marker overflow='visible' markerHeight='8' orient='auto' id='FilledArrow_Marker' markerWidth='10' color='black' viewBox='-1 -4 10 8' markerUnits='strokeWidth'&gt;&lt;g&gt;&lt;path d='M 8 0 L 0 -3 L 0 3 Z' stroke='currentColor' fill='currentColor' stroke-width='1' /&gt;&lt;/g&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;g stroke-opacity='1' fill-opacity='1' stroke='none' fill='none' stroke-dasharray='none'&gt;&lt;title&gt;Canvas 1&lt;/title&gt;&lt;g&gt;&lt;title&gt;Layer 1&lt;/title&gt;&lt;g&gt;&lt;use xl:href='#id14_Graphic' filter='url(#Shadow)' /&gt;&lt;use xl:href='#id15_Graphic' filter='url(#Shadow)' /&gt;&lt;use xl:href='#id16_Graphic' filter='url(#Shadow)' /&gt;&lt;use xl:href='#id17_Graphic' filter='url(#Shadow)' /&gt;&lt;use xl:href='#id18_Graphic' filter='url(#Shadow)' /&gt;&lt;use xl:href='#id19_Graphic' filter='url(#Shadow)' /&gt;&lt;use xl:href='#id20_Graphic' filter='url(#Shadow)' /&gt;&lt;use xl:href='#id21_Graphic' filter='url(#Shadow)' /&gt;&lt;use xl:href='#id22_Graphic' filter='url(#Shadow)' /&gt;&lt;use xl:href='#id23_Graphic' filter='url(#Shadow)' /&gt;&lt;use xl:href='#id24_Graphic' filter='url(#Shadow)' /&gt;&lt;use xl:href='#id25_Graphic' filter='url(#Shadow)' /&gt;&lt;use xl:href='#id26_Graphic' filter='url(#Shadow)' /&gt;&lt;use xl:href='#id27_Graphic' filter='url(#Shadow)' /&gt;&lt;use xl:href='#id28_Graphic' filter='url(#Shadow)' /&gt;&lt;/g&gt;&lt;g id='id14_Graphic'&gt;&lt;circle cy='282.504' fill='#f66' r='10.000017' cx='288.008' /&gt;&lt;circle cy='282.504' stroke-linecap='round' stroke='black' r='10.000017' stroke-width='1' cx='288.008' stroke-linejoin='round' /&gt;&lt;text transform='translate(285.008 275.504)' fill='black'&gt;&lt;tspan font-size='12' font-weight='500' x='0' y='11' font-family='Helvetica' fill='black' textLength='8.0039062'&gt;A&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g id='id15_Graphic'&gt;&lt;circle cy='338.504' fill='#ff6' r='10.0000143' cx='250.008' /&gt;&lt;circle cy='338.504' stroke-linecap='round' stroke='black' r='10.0000143' stroke-width='1' cx='250.008' stroke-linejoin='round' /&gt;&lt;text transform='translate(247.00801 331.504)' fill='black'&gt;&lt;tspan font-size='12' font-weight='500' x='0' y='11' font-family='Helvetica' fill='black' textLength='8.0039062'&gt;B&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g id='id16_Graphic'&gt;&lt;circle cy='394.504' fill='#ff6' r='10.0000095' cx='193.00801' /&gt;&lt;circle cy='394.504' stroke-linecap='round' stroke='black' r='10.0000095' stroke-width='1' cx='193.00801' stroke-linejoin='round' /&gt;&lt;text transform='translate(190.00801 387.504)' fill='black'&gt;&lt;tspan font-size='12' font-weight='500' x='0' y='11' font-family='Helvetica' fill='black' textLength='8.6660156'&gt;D&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g id='id17_Graphic'&gt;&lt;circle cy='394.504' fill='#ff6' r='10.0000143' cx='250.008' /&gt;&lt;circle cy='394.504' stroke-linecap='round' stroke='black' r='10.0000143' stroke-width='1' cx='250.008' stroke-linejoin='round' /&gt;&lt;text transform='translate(247.00801 387.504)' fill='black'&gt;&lt;tspan font-size='12' font-weight='500' x='0' y='11' font-family='Helvetica' fill='black' textLength='8.0039062'&gt;E&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g id='id18_Graphic'&gt;&lt;circle cy='338.504' fill='#ff6' r='10.000017' cx='326.008' /&gt;&lt;circle cy='338.504' stroke-linecap='round' stroke='black' r='10.000017' stroke-width='1' cx='326.008' stroke-linejoin='round' /&gt;&lt;text transform='translate(323.008 331.504)' fill='black'&gt;&lt;tspan font-size='12' font-weight='500' x='0' y='11' font-family='Helvetica' fill='black' textLength='8.6660156'&gt;C&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g id='id19_Graphic'&gt;&lt;circle cy='394.504' fill='#ff6' r='10.000017' cx='326.008' /&gt;&lt;circle cy='394.504' stroke-linecap='round' stroke='black' r='10.000017' stroke-width='1' cx='326.008' stroke-linejoin='round' /&gt;&lt;text transform='translate(323.008 387.504)' fill='black'&gt;&lt;tspan font-size='12' font-weight='500' x='0' y='11' font-family='Helvetica' fill='black' textLength='7.330078'&gt;F&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g id='id20_Graphic'&gt;&lt;circle cy='394.504' fill='#ff6' r='10.000017' cx='383.008' /&gt;&lt;circle cy='394.504' stroke-linecap='round' stroke='black' r='10.000017' stroke-width='1' cx='383.008' stroke-linejoin='round' /&gt;&lt;text transform='translate(380.008 387.504)' fill='black'&gt;&lt;tspan font-size='12' font-weight='500' x='0' y='11' font-family='Helvetica' fill='black' textLength='9.3339844'&gt;G&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g id='id21_Graphic'&gt;&lt;circle cy='450.504' fill='#cf6' r='10.0000095' cx='155.00801' /&gt;&lt;circle cy='450.504' stroke-linecap='round' stroke='black' r='10.0000095' stroke-width='1' cx='155.00801' stroke-linejoin='round' /&gt;&lt;text transform='translate(152.00801 443.504)' fill='black'&gt;&lt;tspan font-size='12' font-weight='500' x='0' y='11' font-family='Helvetica' fill='black' textLength='6.673828'&gt;1&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g id='id22_Graphic'&gt;&lt;circle cy='450.504' fill='#cf6' r='10.0000095' cx='193.00801' /&gt;&lt;circle cy='450.504' stroke-linecap='round' stroke='black' r='10.0000095' stroke-width='1' cx='193.00801' stroke-linejoin='round' /&gt;&lt;text transform='translate(190.00801 443.504)' fill='black'&gt;&lt;tspan font-size='12' font-weight='500' x='0' y='11' font-family='Helvetica' fill='black' textLength='6.673828'&gt;2&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g id='id23_Graphic'&gt;&lt;circle cy='450.504' fill='#cf6' r='10.0000095' cx='231.00801' /&gt;&lt;circle cy='450.504' stroke-linecap='round' stroke='black' r='10.0000095' stroke-width='1' cx='231.00801' stroke-linejoin='round' /&gt;&lt;text transform='translate(228.00801 443.504)' fill='black'&gt;&lt;tspan font-size='12' font-weight='500' x='0' y='11' font-family='Helvetica' fill='black' textLength='6.673828'&gt;3&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g id='id24_Graphic'&gt;&lt;circle cy='450.504' fill='#cf6' r='10.000017' cx='269.008' /&gt;&lt;circle cy='450.504' stroke-linecap='round' stroke='black' r='10.000017' stroke-width='1' cx='269.008' stroke-linejoin='round' /&gt;&lt;text transform='translate(266.008 443.504)' fill='black'&gt;&lt;tspan font-size='12' font-weight='500' x='0' y='11' font-family='Helvetica' fill='black' textLength='6.673828'&gt;4&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g id='id25_Graphic'&gt;&lt;circle cy='450.504' fill='#cf6' r='10.000017' cx='307.008' /&gt;&lt;circle cy='450.504' stroke-linecap='round' stroke='black' r='10.000017' stroke-width='1' cx='307.008' stroke-linejoin='round' /&gt;&lt;text transform='translate(304.008 443.504)' fill='black'&gt;&lt;tspan font-size='12' font-weight='500' x='0' y='11' font-family='Helvetica' fill='black' textLength='6.673828'&gt;5&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g id='id26_Graphic'&gt;&lt;circle cy='450.504' fill='#cf6' r='10.000017' cx='345.008' /&gt;&lt;circle cy='450.504' stroke-linecap='round' stroke='black' r='10.000017' stroke-width='1' cx='345.008' stroke-linejoin='round' /&gt;&lt;text transform='translate(342.008 443.504)' fill='black'&gt;&lt;tspan font-size='12' font-weight='500' x='0' y='11' font-family='Helvetica' fill='black' textLength='6.673828'&gt;6&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g id='id27_Graphic'&gt;&lt;circle cy='450.504' fill='#cf6' r='10.000017' cx='383.008' /&gt;&lt;circle cy='450.504' stroke-linecap='round' stroke='black' r='10.000017' stroke-width='1' cx='383.008' stroke-linejoin='round' /&gt;&lt;text transform='translate(380.008 443.504)' fill='black'&gt;&lt;tspan font-size='12' font-weight='500' x='0' y='11' font-family='Helvetica' fill='black' textLength='6.673828'&gt;7&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g id='id28_Graphic'&gt;&lt;circle cy='450.504' fill='#cf6' r='10.000017' cx='421.008' /&gt;&lt;circle cy='450.504' stroke-linecap='round' stroke='black' r='10.000017' stroke-width='1' cx='421.008' stroke-linejoin='round' /&gt;&lt;text transform='translate(418.008 443.504)' fill='black'&gt;&lt;tspan font-size='12' font-weight='500' x='0' y='11' font-family='Helvetica' fill='black' textLength='6.673828'&gt;8&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;line stroke-linecap='round' marker-end='url(#FilledArrow_Marker)' y1='291.194' x1='282.1112' y2='321.62198' x2='261.46365' stroke='black' stroke-width='1' stroke-linejoin='round' /&gt;&lt;line stroke-linecap='round' marker-end='url(#FilledArrow_Marker)' y1='345.86264' x1='242.51796' y2='380.20721' x2='207.56009' stroke='black' stroke-width='1' stroke-linejoin='round' /&gt;&lt;line stroke-linecap='round' marker-end='url(#FilledArrow_Marker)' y1='349.004' x1='250.00801' y2='374.104' x2='250.00801' stroke='black' stroke-width='1' stroke-linejoin='round' /&gt;&lt;line stroke-linecap='round' marker-end='url(#FilledArrow_Marker)' y1='291.194' x1='293.90479' y2='321.62198' x2='314.55234' stroke='black' stroke-width='1' stroke-linejoin='round' /&gt;&lt;line stroke-linecap='round' marker-end='url(#FilledArrow_Marker)' y1='349.004' x1='326.008' y2='374.104' x2='326.008' stroke='black' stroke-width='1' stroke-linejoin='round' /&gt;&lt;line stroke-linecap='round' marker-end='url(#FilledArrow_Marker)' y1='345.86258' x1='333.49799' y2='380.20724' x2='368.45593' stroke='black' stroke-width='1' stroke-linejoin='round' /&gt;&lt;line stroke-linecap='round' marker-end='url(#FilledArrow_Marker)' y1='403.194' x1='187.11122' y2='433.62198' x2='166.46367' stroke='black' stroke-width='1' stroke-linejoin='round' /&gt;&lt;line stroke-linecap='round' marker-end='url(#FilledArrow_Marker)' y1='405.004' x1='193.00801' y2='430.104' x2='193.00801' stroke='black' stroke-width='1' stroke-linejoin='round' /&gt;&lt;line stroke-linecap='round' marker-end='url(#FilledArrow_Marker)' y1='404.44937' x1='246.6337' y2='431.18353' x2='237.56317' stroke='black' stroke-width='1' stroke-linejoin='round' /&gt;&lt;line stroke-linecap='round' marker-end='url(#FilledArrow_Marker)' y1='404.44937' x1='253.38232' y2='431.18353' x2='262.45282' stroke='black' stroke-width='1' stroke-linejoin='round' /&gt;&lt;line stroke-linecap='round' marker-end='url(#FilledArrow_Marker)' y1='404.44937' x1='322.63367' y2='431.18353' x2='313.56317' stroke='black' stroke-width='1' stroke-linejoin='round' /&gt;&lt;line stroke-linecap='round' marker-end='url(#FilledArrow_Marker)' y1='404.44937' x1='329.38232' y2='431.1835' x2='338.45282' stroke='black' stroke-width='1' stroke-linejoin='round' /&gt;&lt;line stroke-linecap='round' marker-end='url(#FilledArrow_Marker)' y1='405.004' x1='383.008' y2='430.104' x2='383.008' stroke='black' stroke-width='1' stroke-linejoin='round' /&gt;&lt;line stroke-linecap='round' marker-end='url(#FilledArrow_Marker)' y1='403.194' x1='388.90479' y2='433.62198' x2='409.55234' stroke='black' stroke-width='1' stroke-linejoin='round' /&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;
&lt;p&gt;For each node in the tree we can compute a hash value for it&amp;#8217;s children. Using a hash function (crc if low security, or SHA1 or another cryptographically secure hash when required) we can compute the hash value for each node by recursively computing the hash for the left node and concatenating that hash with the hash of the right node. In the case of a leaf node (no children) then the hash is computed based on the stored value.&lt;/p&gt;

&lt;p&gt;Using the example tree in diagram1 we can compute the hash value of the root node according to the following rules.&lt;/p&gt;

&lt;p&gt;Let h be the hash function you have decided for your implementation. In our example we will use &lt;a href='http://en.wikipedia.org/wiki/SHA-1'&gt;SHA1&lt;/a&gt;. The hash for any node in the tree is h(N) = h(h(N.left) + h(N.right)) where N.left and N.right are left and right sub trees of that node. Therefore the hash for the root h(A) = h(h(B) + h(C))&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    h(B) = h(h(D) + h(E))
    h(C) = h(h(F) + h(G))
    h(D) = h(h(1) + h(2))
    h(E) = h(h(3) + h(4))
    h(F) = h(h(5) + h(6))
    h(G) = h(h(7) + h(8))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In our scala implementation the hashes are computed lazily when requested, but they could be computed once and cached, that optimization is left as an exercise for the reader.&lt;/p&gt;

&lt;p&gt;With our tree constructed we can determine if two trees are identical by comparing the hash of the root: h(A) If the root matches congratulations your trees are identical. The identical case is not that interesting, what happens if the third and fifth leaf nodes are different. How do you determine that using the Merkle tree.&lt;/p&gt;

&lt;p&gt;In that scenario h(A) != h(A&amp;#8217;) where A&amp;#8217; is the root of a tree on another machine. We would then look at the hash for the children of A and see that D and D&amp;#8217; matched, but E and E&amp;#8217; did not, we then compare h(3) and h3&amp;#8217;) see they do not match but h(4 and h(4&amp;#8217;) do. We would use a similar set of comparisons on the sub tree rooted at C to discover that h(5) and h(5&amp;#8217;) do not match.&lt;/p&gt;

&lt;p&gt;In our implementation we don&amp;#8217;t name nodes with letters and numbers, instead we address sub trees based on the range of leaf nodes they encompass. For example the hash for h(A) would represent the entire range one through eight (1,8), while B represents one through four (1,4) and so on down the tree. A leaf node&amp;#8217;s range is it&amp;#8217;s position from the left so one would be (1,1).&lt;/p&gt;

&lt;h2 id='code_or_it_didnt_happen'&gt;CODE, or it didn&amp;#8217;t happen&lt;/h2&gt;

&lt;p&gt;I have published an implementation an implementation of a sha1 hashing &lt;a href='https://github.com/danieltoshea/Merkle-Tree'&gt;merkle tree in scala&lt;/a&gt; on Github. I chose scala for fun to learn the language. The implementation consists of two classes. Node.scala and Tree.scala&lt;/p&gt;

&lt;h2 id='node_class'&gt;Node Class&lt;/h2&gt;

&lt;p&gt;The node is not very interesting, it uses the SHA1 message digest algorithm, and recursively determines the hash for any of it&amp;#8217;s child nodes. Empty leaf nodes have a hash value equal to empty string, and that value will bubble up the tree if the neighboring children are also empty.&lt;/p&gt;

&lt;p&gt;I will call attention to the SHA1 method is, because converting the digest from bytes to a string was somewhat annoying, it&amp;#8217;s worth copying it from here should you need to do something similar.&lt;/p&gt;

&lt;h2 id='tree_class'&gt;Tree Class&lt;/h2&gt;

&lt;p&gt;The tree class is where the magic happens :-)&lt;/p&gt;

&lt;p&gt;Tree exposes three methods&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;insert(value : String) - Insert a String into the tree.&lt;/li&gt;

&lt;li&gt;hash_for_range(search_start : Int, search_end : Int) - Determine the hash for a range of child nodes.&lt;/li&gt;

&lt;li&gt;leaf_node(number : Int) - Get the actual Node object representing a leaf node.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The tree class does a couple &amp;#8220;clever&amp;#8221; things. On the first insert it creates a balanced tree based on an initial size. The tree will resize itself like a hash table when it is full and another node is inserted. The resize doubles the size of the tree and copies the leaves from the smaller tree to the larger one. Originally I created a new tree on resize but when refactoring the tree, I know only add one more level of the tree, and move the values from the old leaves to the new ones.&lt;/p&gt;

&lt;p&gt;Only leaf nodes hold values. The other nodes contain a hash representing their child nodes. Insert automatically assigns the value to the next available leaf node in the tree.&lt;/p&gt;

&lt;p&gt;The hash for range method is interesting you specify a range of leaf nodes you would like the hash for. A tree with 8 elements hash_for_range(1, 8) would return the hash of the root, hash_for_range(1,4) would return the hash for the node left of the root, and hash_for_range(8,8) would return just the hash for the 8th leaf node. Hash for range is used to compare the hashes between two trees. This way you can navigate to just the child nodes that are different. Again as we discussed above If the root hash of the two trees is the same, then every node is identical, otherwise you get more and more specific until you find the leaf nodes that are not identical. Finally you use the leaf_node method to retrieve the specific node that is different between the two trees.&lt;/p&gt;

&lt;p&gt;The other methods are for utility purposes. This code is still very new and not yet ripe. Please don&amp;#8217;t use it in a production system. I will include a license file once the code has some tests.&lt;/p&gt;

&lt;p&gt;Until next time. Happy Coding!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Crossfit Update</title>
   <link href="http://danieloshea.com/2011/08/14/crossfit-update.html"/>
   <updated>2011-08-14T00:00:00-07:00</updated>
   <id>http://danieloshea.com/2011/08/14/crossfit-update</id>
   <content type="html">&lt;h1 id='crossfit_update'&gt;Crossfit Update&lt;/h1&gt;

&lt;p&gt;It&amp;#8217;s been over five months since my first post about Crossfit. It&amp;#8217;s been a terrific journey so far. I&amp;#8217;ve lost almost sixty pounds, gotten decently strong, and went from being a couch potato to running a couple 5 KM runs per week plus doing 2 Crossfit workouts.&lt;/p&gt;

&lt;p&gt;This past Sunday I attended my first group class. Up to this point I&amp;#8217;ve been working out one on one with a trainer, focusing on technique and working up the amount of weight I can move safely. The group class was great. I feel like I should have started attending sooner I had such a good time. A few short months ago I would not say running, burpees, and carrying a kettle bell 200m was a good time on a weekend. Now I&amp;#8217;m hooked (you might even say addicted) and really look forward to the workouts, even though I hurt like the dickens afterwards.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve changed around my work schedule so I can workout in the middle of the day and still go running in the morning, or at the end of the day. The great thing about &lt;a href='http://www.sparkart.com'&gt;Sparkart&lt;/a&gt; is we really do have flexible schedules, and everyone at work has been very supportive even when I blow off their meetings because I&amp;#8217;m &amp;#8220;in the gym&amp;#8221;.&lt;/p&gt;

&lt;p&gt;Also ending the day with a 5k run along the bay trail in Emeryville with the sun setting behind the mountains is beautiful and relaxing. The hot shower or a trip to the hot tub afterward is like heaven.&lt;/p&gt;

&lt;p&gt;The experience overall has been fantastic. The trainers at &lt;a href='http://www.crossfiteastbay.com'&gt;Crossfit East Bay&lt;/a&gt; are excellent and I can not recommend Maximus enough. If you want to get seriously fit, some might even say &amp;#8220;Elite&amp;#8221; fitness, and have a great time doing it, you owe it to yourself to check them out.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Presentation at the Eastbay HTML5 Meetup</title>
   <link href="http://danieloshea.com/2011/03/17/html5-meetup.html"/>
   <updated>2011-03-17T00:00:00-07:00</updated>
   <id>http://danieloshea.com/2011/03/17/html5-meetup</id>
   <content type="html">&lt;h1 id='presentation_at_the_eastbay_html5_meetup'&gt;Presentation at the Eastbay HTML5 Meetup&lt;/h1&gt;

&lt;h2 id='getting_out_there'&gt;Getting out there&lt;/h2&gt;

&lt;p&gt;&lt;a href='http://twitter.com/theycallmeninja'&gt;Niraj&lt;/a&gt; and I presented the work we did for &amp;#8220;The Killers&amp;#8221; at the Eastbay HTML5 Meetup tonight. Overall I think the the presentation went pretty well. We tried to strike a good balance between talking about the creative process that went into creating the site, and actionable advice regarding SVG and Canvas.&lt;/p&gt;

&lt;p&gt;I also gave a simple canvas animation demo:&lt;/p&gt;
&lt;script src='https://gist.github.com/873488.js'&gt; &lt;/script&gt;
&lt;p&gt;The code above adds three circles to a canvas element, and moves them from (xCoord, yCoord) to (xDest, yDest) and then back. We apply some easing to give them some acceleration, and to make the animation slightly more interesting.&lt;/p&gt;

&lt;p&gt;This is very similar to what we did with on the actual Killers site, just with far fewer elements :-)&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Crossfit Part 1</title>
   <link href="http://danieloshea.com/2011/02/07/crossfit.html"/>
   <updated>2011-02-07T00:00:00-08:00</updated>
   <id>http://danieloshea.com/2011/02/07/crossfit</id>
   <content type="html">&lt;h1 id='crossfit_part_1'&gt;Crossfit Part 1&lt;/h1&gt;

&lt;h2 id='the_beginning'&gt;The Beginning&lt;/h2&gt;

&lt;p&gt;Another year has rolled around, and another birthday on top of that, the big Three Ohh; and I find myself a bit rounder than I&amp;#8217;d like. Every year I say I&amp;#8217;ll do something about it, sometimes I&amp;#8217;ll even make it so far as to join a gym, which lasts for about two months. Then I get bored, stop going and have to wait for the terms of the contract to expire so I can cancel it. This year I wanted to do something different, something that I wouldn&amp;#8217;t get bored doing, and something where I could get help along the way. I thought about hiring a trainer in traditional gym, it&amp;#8217;s a pretty big investment, so I immediately start googling trainers, reading reviews, asking friends, doing due diligence like I would before any big purchase. A couple friends thought the trainer idea was pretty bogus. &amp;#8220;Why hire someone when you are pretty much guaranteed results the first couple months, if you just do any kind of workout&amp;#8221;, they would say. Perhaps they are right, maybe anyone can get some short term results, blubbing around in the gym; but I&amp;#8217;m looking for a program, a movement, a freaking way to keep this going for the long term. So I was about ninety percent confident that the trainer route was the right path.&lt;/p&gt;

&lt;p&gt;Now, there are many trainer options out there. The people available at the local 24hr fitness, boutique gyms, boot camps, etc, etc. It&amp;#8217;s quite a field to navigate with all the options. Perhaps drawn by the videos on the internet of what appears to be crazy buff beasts doing amazing thinks like 50 inch box jumps (50&amp;#8221; are you kidding me, that&amp;#8217;s crazy shit). Anyway, I jumped on yelp.com and browsed around some of the crossfit gyms in my area.&lt;/p&gt;

&lt;h2 id='crossfit__holy_shit_man_what_are_you_thinking'&gt;Crossfit - Holy Shit Man, What Are You Thinking?&lt;/h2&gt;

&lt;p&gt;Yeah, the workouts are intense, some people even told me there is no way I will be able to do a crossfit workout, that I&amp;#8217;m crazy for trying. Maybe they are right, but you have to try to find out for sure what you can do.&lt;/p&gt;

&lt;h2 id='crossfit__session_1'&gt;Crossfit - Session 1&lt;/h2&gt;

&lt;p&gt;Today I had my first Crossfit&amp;#8217;ish workout. It was just an intro, and I didn&amp;#8217;t make it all the way through. We managed to get through a rowing warmup, streaching, air squats, deadlifts, overhead press, and some pushups. After the deadlift, I &amp;#8220;almost&amp;#8221; puked, but was able to walk it off, not the greatest start to looking like one of the guys from 300 :-)&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/pukie.jpeg' alt='Pukie' /&gt;&lt;/p&gt;

&lt;p&gt;Wednesday will mark day two, tune back then for an update.&lt;/p&gt;</content>
 </entry>
 
 
</feed>

