<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Erlang on Probably Programming</title>
    <link>http://probablyprogramming.com/categories/erlang/</link>
    <description>Recent content in Erlang on Probably Programming</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Fri, 25 Sep 2009 03:37:22 +0000</lastBuildDate>
    <atom:link href="http://probablyprogramming.com/categories/erlang/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Walking Journal: 45 miles, starting a Twitter client chain</title>
      <link>http://probablyprogramming.com/2009/09/25/starting-a-twitter-client-chain/</link>
      <pubDate>Fri, 25 Sep 2009 03:37:22 +0000</pubDate>
      
      <guid>http://probablyprogramming.com/2009/09/25/starting-a-twitter-client-chain/</guid>
      <description>

&lt;p&gt;I&amp;rsquo;ve been neglecting both walking and posting on here, though I&amp;rsquo;ve neglected posting more, obviously.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve been very busy with work and side projects and my house trying to fall apart on me, so I&amp;rsquo;ve been out of free time lately.&lt;/p&gt;

&lt;p&gt;Anyway, my total is now up to 45 miles of walking. Not too much more than last time, really. I&amp;rsquo;ve gone on some walks around the neighborhood with Angie, and I&amp;rsquo;m not counting them, mostly because I don&amp;rsquo;t know how long they are, really.&lt;/p&gt;

&lt;p&gt;I decided I wanted to start a &amp;ldquo;chain,&amp;rdquo; where every day I do something to work toward a goal I&amp;rsquo;ve set for myself (yes, I mean other than the walking, though that can be a chain as well).&lt;/p&gt;

&lt;p&gt;Fortunately enough for me, I found &lt;a href=&#34;http://dontbreakthechain.com/&#34;&gt;Don&amp;rsquo;t Break The Chain&lt;/a&gt;, where you can keep track of one or more &amp;ldquo;chains&amp;rdquo; of things you want to do every day.&lt;/p&gt;

&lt;h3 id=&#34;the-twitter-client-chain:4801f1f98cf6f09e50c6cae84d356d78&#34;&gt;The Twitter Client Chain&lt;/h3&gt;

&lt;p&gt;So I&amp;rsquo;m creating a web-based Twitter client, as a project for me to try out all the different techniques and technologies that I want to use, but don&amp;rsquo;t have the chance to work with as much as I&amp;rsquo;d like during my day job. Also, ideally, it will at some point become a supplementary source of income.&lt;/p&gt;

&lt;p&gt;That&amp;rsquo;s a quite a way off until I have more free time in a month or two, but for now, I will satisfy myself with making some small amount of progress on it each day (hopefully).&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m writing this client in Erlang, using the awesome &lt;a href=&#34;http://nitrogenproject.com/&#34;&gt;Nitrogen web framework&lt;/a&gt; with the equally awesome &lt;a href=&#34;http://code.google.com/p/mochiweb/&#34;&gt;MochiWeb web server&lt;/a&gt;. My goals for this project include using &lt;a href=&#34;http://c2.com/cgi/wiki?TestDrivenDevelopment&#34;&gt;test driven development&lt;/a&gt; and &lt;a href=&#34;http://timothyfitz.wordpress.com/2009/02/10/continuous-deployment-at-imvu-doing-the-impossible-fifty-times-a-day/&#34;&gt;continuous deployment&lt;/a&gt; and fully embracing the mantra of &lt;a href=&#34;http://www.google.com/search?q=release%20early%2C%20release%20often&#34;&gt;&amp;ldquo;release early, release often&amp;rdquo;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The plan is to have something up and running on a server as soon as possible. By something, I mean even less than a full-featured twitter client. But as soon as something is up, I can start getting feedback, and see what I should work on next. If I&amp;rsquo;m creating a product for users, there&amp;rsquo;s no use in developing what I want.&lt;/p&gt;

&lt;p&gt;I need to develop what my users want.&lt;/p&gt;

&lt;p&gt;I started this chain up about a week ago, and broke it after the first day. Now I&amp;rsquo;m trying again.&lt;/p&gt;

&lt;h4 id=&#34;tests-and-pre-commit-hooks:4801f1f98cf6f09e50c6cae84d356d78&#34;&gt;Tests and pre-commit hooks&lt;/h4&gt;

&lt;p&gt;During my previous, one-day chain, I managed to get a test harness (using the &lt;a href=&#34;http://svn.process-one.net/contribs/trunk/eunit/doc/overview-summary.html&#34;&gt;EUnit Erlang unit test framework&lt;/a&gt;) set up which will find any modules ending with _tests, stopping at the first error.&lt;/p&gt;

&lt;p&gt;At the moment, I have a shell script which runs the tests. When it starts to take too long, I will switch over to an Erlang module which loops through, so I don&amp;rsquo;t get the startup times of the Erlang interpreter for each test. Or if anyone knows an easier way (perhaps there&amp;rsquo;s already a module that does that somewhere?).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;    #!/bin/bash
    
    for modfile in `ls ebin/*_tests.beam`
    do
        mod=`basename $modfile .beam`
        echo Running $mod:
        erl -noshell -pa ./ebin -s runtest main ${mod%.*}
        [ $? -eq 0 ] || exit 1
    done
    [ $mod ] || exit 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The runtest module consists of the following:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-erlang&#34;&gt;    -module(runtest).
    -export([main/1]).
    
    main(Mod) -&amp;gt;
        case eunit:test(Mod) of
            error -&amp;gt; halt(1);
            _ -&amp;gt; init:stop()
        end.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It&amp;rsquo;s all kind of thrown together, but the point is incremental improvement, so I&amp;rsquo;ll get back to it when/if I need to. Like I said, there&amp;rsquo;s probably something else out there that will do a better job at this than I did.&lt;/p&gt;

&lt;p&gt;So, today, my &amp;ldquo;chain link&amp;rdquo; was partially taking that script and setting it up to run from the GIT pre-commit script, and partially writing this blog post.&lt;/p&gt;

&lt;p&gt;Getting it set up to run as a pre-commit script just involved making sure it returns non-zero whenever there is a test error (or if no tests were run, which happens when make hasn&amp;rsquo;t been run yet).&lt;/p&gt;

&lt;p&gt;The pre-commit script itself (placed in .git/hooks/pre-commit and set executable) is pretty simple:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;    #!/bin/sh
    ./tests.sh
    if [ $? != 0 ]
    then
            echo &amp;quot;====================================&amp;quot;
            echo &amp;quot; Commit stopped due to test failure&amp;quot;
            echo &amp;quot;====================================&amp;quot;
            exit 1
    fi
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;script src=&#34;http://dontbreakthechain.com/share_js/pib/last-four/29377&#34; type=&#34;text/javascript&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;
Chain length: 1!&lt;/p&gt;

&lt;h4 id=&#34;what-s-next:4801f1f98cf6f09e50c6cae84d356d78&#34;&gt;What&amp;rsquo;s next?&lt;/h4&gt;

&lt;p&gt;Next up, I&amp;rsquo;m acutally going to start on the meat of the project. Since I haven&amp;rsquo;t fully decided on what GUI library I want to use, nor what GUI testing framework I want to use, I&amp;rsquo;m going to start on the backend with code to manage user login info and queries (timeline searches, DMs, etc.).&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve got some great ideas (I think) on ways to enhance the way people have conversations over Twitter (and eventually other mediums), so you can be sure that there will be more posts about this in the future.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Nitrogen module auto-reloading</title>
      <link>http://probablyprogramming.com/2009/06/20/nitrogen-module-auto-reloading/</link>
      <pubDate>Sat, 20 Jun 2009 19:27:14 +0000</pubDate>
      
      <guid>http://probablyprogramming.com/2009/06/20/nitrogen-module-auto-reloading/</guid>
      <description>&lt;p&gt;This is a really simple tip, but it was handy for me, and it could be helpful for someone else, too.&lt;/p&gt;

&lt;p&gt;While playing around with &lt;a href=&#34;http://nitrogenproject.com/&#34;&gt;Nitrogen&lt;/a&gt;, which is a great project by the way (more in a later blog post, I guarantee it), I noticed that I had to restart the server to re-load modules as I changed them (or I could manually, reload them, I know, I know..).&lt;/p&gt;

&lt;p&gt;Since I was using &lt;a href=&#34;http://code.google.com/p/mochiweb/&#34;&gt;Mochiweb&lt;/a&gt; as my backend, and I&amp;rsquo;m used to the development version of Mochiweb auto-reloading modules as you recompile, I wanted the same functionality here.&lt;/p&gt;

&lt;p&gt;Turns out it&amp;rsquo;s as simple as changing the default start.sh from&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;    #!/bin/sh
    cd `dirname $0`
    
    echo Starting Nitrogen.
    erl \
    	-name nitrogen@localhost \
    	-pa ./ebin -pa ./include \
    	-s make all \
    	-eval &amp;quot;application:start(appname)&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to this&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;    #!/bin/sh
    cd `dirname $0`
    
    echo Starting Nitrogen.
    erl \
    	-name nitrogen@localhost \
    	-pa ./ebin -pa ./include \
    	-s make all \
    	-s reloader \
    	-eval &amp;quot;application:start(appname)&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&amp;hellip; and bam, modules now reload as you recompile them.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Untiny that url!</title>
      <link>http://probablyprogramming.com/2009/04/11/untiny-that-url/</link>
      <pubDate>Sat, 11 Apr 2009 20:36:21 +0000</pubDate>
      
      <guid>http://probablyprogramming.com/2009/04/11/untiny-that-url/</guid>
      <description>&lt;p&gt;There has been some &lt;a href=&#34;http://shiflett.org/blog/2009/apr/save-the-internet-with-rev-canonical&#34;&gt;talk about&lt;/a&gt; and &lt;a href=&#34;http://benramsey.com/archives/a-revcanonical-rebuttal/&#34;&gt;arguments against&lt;/a&gt; and &lt;a href=&#34;http://shiflett.org/blog/2009/apr/a-rev-canonical-http-header&#34;&gt;responses to issues&lt;/a&gt; about using &lt;a href=&#34;http://revcanonical.appspot.com/&#34;&gt;rev=&amp;ldquo;cononical&amp;rdquo;&lt;/a&gt; for referencing shorter URLs instead of the automated use of TinyURL when posting to sites like Twitter.&lt;/p&gt;

&lt;p&gt;I must say that I agree with Ben Ramsey (see &amp;ldquo;arguments agains&amp;rdquo; above) in suggesting we use rel=&amp;ldquo;alternate shorter&amp;rdquo; instead.&lt;/p&gt;

&lt;p&gt;I also like the idea that Chris Shiflett had of using a HTTP header and a HEAD request to make it so you neither have to retrieve the entire requested page nor parse any HTML. I&amp;rsquo;d stick with Ben&amp;rsquo;s suggestion, however, and make the header something like &amp;ldquo;X-Alternate-Shorter:&amp;ldquo;, rather than &amp;ldquo;X-Rev-Canonical&amp;rdquo;. What&amp;rsquo;s the harm in calling it something that actually makes sense?&lt;/p&gt;

&lt;p&gt;The idea of using HTTP HEAD requests to solve the problem inspired me to come up with a more immediate solution to one of the problems introduced by using url shortening services: uncertainty about where a URL leads.&lt;/p&gt;

&lt;p&gt;This problem can be solved on the client side, which requires no work on the part of Twitter (meaning this is more likely to be put into use sooner).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Since most URL shortening services use an HTTP redirect to do their job, all it takes is a HEAD request to the tiny URL in question, and then a look at whatever &amp;ldquo;Location:&amp;rdquo; header is returned to see what the real URL is.&lt;/strong&gt; In fact, you don&amp;rsquo;t even really need to do a HEAD request in most cases, since most URL shortening services don&amp;rsquo;t return any body, since they are just redirecting you anyway.&lt;/p&gt;

&lt;p&gt;Read on for more information and implementations of an untinyurl function in various languages.&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s actually already a site online that offers the service of un-shortening URLs for you at &lt;a href=&#34;http://untinyurl.com/&#34;&gt;UnTinyURL.com&lt;/a&gt;, but I wouldn&amp;rsquo;t suggest using that in any sort of automated system, and it&amp;rsquo;s of limited usefulness since you don&amp;rsquo;t really want to have to go to this site just to see what site you&amp;rsquo;re about to go to. Most people will just click a link, even if it means they might get RickRolled.&lt;/p&gt;

&lt;p&gt;For those comfortable with the commandline, a simple curl call can give you the same basic info:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;    curl -I http://tinyurl.com/c8f5bz
    HTTP/1.1 301 Moved Permanently
    X-Powered-By: PHP/5.2.9
    Location: http://probablyprogramming.com/2009/04/11/untiny-that-url/
    Content-type: text/html
    Date: Sun, 12 Apr 2009 01:26:08 GMT
    Server: TinyURL/1.6
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Toss in a grep and an awk, and you get your URL in a single line, perfect if you&amp;rsquo;re handing shortened URLs in a shell script for some reason:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;    $ curl -s -I http://tinyurl.com/c8f5bz | grep Location | awk &#39;{print $2}&#39;
    http://probablyprogramming.com/2009/04/11/untiny-that-url/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here&amp;rsquo;s untinyurl in Python:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;    import httplib
    import urlparse
    
    def untinyurl(tinyurl):
        url = urlparse.urlsplit(tinyurl)
        req = urlparse.urlunsplit((&#39;&#39;, &#39;&#39;, url.path, url.query, url.fragment))
        con = httplib.HTTPConnection(url.netloc)
        try:
            con.request(&#39;HEAD&#39;, req)
        except:
            return None
        response = con.getresponse()
        return response.getheader(&#39;Location&#39;, None)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And here&amp;rsquo;s a version in PHP. It&amp;rsquo;s a bit longer and uglier than the Python version because I&amp;rsquo;m using the low-level fsockopen function to do my HTTP request rather than using cUrl or the HTTP extension. The reason I did this is because every PHP install will have fsockopen, whereas not every install will have cUrl or the HTTP extension.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-php&#34;&gt;    &amp;lt;?php
    
    function untinyurl($tinyurl) 
    {
        $url = parse_url($tinyurl);
        $host = $url[&#39;host&#39;];
        $port = isset($url[&#39;port&#39;]) ? $url[&#39;port&#39;] : 80;
        $query = isset($url[&#39;query&#39;]) ? &#39;?&#39; . $url[&#39;query&#39;] : &#39;&#39;;
        $fragment = isset($url[&#39;fragment&#39;]) ? &#39;#&#39; . $url[&#39;fragment&#39;] : &#39;&#39;;
    
        $sock = @fsockopen($host, $port);
        if (!$sock) return $tinyurl;
        
        $url = $url[&#39;path&#39;] . $query . $fragment;
        $request = &amp;quot;HEAD {$url} HTTP/1.0\r\nHost: {$host}\r\nConnection: Close\r\n\r\n&amp;quot;;
    
        fwrite($sock, $request);
        $response = &#39;&#39;;
        while (!feof($sock)) {
            $response .= fgets($sock, 128);
        }
        $lines = explode(&amp;quot;\r\n&amp;quot;, $response);
        foreach ($lines as $line) {
            if (strpos(strtolower($line), &#39;location:&#39;) === 0) {
                list(, $location) = explode(&#39;:&#39;, $line, 2);
                return ltrim($location);
            }
        }
        return $tinyurl;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I&amp;rsquo;m not too familiar with Ruby, but after poking around for a little bit, I came up with this Ruby version. Holy crap, Ruby, that was easy and short!&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-ruby&#34;&gt;    require &#39;net/http&#39;
    require &#39;uri&#39;
    def untinyurl(tinyurl)
      Net::HTTP.get_response(URI.parse(tinyurl))[&#39;location&#39;] or tinyurl
    rescue
      tinyurl
    end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And one more, and Erlang implementation (that &amp;lt;SEMI&amp;gt; is supposed to be a semicolon, but something is wrong with the syntax highlighter Erlang plugin). Be sure you call &amp;ldquo;inets:start()&amp;rdquo; before calling this function.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-erlang&#34;&gt;    -module(untinyurl).
    -export([untinyurl/1]).
    untinyurl(TinyUrl) -&amp;gt;
        case http:request(head, {TinyUrl, []}, [{autoredirect, false}], []) of
            {ok, {_Status, Headers, _Body{% templatetag closevariable %} -&amp;gt; proplists:get_value(&amp;quot;location&amp;quot;, Headers, TinyUrl);
            _ -&amp;gt; TinyUrl
        end.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Interesting how the Erlang and Ruby implementations look pretty similar.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve made the source code available &lt;a href=&#34;http://github.com/pib/untinyurl/tree/master&#34;&gt;at GitHub&lt;/a&gt;.
If you would like to contribute an untinyurl implementation in another language or have a bug-fix or suggestion for an improvement of one of the implementations I have so far, either email me, send me a pull request on GitHub, or post a comment here.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>First steps to an Erlang OpenID consumer</title>
      <link>http://probablyprogramming.com/2009/01/21/first-steps-to-an-erlang-openid-consumer/</link>
      <pubDate>Wed, 21 Jan 2009 03:18:14 +0000</pubDate>
      
      <guid>http://probablyprogramming.com/2009/01/21/first-steps-to-an-erlang-openid-consumer/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m working on a little project in Erlang and I wanted to use only OpenID for my authentication. It turns out there is currently no Erlang OpenID consumer library (or if there is, I couldn&amp;rsquo;t find it).&lt;/p&gt;

&lt;p&gt;So I&amp;rsquo;ve started writing my own. So far I&amp;rsquo;ve got the first necessary step complete: HTML-based discovery.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m starting with version 1.1, simply because it is shorter and requires less (I don&amp;rsquo;t want to implement the XRI or Yadis protocols just yet).&lt;/p&gt;

&lt;p&gt;It turns out that mochiweb &lt;a href=&#34;http://www.rsaccon.com/2007/11/mochiweb-got-html-parser.html&#34;&gt;comes with an HTML parser&lt;/a&gt;, so I used that, since I&amp;rsquo;m using mochiweb for my application. The parsed HTML comes back as a series of nested tuples of the format {&amp;lt;&amp;lt;&amp;ldquo;tag&amp;rdquo;&amp;gt;&amp;gt;, Attributes, Children}, where &amp;ldquo;tag&amp;rdquo; is the tagname (the root will be &amp;lt;&amp;lt;&amp;ldquo;html&amp;rdquo;&amp;gt;&amp;gt;, for example), Attributes is a &lt;a href=&#34;http://www.erlang.org/doc/man/proplists.html&#34;&gt;proplist&lt;/a&gt; of that tag&amp;rsquo;s attributes, and Children is a list of more tuples of the same format and/or binaries with the contents of text nodes. Everything is represented as binaries, so I use those directly rather than converting between strings and binaries.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s the code which finds the link tags with rel=&amp;ldquo;openid.server&amp;rdquo; and rel=&amp;ldquo;openid.delegate&amp;rdquo; (if it is there):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-erlang&#34;&gt;    get_openid_server(Identifier) -&amp;gt;
        NormalizedIdentifier = normalize_identifier(Identifier),
        case http:request(NormalizedIdentifier) of
            {ok, {_Status, _Headers, Body{% templatetag closevariable %} -&amp;gt;
                HtmlTokens = mochiweb_html:parse(Body),
                find_openid_tags(HtmlTokens);
            _ -&amp;gt;
                {error, http_error}
        end.
    
    normalize_identifier(Ident = &amp;quot;http://&amp;quot; ++ _Rest) -&amp;gt;
        Ident;
    normalize_identifier(Ident) -&amp;gt;
        &amp;quot;http://&amp;quot; ++ Ident.
    
    find_openid_tags(HtmlTokens) -&amp;gt;
        case find_tag(&amp;lt;&amp;lt;&amp;quot;head&amp;quot;&amp;gt;&amp;gt;, [HtmlTokens]) of
            {&amp;lt;&amp;lt;&amp;quot;head&amp;quot;&amp;gt;&amp;gt;, _Attrs, Children, _Rest} -&amp;gt;
                case find_tag_with_attr(&amp;lt;&amp;lt;&amp;quot;link&amp;quot;&amp;gt;&amp;gt;, {&amp;lt;&amp;lt;&amp;quot;rel&amp;quot;&amp;gt;&amp;gt;, &amp;lt;&amp;lt;&amp;quot;openid.server&amp;quot;&amp;gt;&amp;gt;}, Children) of
                    not_found -&amp;gt;
                        {error, openid_server_not_found};
                    ServerAttrs -&amp;gt;
                        Server = proplists:get_value(&amp;lt;&amp;lt;&amp;quot;href&amp;quot;&amp;gt;&amp;gt;, ServerAttrs),
                        case find_tag_with_attr(&amp;lt;&amp;lt;&amp;quot;link&amp;quot;&amp;gt;&amp;gt;, {&amp;lt;&amp;lt;&amp;quot;rel&amp;quot;&amp;gt;&amp;gt;, &amp;lt;&amp;lt;&amp;quot;openid.delegate&amp;quot;&amp;gt;&amp;gt;}, Children) of
                            not_found -&amp;gt;
                                [{server, Server}];
                            DelegateAttrs -&amp;gt;
                                Delegate = proplists:get_value(&amp;lt;&amp;lt;&amp;quot;href&amp;quot;&amp;gt;&amp;gt;, DelegateAttrs),
                                [{server, Server}, {delegate, Delegate}]
                        end
                end;
            not_found -&amp;gt;
                {error, no_head_tag}
        end.
    
    find_tag(_TagName, []) -&amp;gt;
        not_found;
    find_tag(TagName, [{TagName, Attributes, Children} | Rest]) -&amp;gt;
        {TagName, Attributes, Children, Rest};
    find_tag(TagName, [{_OtherTag, _Attributes, Children} | Rest]) -&amp;gt;
        find_tag(TagName, Children ++ Rest);
    find_tag(TagName, [_Other | Rest]) -&amp;gt;
        find_tag(TagName, Rest).
    
    find_tag_with_attr(_TagName, {_AttrKey, _AttrVal}, []) -&amp;gt;
        not_found;
    find_tag_with_attr(TagName, Attr = {AttrKey, AttrVal}, Tags) -&amp;gt;
        case find_tag(TagName, Tags) of
            not_found -&amp;gt;
                not_found;
            {TagName, Attributes, Children, Rest} -&amp;gt;
                case proplists:get_value(AttrKey, Attributes) of
                    AttrVal -&amp;gt;
                        Attributes;
                    _ -&amp;gt; 
                        find_tag_with_attr(TagName, Attr, Children ++ Rest) 
                end
        end.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(the &amp;lt;PIPE&amp;gt;s above should be &amp;ldquo;|&amp;ldquo;s and the &amp;lt;SEMI&amp;gt;s should be &amp;ldquo;;&amp;ldquo;s. Not sure why the syntax highlighter is doing that to them&amp;hellip;&lt;/p&gt;

&lt;p&gt;Assuming the above code is put into a module called &amp;ldquo;openid&amp;rdquo;, you get the following:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-erlang&#34;&gt;    1&amp;gt; openid:get_openid_server(&amp;quot;blog.paulbonser.com&amp;quot;)
    [{server,&amp;lt;&amp;lt;&amp;quot;http://www.livejournal.com/openid/server.bml&amp;quot;&amp;gt;&amp;gt;},
     {delegate,&amp;lt;&amp;lt;&amp;quot;http://misterpib.livejournal.com/&amp;quot;&amp;gt;&amp;gt;}]
    2&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As I said, this is the first step. Hopefully I&amp;rsquo;ll have some time very soon to get on with the next couple of steps, and then I&amp;rsquo;ll be done.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Storing Hierarchical Data in CouchDB</title>
      <link>http://probablyprogramming.com/2008/07/04/storing-hierarchical-data-in-couchdb/</link>
      <pubDate>Fri, 04 Jul 2008 18:20:52 +0000</pubDate>
      
      <guid>http://probablyprogramming.com/2008/07/04/storing-hierarchical-data-in-couchdb/</guid>
      <description>

&lt;p&gt;Much to my surprise, my last post generated more traffic in a single day than my blog has ever gotten in a single month. Apparently people are quite interested in making web applications with Python. I&amp;rsquo;ve started on part two, but since so many people showed interest I want to spend more time on it than I spent on the last one. So instead, you get this post.&lt;/p&gt;

&lt;p&gt;So I&amp;rsquo;ve been fiddling around with CouchDB lately. Since it&amp;rsquo;s common to store tree-based data, and it&amp;rsquo;s kind of a pain to do so in your standard relational DB, I thought it would be a good exercise to see how hard it is to store hierarchical data in CouchDB.&lt;/p&gt;

&lt;p&gt;Turns out it&amp;rsquo;s pretty easy.&lt;/p&gt;

&lt;p&gt;For comparison, you might want to check out &lt;a href=&#34;http://www.sitepoint.com/article/hierarchical-data-database&#34;&gt;this article&lt;/a&gt; on storing trees in a relational database. It covers how to store tree-like data using both Adjacency Lists and Modified Preorder Tree Traversal (that&amp;rsquo;s a mouthful). I&amp;rsquo;ll cover how I put the data into CouchDB and some of the ways you might want to pull it out.&lt;/p&gt;

&lt;h3 id=&#34;storing-the-tree:c3299f700a9c3aa73b011d2d41847148&#34;&gt;Storing the Tree&lt;/h3&gt;

&lt;p&gt;Rather than keeping track of parents as in the Adjacency List method or &amp;lsquo;left&amp;rsquo; and &amp;lsquo;right&amp;rsquo; as in the Modified Preorder Tree Traversal method, I store the full path to each node as an attribute in that node&amp;rsquo;s document. I then use this data in the views to organize the data as I need it.&lt;/p&gt;

&lt;p&gt;The test data I used is as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;    [
        {&amp;quot;_id&amp;quot;:&amp;quot;Food&amp;quot;,   &amp;quot;path&amp;quot;:[&amp;quot;Food&amp;quot;]},
        {&amp;quot;_id&amp;quot;:&amp;quot;Fruit&amp;quot;,  &amp;quot;path&amp;quot;:[&amp;quot;Food&amp;quot;,&amp;quot;Fruit&amp;quot;]},
        {&amp;quot;_id&amp;quot;:&amp;quot;Red&amp;quot;,    &amp;quot;path&amp;quot;:[&amp;quot;Food&amp;quot;,&amp;quot;Fruit&amp;quot;,&amp;quot;Red&amp;quot;]},
        {&amp;quot;_id&amp;quot;:&amp;quot;Cherry&amp;quot;, &amp;quot;path&amp;quot;:[&amp;quot;Food&amp;quot;,&amp;quot;Fruit&amp;quot;,&amp;quot;Red&amp;quot;,&amp;quot;Cherry&amp;quot;]},
        {&amp;quot;_id&amp;quot;:&amp;quot;Tomato&amp;quot;, &amp;quot;path&amp;quot;:[&amp;quot;Food&amp;quot;,&amp;quot;Fruit&amp;quot;,&amp;quot;Red&amp;quot;,&amp;quot;Tomato&amp;quot;]},
        {&amp;quot;_id&amp;quot;:&amp;quot;Yellow&amp;quot;, &amp;quot;path&amp;quot;:[&amp;quot;Food&amp;quot;,&amp;quot;Fruit&amp;quot;,&amp;quot;Yellow&amp;quot;]},
        {&amp;quot;_id&amp;quot;:&amp;quot;Banana&amp;quot;, &amp;quot;path&amp;quot;:[&amp;quot;Food&amp;quot;,&amp;quot;Fruit&amp;quot;,&amp;quot;Yellow&amp;quot;,&amp;quot;Banana&amp;quot;]},
        {&amp;quot;_id&amp;quot;:&amp;quot;Meat&amp;quot;,   &amp;quot;path&amp;quot;:[&amp;quot;Food&amp;quot;,&amp;quot;Meat&amp;quot;]},
        {&amp;quot;_id&amp;quot;:&amp;quot;Beef&amp;quot;,   &amp;quot;path&amp;quot;:[&amp;quot;Food&amp;quot;,&amp;quot;Meat&amp;quot;,&amp;quot;Beef&amp;quot;]},
        {&amp;quot;_id&amp;quot;:&amp;quot;Pork&amp;quot;,   &amp;quot;path&amp;quot;:[&amp;quot;Food&amp;quot;,&amp;quot;Meat&amp;quot;,&amp;quot;Pork&amp;quot;]}
    ]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In a real system you&amp;rsquo;d probably want to use some sort of UUID instead of descriptive strings, since conflicts between node names could be bad. In fact, it&amp;rsquo;d probably be much faster to just use numbers, since comparisons on numbers are generally much faster. For the purposes of this post, however, it&amp;rsquo;s much easier to understand if it&amp;rsquo;s descriptive text.&lt;/p&gt;

&lt;p&gt;Once that data is in your DB, it&amp;rsquo;s time to get it out again!&lt;/p&gt;

&lt;h3 id=&#34;retrieving-the-whole-tree:c3299f700a9c3aa73b011d2d41847148&#34;&gt;Retrieving the whole tree&lt;/h3&gt;

&lt;p&gt;The CouchDB map function to retrieve the whole tree is nice and simple:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;    function(doc) {
        emit(doc.path, doc)
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Using the path as the key, the documents will be sorted as above, with each parent immediately followed by its children.&lt;/p&gt;

&lt;p&gt;One option to get the data into an actual tree would be to add a reduce function to the view:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;    function(keys, vals) {
        tree = {};
        for (var i in vals)
        {
            current = tree;
            for (var j in vals[i].path)
            {
                child = vals[i].path[j];
                if (current[child] == undefined) 
                    current[child] = {};
                current = current[child];
            } 
            current[&#39;_data&#39;] = vals[i];
        }
        return tree;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;Note: don&amp;rsquo;t use this reduce function, since it doesn&amp;rsquo;t take the rereduce parameter into account, and would most likely not work correctly if a rereduce was done.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I chose to write a similar function in Python and use that to generate my tree on the client side:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;    class TreeNode(dict): pass
    
    def tree_from_rows(list):
        tree = {}
        for item in list:
            current = tree
            for child in item.value[&#39;path&#39;]:
                current = current.setdefault(child, TreeNode())
            current.data = item.value
        return tree
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This code does the job nicely and allows me to use the same function to build a tree from several different views without duplicating code.&lt;/p&gt;

&lt;h3 id=&#34;getting-a-subtree:c3299f700a9c3aa73b011d2d41847148&#34;&gt;Getting a subtree&lt;/h3&gt;

&lt;p&gt;To get all the nodes which are underneath a specific node, I implemented the view&amp;rsquo;s reduce function as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;    function(doc) { 
        for (var i in doc.path) { 
            emit([doc.path[i], doc.path], doc) 
        } 
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Again, this is pretty simple. The only difference from the last view is that I can now query this view with a startkey and endkey (see the &lt;a href=&#34;http://wiki.apache.org/couchdb/HttpViewApi#head-45806c14f9b1a9e1a4b0ea579ffdf150077f8cb9&#34;&gt;CouchDB HttpViewApi&lt;/a&gt;) to get only nodes under a certain node. I could actually do that with the previous view, except I&amp;rsquo;d have to include the full path to the node in my startkey, which is a bit too much.&lt;/p&gt;

&lt;p&gt;For example, if you had CouchDB running on your machine right now with my example data loaded and went to &lt;a href=&#34;http://localhost:5984/tree/_view/tree/descendants?startkey=[%22Fruit%22]&amp;amp;endkey=[%22Fruit%22,{}]&#34;&gt;http://localhost:5984/tree/_view/tree/descendants?startkey=[&amp;ldquo;Fruit&amp;rdquo;]&amp;amp;endkey=[&amp;ldquo;Fruit&amp;rdquo;,{}]&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;how-many-descendants:c3299f700a9c3aa73b011d2d41847148&#34;&gt;How Many Descendants&lt;/h3&gt;

&lt;p&gt;Getting the number of descendants for a given node is simple. The view is as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;    &#39;descendant_count&#39;: {
        &#39;map&#39;:    &#39;function(doc) { for (var i in doc.path) { emit(doc.path[i], 1) } }&#39;,
        &#39;reduce&#39;: &#39;function(keys, values) { return sum(values) }&#39;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will count the parent node as well, so you will probably want to subtract one from it at some point. To use this view simply call it with the key parameter set to the id of the desired root node.&lt;/p&gt;

&lt;h3 id=&#34;getting-the-immediate-children-of-a-node:c3299f700a9c3aa73b011d2d41847148&#34;&gt;Getting the immediate children of a node&lt;/h3&gt;

&lt;p&gt;Sometimes you just want to get a list of nodes which are immediately under a given node. This can be done by using a map with the following map function:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;    function(doc) { 
        emit([doc.path.slice(-2,-1)[0], doc.path], doc) 
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This map function simply takes the second-to-last element from the path and uses that as the first element in the key. You can query this view in the same way as the &amp;ldquo;getting a subtree&amp;rdquo; view above.&lt;/p&gt;

&lt;h3 id=&#34;adding-a-node:c3299f700a9c3aa73b011d2d41847148&#34;&gt;Adding a node&lt;/h3&gt;

&lt;p&gt;Adding a node to the tree is fairly simple. Set the new node&amp;rsquo;s path to be the path of the desired parent node with the new node&amp;rsquo;s ID appended to the end. That&amp;rsquo;s it.&lt;/p&gt;

&lt;h3 id=&#34;deleting-a-node:c3299f700a9c3aa73b011d2d41847148&#34;&gt;Deleting a node&lt;/h3&gt;

&lt;p&gt;Deleting a node is a bit trickier since any given node may have some number of children. You can get the list of nodes in the subtree as outlined above and then do a bulk update to delete each of them.&lt;/p&gt;

&lt;p&gt;Depending on the data being stored, deleting the whole sub-tree might not ever be something you want to do, in a discussion forum, for example, you might want to simply delete a single offensive post, leaving any replies which might have been posted. Even in this case, it&amp;rsquo;s more likely that you&amp;rsquo;d want to set a flag indicating the deletion rather than actually deleting the post.&lt;/p&gt;

&lt;h3 id=&#34;moving-a-node-to-another-parent:c3299f700a9c3aa73b011d2d41847148&#34;&gt;Moving a node to another parent&lt;/h3&gt;

&lt;p&gt;This is an instance where being able to update just certain fields in a document would be handly, since bulk-updating a large chunk of documents could start to kill performance.&lt;/p&gt;

&lt;p&gt;Either way, if something needs to be reparented, it&amp;rsquo;s just a matter of getting all nodes which are children of a certain node, then doing a bulk update to change their paths to wherever they need to be.&lt;/p&gt;

&lt;p&gt;This part worries me a bit, because there&amp;rsquo;s a chance that somebody else could add a new child node while you are in the process of moving the sub-tree, leaving that new node dangling by itself in a sub-tree which no longer exists. I&amp;rsquo;m not sure of the best approach to avoid such a problem.&lt;/p&gt;

&lt;h3 id=&#34;conclusion:c3299f700a9c3aa73b011d2d41847148&#34;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;After my initial experimentation, it seems that CouchDB could potentially do a good job handling hierarchical data. It&amp;rsquo;s simpler to understand and implement than Modified Preorder Tree Traversal, but still has the advantage of being able to get a whole tree in a single query, unlike the Adjacency List model.&lt;/p&gt;

&lt;p&gt;I wrote some python code to load in my test data and query the various views I created. It requires &lt;a href=&#34;http://code.google.com/p/couchdb-python/&#34;&gt;CouchDB-Python&lt;/a&gt;, which can be gotten via that link or from EasyInstall by running &lt;em&gt;easy_install CouchDB&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;My code can be found in the &lt;a href=&#34;http://git.paulbonser.com/?p=couchdb.git;a=summary&#34;&gt;appropriate spot&lt;/a&gt; on my Gitweb.&lt;/p&gt;

&lt;div class=&#34;pitch&#34;&gt;
Have some questions? Have an idea for a better way of storing hierarchical data in CouchDB? Any other comments? Then leave a comment below!
&lt;/div&gt;
</description>
    </item>
    
  </channel>
</rss>