<?xml version="1.0" encoding="UTF-8"?>
<!--Generated by Squarespace Site Server v5.5.4 (http://www.squarespace.com/) on Sun, 05 Jul 2009 16:06:57 GMT--><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rss="http://purl.org/rss/1.0/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:cc="http://web.resource.org/cc/"><rss:channel rdf:about="http://medevyoujane.com/blog/"><rss:title>Me Dev, You Jane</rss:title><rss:link>http://medevyoujane.com/blog/</rss:link><rss:description></rss:description><dc:language>en-US</dc:language><dc:date>2009-07-05T16:06:57Z</dc:date><admin:generatorAgent rdf:resource="http://www.squarespace.com/">Squarespace Site Server v5.5.4 (http://www.squarespace.com/)</admin:generatorAgent><rss:items><rdf:Seq><rdf:li rdf:resource="http://medevyoujane.com/blog/2009/4/10/power-couchdb-basic-http-handlers.html"/><rdf:li rdf:resource="http://medevyoujane.com/blog/2009/1/15/the-state-of-me-jan-2009.html"/><rdf:li rdf:resource="http://medevyoujane.com/blog/2008/12/18/erlang-web-development-frameworks.html"/><rdf:li rdf:resource="http://medevyoujane.com/blog/2008/12/12/5-minute-blog-using-nitrogen-and-couchdb.html"/><rdf:li rdf:resource="http://medevyoujane.com/blog/2008/11/23/my-couchdbx-version.html"/><rdf:li rdf:resource="http://medevyoujane.com/blog/2008/11/21/a-knock-knock-joke.html"/><rdf:li rdf:resource="http://medevyoujane.com/blog/2008/11/13/adding-erlang-library-locations.html"/><rdf:li rdf:resource="http://medevyoujane.com/blog/2008/11/1/contact-list-using-sproutcore-mochiweb-and-mnesia.html"/><rdf:li rdf:resource="http://medevyoujane.com/blog/2008/10/4/introducing-erlangx-and-erlangxcode.html"/><rdf:li rdf:resource="http://medevyoujane.com/blog/2008/9/10/erlang-tutorial-sysinfo-server.html"/></rdf:Seq></rss:items></rss:channel><rss:item rdf:about="http://medevyoujane.com/blog/2009/4/10/power-couchdb-basic-http-handlers.html"><rss:title>Power CouchDB - Basic HTTP Handlers</rss:title><rss:link>http://medevyoujane.com/blog/2009/4/10/power-couchdb-basic-http-handlers.html</rss:link><dc:creator>Jón Grétar Borgþórsson</dc:creator><dc:date>2009-04-10T17:22:28Z</dc:date><dc:subject>CouchDBX Erlang</dc:subject><content:encoded><![CDATA[<p>You may know CouchDB's mostly as a kick ass document store but you can use it's base for many great things. Thanks to the fact that CouchDB is an amazingly well written and very modular piece of technology. It is easy to extend it and add your custom code to all areas of CouchDB. If you want to use your own language for views you can add it without even touching the CouchDB code. Write your own authentication handlers connected to LDAP or even CouchDB itself in just a few lines of erlang.</p>

<p>One thing that may interest you are the httpd_global_handlers. They are the little handlers for example behind the /_all_dbs and /_utils paths and more. You can also use them to easily make our own resources and in fact it is by far the simplest way to create a REST resource I know of. So if you are working with json resources it me be worth simply adding a handler in CouchDB rather than making it seperatly using webmachine or other technology. In fact here is an example of how making a resource for the computers environment variables. (Hey it could happen you needed that.)</p>

<script src="http://gist.github.com/105785.js">//Sample Code Inserted By Javascript</script>

<p>Well thats easy. We import a few helper functions from couch_httpd that will handle returning JSON data back to the client. We make a method that takes a #httpd record as a variable and if its path has one part we return all environment variables but if it has 2 parts we return the value of that specific one. In fact in creating this resource there are only a handful of lines that I would even call "my code".</p>

<p>Compile this and put in CouchDB's code path. To use it we just open up local.ini and define our new handler and map to '/_env'.</p>

<pre><code>[httpd_global_handlers]
_env = {my_httpd_handlers, handle_env_req}
</code></pre>

<p>Now just restart and go to <em>http://127.0.0.1/_env</em> and <em>http://127.0.0.1/_env/HOME</em> to see the result. For more complete examples of using handlers just go the the couchdb source and view the couch_httpd_misc_handlers.erl file.</p>]]></content:encoded></rss:item><rss:item rdf:about="http://medevyoujane.com/blog/2009/1/15/the-state-of-me-jan-2009.html"><rss:title>The State of Me - Jan 2009</rss:title><rss:link>http://medevyoujane.com/blog/2009/1/15/the-state-of-me-jan-2009.html</rss:link><dc:creator>Jón Grétar Borgþórsson</dc:creator><dc:date>2009-01-15T15:15:02Z</dc:date><dc:subject>Arduino CouchDBX ErlangXCode Git Nitrogen Personal</dc:subject><content:encoded><![CDATA[<p>Well. Just a little status update on me and my various projects for 2008.  </p>

<p>2008 was a good year for me and my education as a developer. I got to know <a href="http://erlang.org">Erlang</a> at the middle of the year and by the end of the year I was almost exclusively coding in Erlang. I have also started learning some standard C for playing with <a href="http://arduino.cc">Arduino</a>. I also learned the basics of Emacs and so far I like it though I still use <a href="http://macromates.com">Textmate</a> for many things. And I started using <a href="http://git-scm.com">Git</a> and <a href="http://github.com">Github</a>. I was to begin with skeptical about it and the fact that Linus Thorvalds was <a href="http://www.youtube.com/watch?v=4XpnKHJAok8">a bit of a dick</a> when talking about it didn't help. But once I tried it I found it to be very productive and combined with GitHub it's quickly revolutionizing open source development in the world.</p>

<p>I became a contributor to the <a href="http://nitrogenproject.com/">Nitrogen Web Framework</a>. I have many ideas for it and hope to add many things to it. Nitrogen is at a very exciting stage as we are finding the path we want to take and can make many choices at this stage.</p>

<p>Is started playing with a little project I call <a href="http://github.com/JonGretar/couchmail-poc">CouchMail</a>. It's basically a quick ugly hack to research gluing together a mail server with <a href="http://nitrogenproject.com">Nitrogen</a>, <a href="http://cappuccino.org/">Cappuccino</a>, Mochiweb and finally <a href="http://couchdb.org/">CouchDB</a> for data storage. If this works out ok I may consider writing a real application from scratch from what I learn.</p>

<p>I forked <a href="https://github.com/JonGretar/couchdbx">CouchDB<em>X</em></a> and completely rewrote the UI. I like my changes as they remove CouchDB from the desktop and you don't have to know about it until it is needed. I have most of the new code needed for CouchDB 0.9.0 ready so it should come out as soon as the new CouchDB is released.</p>

<p><a href="http://github.com/JonGretar/erlangxcode">ErlangXcode</a> is an attempt to make Apple's <a href="http://apple.com/xcode">Xcode 3 IDE</a> be a kick ass Erlang IDE. A lot of the basic syntax is there with some, like records, still to be implemented. Also a basic build system in place and compilation errors show up in-code. I had to take a bit a break from it before going nuts though. Xcode's plugin system is 100% undocumented and there is no way do debug anything. What you have to do is to make small changes, compile and then reboot Xcode. There are no errors. The code just works, quietly doesn't work or it crashes Xcode. Hopefully I will quickly have energy to deal with it again soon. I did however start a little wiki project at <a href="http://code.google.com/p/xcode-plugin/">google code</a> documenting the xcode plugin system.</p>

<p>Finally there is a little project I started in the middle of the year called AstAssist. It's in a bit of a pause at the moment but basically it is an Erlang based system for <a href="http://asterisk.org/">Asterisk</a> management. It's a complete solution for configuration, monitoring, event parsing, fastagi and so on. I have some of the basics done and hope to continue later in the year.</p>

<p>Well.. That's the bullet points. Hope some or all of these will become something amazing in 2009.</p>
]]></content:encoded></rss:item><rss:item rdf:about="http://medevyoujane.com/blog/2008/12/18/erlang-web-development-frameworks.html"><rss:title>Erlang Web Development Frameworks</rss:title><rss:link>http://medevyoujane.com/blog/2008/12/18/erlang-web-development-frameworks.html</rss:link><dc:creator>Jón Grétar Borgþórsson</dc:creator><dc:date>2008-12-18T16:11:13Z</dc:date><dc:subject>Erlang Nitrogen</dc:subject><content:encoded><![CDATA[<h3>Web Frameworks.</h3>

<p>I'm going to mention the two of the most interesting web frameworks out there. They choose a very different path and I would call both of them production ready. As they are both projects in active development you might have a problem with a new release breaking a few things.</p>

<h4><a href="http://github.com/rklophaus/nitrogen/wikis">Nitrogen</a></h4>

<p>Nitrogen is the new kid on the scene but has quickly become my favorite framework. Unlike most frameworks it's  <a href="http://yuiblog.com/blog/2007/01/17/event-plan/">event driven</a>. I enjoy it even more than Rails at the moment. It's dead simple to get started in and very powerful. It's in very active development and new and cool features are added almost weekly. The last new feature added was the simplest but one of the most powerful Comet implementation out there. </p>

<p>ONe of it's drawbacks is that there is no routing system in it. Paths are defined by the module names. So <strong>web_index.erl</strong> becomes <em>/web/index</em> or <em>/web</em> and <strong>web_blog_comment.erl</strong> becomes <em>/web/blog/comment</em>. Some might find this a bit limiting.</p>

<p>There are many cool features planned and one of the most interesting is implementing Erlangs power to be a distributed web frameworks. Thus solving many of the problems of scalability that many other web frameworks have</p>

<p><strong>Pros:</strong></p>

<ul>
<li>Dead simple.</li>
<li>Nice bindings system.</li>
<li>Kick ass Comet support.</li>
<li>Interesting future ideas.</li>
</ul>

<p><strong>Cons:</strong></p>

<ul>
<li>No routing at the moment.</li>
<li>A little too simple on the template side.</li>
<li>Really young so no real documentation yet.</li>
</ul>

<h4><a href="http://www.erlang-web.org/">Erlang Web</a></h4>

<p>I have not much experience with Erlang Web but many seem to have started using it. It's and MVC framework built on OTP principles and uses many standard Erlang practices. It's template system on first view reminds me a bit of good old WebObjects. Currently it supports INETS and Yaws but not MochiWeb at the moment.</p>

<p><strong>Pros:</strong></p>

<ul>
<li>Very Flexible.</li>
<li>Powerful template language.</li>
<li>OTP Principles.</li>
</ul>

<p><strong>Cons:</strong></p>

<ul>
<li>Could be simpler.</li>
<li>Needs way better documentation.</li>
</ul>

<h3>Template Languages</h3>

<p>Sometimes you may just want something simpler. Just a little template engine on a custom built web server to show some dynamic data. Or for use in your own web framework. Here are 2 notable template engines.</p>

<h4><a href="http://github.com/kevsmith/herml">HERML</a></h4>

<p>HERML is an erlang implementation of the <a href="http://haml.hamptoncatlin.com/">HAML</a> markup language. It's quick and simple but remember that this skips HTML altogether so it might not be for everyone.</p>

<h4><a href="http://code.google.com/p/erlydtl/">ErlyDTL</a></h4>

<p>ErlyDTL is an erlang implementation of the Django Template Language. I personally found DTL to be Django's most anoying feature but as many people like it it's best to mention it.</p>
]]></content:encoded></rss:item><rss:item rdf:about="http://medevyoujane.com/blog/2008/12/12/5-minute-blog-using-nitrogen-and-couchdb.html"><rss:title>5 Minute Blog Using Nitrogen and CouchDB</rss:title><rss:link>http://medevyoujane.com/blog/2008/12/12/5-minute-blog-using-nitrogen-and-couchdb.html</rss:link><dc:creator>Jón Grétar Borgþórsson</dc:creator><dc:date>2008-12-12T03:16:58Z</dc:date><dc:subject>Erlang Nitrogen</dc:subject><content:encoded><![CDATA[<h3>Introduction</h3>

<p>Hey. Today I'm going to show you how to create a really, really simple blog in a few minutes using the <a href="http://nitrogenproject.com/">Nitrogen Web Framework</a> and the <a href="http://couchdb.org">CouchDB</a> document system. I presume you have basic erlang skills but this should be simple for anyone. I also presume you have already seen the <a href="nitrogen-erlang.tumblr.com/">Nitrogen Screencasts</a> and are familiar with the basic behavior of Nitrogen.</p>

<h3>Ingredients</h3>

<p>Here is what yo will need: </p>

<ul>
<li><a href="http://nitrogenproject.com/">Nitrogen</a></li>
<li><a href="http://couchdb.org">CouchDB</a> (or CouchDBX)</li>
<li><a href="http://ecouch.googlecode.com/">Ecouch</a></li>
<li><a href="http://medevyoujane.com/storage/tutorial-data/erlang/5MinBlog-Extra.zip">Extra Files</a></li>
</ul>

<p>I assume that Ecouch and Nitrogen are set up in the library path (see <a href="http://wiki.github.com/rklophaus/nitrogen/installing-nitrogen">here</a> for installation info). If you need any further help on this see <a href="http://medevyoujane.com/blog/2008/8/6/installing-erlang-and-a-few-libraries-on-mac-os-x.html">this post</a></p>

<p>If you are using Mac OS 10.5 I recommend you use my implementation of <a href="http://medevyoujane.com/blog/2008/11/23/my-couchdbx-version.html">CouchDBX</a> to get you started quickly.</p>

<p>First we create a new project in a location of your choosing with the command </p>

<pre><code>nitrogen create myblog
</code></pre>

<p>In there you will see a basic project to get started with. Now unzip the <a href="http://medevyoujane.com/storage/tutorial-data/erlang/5MinBlog-Extra.zip">Extra Files</a> and copy the files to your project. You will see a basic template I have set up for you at <strong>wwwroot/template.html</strong>. You will also see the module <strong>json_obj</strong> wich I savagely stole from the <a href="http://beebole.com/blog/2008/10/20/tutorial-web-application-erlang/">StickyNotes</a> tutorial. It's basically a module that will assist you dealing with  JSON data  in Erlang. As JSON's data types are incompatible with Erlang it's best to grab help wherever you can.</p>

<p>First we will need to start ecouch. Open up <strong>src/myblog_app.erl</strong> and modify start() to start up ecouch before nitrogen</p>

<pre><code>start(_, _) -&gt; 
  application:start(ecouch),
  nitrogen:start().
</code></pre>

<p>To start the development server open up a terminal to the project root, type in "<code>./start.sh</code>" and visit the website <a href="http://localhost:8000">http://localhost:8000</a>. You should see a nice website with the body "web_index body.". Whenever you change the code in the project you will have to recompile with the command "<code>sync:go().</code>".</p>

<h3>CouchDB</h3>

<p>First thing we want to do is create the database and our view. Open up CouchDB at <a href="http://127.0.0.1:5984/_utils/">http://127.0.0.1:5984/_utils/</a>, create a new database and name it "myblog". Next we are going to need a convenient view for Nitrogen. We are going to create a really simple view that returns a simple array with first the title and then the body. This makes it easy for us when we need to map the data later in Nitrogen as you will see later. We are also going to use the field timestamp as a key so the data is in time order.</p>

<p>To do that we select "Custom Query" under "Select view". Expand the "View Code" flap and replace the map function with the following.</p>

<pre><code>function(doc) {
  emit(doc.timestamp, [doc.title, doc.body]);
}
</code></pre>

<p>Select "Save As" and save as the design document: "nitrogen" and view name: "flat".</p>

<h3>The Model</h3>

<p>We could call the data from the pages themselves but I prefer to create a little model class to seperate the logic. Create the file <em>blog_posts.erl</em> inside src and export <em>get_posts/0</em> and <em>add_post/1</em>. First create the get_post/1.</p>

<pre><code>get_posts() -&gt;
    {ok, Return} = ecouch:view_access("myblog", "nitrogen", "flat"),
    RawRows = json_obj:get_value("rows", Return),
    F = fun(X) -&gt;
            json_obj:get_value("value", X)
    end,
    Rows = lists:map(F, RawRows),
    lists:reverse(Rows).
</code></pre>

<p>First of all we made a call to CouchDB using ecouch requesting the <em>nitrogen/flat</em> view for the <em>myblog</em> database. Now as Erlang has incompatible types to JSON there is a lot of ugly extra data in the raw return which looks like this</p>

<pre><code>{obj,[{"total_rows",2},
          {"offset",0},
          {"rows",
           [{obj,[{"id",&lt;&lt;"b8ffeaa68f2fd4010a105ddc56460466"&gt;&gt;},
                  {"key",123},
                  {"value",[&lt;&lt;"The Title"&gt;&gt;,&lt;&lt;"TheBody"&gt;&gt;]}]},
            {obj,[{"id",&lt;&lt;"53b075b3633f8d8b3654576806ef18b3"&gt;&gt;},
                  {"key",321},
                  {"value",[&lt;&lt;"Another Title"&gt;&gt;,&lt;&lt;"Another Body"&gt;&gt;]}]}]}]}
</code></pre>

<p>Now thats not very pretty is it so we use the json_obj module to query the value of "rows" so we don't have to parse this data by hand. We then make a fun that does the same thing for the "value" field of a row and use the map function to call it on each of the rows. We then reverse the list so the latest post is first. After doing all this the result of the function would be as following:</p>

<pre><code>[ [&lt;&lt;"Another Title"&gt;&gt;,&lt;&lt;"Another Body"&gt;&gt;], [&lt;&lt;"The Title"&gt;&gt;,&lt;&lt;"TheBody"&gt;&gt;] ]
</code></pre>

<p>Ahh... Much Nicer.</p>

<p>We also need to create the data so we add the add_post/1 method.</p>

<pre><code>add_post({post, Title, Body}) -&gt;
    JSONTemplate = {obj, []},
    WithTitle = json_obj:set_value("title", list_to_binary(Title), JSONTemplate),
    WithTitleAndBody = json_obj:set_value("body", list_to_binary(Body), WithTitle),
    Complete = json_obj:set_value("timestamp", calendar:time_to_seconds(now()), WithTitleAndBody),
    ecouch:doc_create("myblog", Complete).
</code></pre>

<p>This does not need much explanation. We start by creating an empty JSON object so that we can use the  json_obj functions on it. We then add the Title and Body parameters to the object and create a timestamp as well. Finally we ask ecouch to create the document.</p>

<h3>The Index Page</h3>

<p>Now edit the file called <em>src/pages/web_index.erl</em> and edit the function body() to look like this.</p>

<pre><code>body() -&gt;
    Data = blog_posts:get_posts(),
    Map = [titleHeader@text, bodyLabel@text],
    #bind { id=simpleBinding, data=Data, map=Map, body=[
        #panel { class="post", body=[
            #h2 { class="title", id=titleHeader },
            #panel { class="entry", body=[
                #label{ id=bodyLabel }
            ]}
        ]}
    ]}.
</code></pre>

<p>The main thing here is the data binding. We first take the output from our model and bind it to <em>Data</em>. As you remember the output of the model is a list of lists. Then we create the Map to describe how the elements of those lists should should bind to the page elements. So we are saying that the first element should bind to the "text" variable on the element with the id "titleHeader". We then use the #bind record, which is a sort of a for loop, and feed to it the Data and the Map.</p>

<p>You should now be able to sync and go see the webpage. Of course you can not see anything yes as we have yet to create any data.</p>

<h3>The Create Page</h3>

<p>Next create a new page using the command <code>nitrogen page /web/create</code> in your project root. Open up the newly generate <strong>src/pages/web_create.erl</strong> and replace body():</p>

<pre><code>body() -&gt;
    Body = [
        #label { text="Title:" },
        #textbox{ id=titleTextBox, class="create_title", next=body },
        #label { text="Body (HTML Allowed):" }, 
        #textarea{ id=bodyTextArea, class="create_body" },
        #br {},
        #link{ id=commitButton, text="Submit", postback=commit }
    ],

    %% Validations
    wf:wire(commitButton, titleTextBox, #validate { validators=[
        #is_required { text="Required." },
        #min_length { length=2, text="Title must be at least 2 characters long." }
    ]}),
    wf:wire(commitButton, bodyTextArea, #validate { validators=[
        #is_required { text="Required." }
    ]}),

    %% Render
    wf:render(Body).
</code></pre>

<p>Next up add a new event() just above the line that says ´event(_) -> ok.´</p>

<pre><code>event(commit) -&gt;
    [Title] = wf:q(titleTextBox),
    [Body] = wf:q(bodyTextArea),
    blog_posts:add_post({post, Title, Body}),
    Message = wf:f("Post ~p created. &lt;a href=\"/web/index\"&gt;click here&lt;/a&gt; to see it.", [Title]),
    wf:flash(Message);
</code></pre>

<p>There is nothing really complicated here as we have made most of the work already in the model. We set up a textfield and a textarea. We then bind the commitButton the generate the commit event. We then set up Validations so we can't submit empty data.</p>

<p>The commit event takes the value of the titleTextBox and bodyTextArea and sends it's data to <em>blog_posts:add_post/1</em>. It then formats a nice message and flashes it to the user.</p>

<p>Now sync and visit the page. Enter the create page and try submitting empty field. Then fill in the data and add a few posts. Visit the Index page to view your posts.</p>

<h3>Conclusion</h3>

<p>Even though this is not a very thorough nor complex tutorial it really shows how easily you can use together these two projects and create something really powerful with little code.</p>

<p>If you hit a problem please check my completed code <a href="http://medevyoujane.com/storage/tutorial-data/erlang/5MinBlog-Complete.zip">here</a></p>
]]></content:encoded></rss:item><rss:item rdf:about="http://medevyoujane.com/blog/2008/11/23/my-couchdbx-version.html"><rss:title>My CouchDBX version</rss:title><rss:link>http://medevyoujane.com/blog/2008/11/23/my-couchdbx-version.html</rss:link><dc:creator>Jón Grétar Borgþórsson</dc:creator><dc:date>2008-11-23T21:31:00Z</dc:date><dc:subject>Cocoa CouchDBX Erlang</dc:subject><content:encoded><![CDATA[<p>Hey people.</p>

<p>I have been playing with <a href="http://jan.prima.de/~jan/plok/archives/142-CouchDBX-Revival.html">Jan's CouchDB<em>X</em></a> a bit and thought someone might enjoy what I did. CouchDBX is a nice little Mac OS X tool to run CouchDB without the need to set up Erlang or anything.</p>

<p>There are 3 major changes that I did. First of the UI is gone and everything is now in a status bar menu. Should make for quicker access to it and also stay out of the way. There is also a new transparent log window if you need to see what is happening on the Erlang level. The third an most important change is that CouchDBX now stores it's database in <strong>~/Documents/CouchDB</strong>. Before the database was inside the Application bundle itself and all the data disappeared every time you downloaded a new release of CouchDBX.</p>

<p>I have not renamed it or anything in case <a href="http://jan.prima.de/">Jan</a> would like to incorporate these changes to the original code or something.</p>

<p><strong>EDIT 26. Nov:</strong> There was a serious error in my old version that made the javascript engine not run correctly. This has now been fixed and you need to redownload.</p>

<ul>
<li><a href="http://dl-client.getdropbox.com/u/65508/CouchDBX.zip">Download</a></li>
<li><a href="http://github.com/JonGretar/couchdbx">My Source</a></li>
</ul>

<p><span class="full-image-block ssNonEditable"><span><img src="http://medevyoujane.com/storage/couchdbx/couchDBX-screenshot.png?__SQUARESPACE_CACHEVERSION=1227476827269" alt="CouchDBX Screenshot"/></span></span></p>
]]></content:encoded></rss:item><rss:item rdf:about="http://medevyoujane.com/blog/2008/11/21/a-knock-knock-joke.html"><rss:title>A knock knock joke</rss:title><rss:link>http://medevyoujane.com/blog/2008/11/21/a-knock-knock-joke.html</rss:link><dc:creator>Jón Grétar Borgþórsson</dc:creator><dc:date>2008-11-21T12:07:33Z</dc:date><dc:subject>Erlang</dc:subject><content:encoded><![CDATA[<p>Just a quick one in the morning.</p>

<pre><code>-module(knockknock).
-compile(export_all).

start_joke() -&gt;
    register(person_1, erlang:spawn(knockknock, person1, [])),
    register(person_2, erlang:spawn(knockknock, person2, [])),
    person_1 ! start_joke.

relay(Person, Message) -&gt;
    io:format("------- ~p -------~n", [Message]),
    Person ! Message.

person1() -&gt;
    receive 
        start_joke -&gt;
            relay(person_2, "Knock, Knock");
        "Who's There?" -&gt;
            timer:sleep(100000),
            relay(person_2, "Java")
    end,
    person1().

person2() -&gt;
    receive
        "Knock, Knock" -&gt;
            relay(person_1, "Who's There?");
        "Java" -&gt;
            relay(person_1, "Ha Ha")
    end,
    person2().
</code></pre>
]]></content:encoded></rss:item><rss:item rdf:about="http://medevyoujane.com/blog/2008/11/13/adding-erlang-library-locations.html"><rss:title>Adding Erlang library locations</rss:title><rss:link>http://medevyoujane.com/blog/2008/11/13/adding-erlang-library-locations.html</rss:link><dc:creator>Jón Grétar Borgþórsson</dc:creator><dc:date>2008-11-13T19:36:05Z</dc:date><dc:subject>Erlang</dc:subject><content:encoded><![CDATA[<p>When adding Erlang libraries there are a few possible ways. The easy way is to add the libraries into the directory <em>/usr/local/lib/erlang/lib</em>. All directories there will be added to the library paths by default. The problem with that is that I don't like mixing 3rd party libraries with the core libraries. </p>

<p>Enter the ERL_LIBS environment variable. Set that to a directory and all the subdirectories of it that include code will the added automatically to the code path. To add it open up the file <em>/etc/bashrc</em> and add the following:</p>

<pre><code>ERL_LIBS=/Library/Erlang/lib
if [ -d $HOME/Library/Erlang/lib ]; then
  ERL_LIBS=$HOME/Library/Erlang/lib:$ERL_LIBS
fi
export ERL_LIBS
</code></pre>

<p>This way all libraries under /Library/Erlang/lib and /Users/JoeUser/Library/Erlang/lib will be added to Erlangs code paths. The libraries will be in priority before the system libraries but after the -pa code paths. Now you can add things like Mochiweb, Eunit, Nitrogen and more under the /Library/Erlang/lib directory.</p>

<p>You could also put this in the file <em>/usr/local/bin/erl</em></p>
]]></content:encoded></rss:item><rss:item rdf:about="http://medevyoujane.com/blog/2008/11/1/contact-list-using-sproutcore-mochiweb-and-mnesia.html"><rss:title>Contact List using SproutCore, Mochiweb and Mnesia</rss:title><rss:link>http://medevyoujane.com/blog/2008/11/1/contact-list-using-sproutcore-mochiweb-and-mnesia.html</rss:link><dc:creator>Jón Grétar Borgþórsson</dc:creator><dc:date>2008-11-01T21:01:02Z</dc:date><dc:subject>Erlang</dc:subject><content:encoded><![CDATA[<p>Here is an example program using a <a href="http://sproutcore.com/">SproutCore</a> frontend talking to an <a href="http://erlang.org">Erlang</a> backend using the ReST protocol.</p>

<h2>Sproutcore</h2>

<p>Lets start by creating the Sproutcore application. I will not go into detail into the Sproutcore code as JavaScript and Sprutcore are way beyond a single tutorial. </p>

<pre><code>sc-init mochi_contacts
cd mochi_contacts
</code></pre>

<p>Inside <code>mochi_contacts</code> we find a nice little framework for our application. Lets start by creating our model with the command. "<code>sc-gen model mochi_contacts/contacts</code>". Then we edit our model at <strong>clients/mochi_contacts/model/contacts.js</strong> and add the following code.</p>

<pre><code>resourceURL: 'contacts',
properties: ["guid","fullname",'email','mobile'],

commitChanges: function(){
    if(this.get('fullname') == '') this.set('fullname', 'Unnamed');
    this.commit();
}
</code></pre>

<p>This is pretty straight forward. resourceURL defines the location of the data source. In this case it would be http://localhost/contacts/. In properties we define the keys we want to read from that resource. The commitChanges function then makes sure we have the fullname property defined and commits the changes to the resource.</p>

<p>Next up is our master controller. The master contoller handles our list view at the side. Create it with the command "<code>sc-gen controller mochi_contacts/master SC.CollectionController</code>", open up the file <strong>clients/mochi_contacts/controller/masterController.js</strong> and add the following.</p>

<pre><code>allowsEmptySelection: false,
allowsMultipleSelection: false,
canEditCollection: true,

addContact: function(sender){
    var content = this.get('content');
    var contact = MochiContacts.Contacts.newRecord({
        fullname: "Unnamed"
    },MochiContacts.server);

    contact.commitChanges();
    this.set('selection',[contact]);
},

delContact: function(sender){
    if(!confirm('Are you sure?')) return;
    var sel = (this.get('selection') || []).clone() ;
    var idx = sel.get('length') ;
    while(--idx &gt;= 0) {
        var contact = sel.objectAt(idx);
        contact.destroy();
    }
},
</code></pre>

<p>Not much to see here. Just basic functions for creating and deleting contacts from the list and 3 properties for defining the behaviour of the list view.</p>

<p>So now we need a second controller that will handle the form itself. Create it with the command "<code>sc-gen controller mochi_contacts/detail SC.ObjectController</code>" and put the following inside <strong>clients/mochi_contacts/controller/detailController.js</strong></p>

<pre><code>contentBinding: 'MochiContacts.masterController.selection',
commitChangesImmediately: false
</code></pre>

<p>Wow. Even less we do here. We simply bind the content of the controller to the currently selected object of the master controller. We then define that we dont want the changes to be posted automatically because we will add a button to do that.</p>

<p>Now we have to define the view. Open up <strong>clients/mochi_contacts/english.lproj/body.rhtml</strong> and remove everything. Replace with the following:</p>

<pre><code>&lt;% content_for('body') do %&gt;

&lt;% split_view :workspace, :class =&gt; 'sc-app-workspace footer', 
    :direction =&gt; :horizontal do %&gt;  
  &lt;% view :sidebar, :outlet =&gt; true do %&gt;
    &lt;% scroll_view :master_list, :outlet =&gt; true do %&gt;
      &lt;%= list_view :list_view, 
            :outlet =&gt; true, 
            :content_value_key =&gt; 'fullname', 
            :content_value_editable =&gt; false,
            :can_reorder_content =&gt; true,
            :bind =&gt; { 
              :content =&gt; 'MochiContacts.masterController.arrangedObjects', 
              :selection =&gt; 'MochiContacts.masterController.selection' 
            }
            %&gt;
    &lt;% end %&gt;
  &lt;% end %&gt;

  &lt;%= split_divider_view :outlet =&gt; true, :width =&gt; 5 %&gt;

  &lt;% view :detail_view, :outlet =&gt; true do %&gt;
    &lt;table class="card-detail"&gt;

      &lt;tr&gt;
        &lt;td&gt;&lt;label&gt;Full Name:&lt;/label&gt;&lt;/td&gt;
        &lt;td&gt;
          &lt;%= text_field_view :outlet =&gt; true, :hint =&gt; "Full Name",
            :bind =&gt; {
              :value =&gt; 'MochiContacts.detailController.fullname'
            } %&gt;
        &lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td&gt;&lt;label&gt;Email:&lt;/label&gt;&lt;/td&gt;
        &lt;td&gt;
          &lt;%= text_field_view :outlet =&gt; true, :hint =&gt; "email@email.com",
            :bind =&gt; {
              :value =&gt; 'MochiContacts.detailController.email'
            } %&gt;
        &lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td&gt;&lt;label&gt;Mobile:&lt;/label&gt;&lt;/td&gt;
        &lt;td&gt;
          &lt;%= text_field_view :outlet =&gt; true, :hint =&gt; "555-0000",
            :bind =&gt; {
              :value =&gt; 'MochiContacts.detailController.mobile'
            } %&gt;
        &lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td colspan="2" class="buttons"&gt;
          &lt;%= button_view :outlet =&gt; true, 
            :title =&gt; "Cancel",
            :action =&gt; 'MochiContacts.detailController.discardChanges',
            :bind =&gt; {
              :enabled =&gt; 'MochiContacts.detailController.hasChanges'
            } %&gt;
          &lt;%= button_view :outlet =&gt; true, 
            :title =&gt; "Save Changes", :default =&gt; true,
            :action =&gt; 'MochiContacts.detailController.commitChanges',
            :bind =&gt; {
              :enabled =&gt; "MochiContacts.detailController.hasChanges"
            } %&gt;
        &lt;/td&gt;
      &lt;/tr&gt;
    &lt;/table&gt;

  &lt;% end %&gt;
&lt;% end %&gt;

&lt;% view :footer, :class =&gt; 'sc-footer sc-square-theme' do %&gt;
  &lt;div class="left"&gt;
    &lt;%= button_view :outlet =&gt; true, :label =&gt; '+', 
        :action =&gt; 'MochiContacts.masterController.addContact' %&gt;
    &lt;%= button_view :outlet =&gt; true, :label =&gt; '-', 
        :action =&gt; 'MochiContacts.masterController.delContact' %&gt;
  &lt;/div&gt;

&lt;% end %&gt; &lt;!-- footer --&gt;

&lt;% end %&gt;
</code></pre>

<p>In here we have defined the views and bound their properties to the controllers.</p>

<p>Next we connect the contollers to the model. We do that inside <strong>clients/mochi_contacts/main.js</strong> by replacing the line <code>MochiContacts.server.preload(MochiContacts.FIXTURES);</code> with the following commands:</p>

<pre><code>var contactList = MochiContacts.Contacts.collection();
contactList.refresh();
MochiContacts.masterController.set('content', contactList);
MochiContacts.server.listFor(contactList);
</code></pre>

<p>Before we move to the Erlang part we have to edit <strong>sc-config</strong>. As javascript request are bound to it's own domain we have to proxy the request by adding this as the very last line:</p>

<pre><code>proxy '/contacts', :to =&gt; 'localhost:8808', :cookie_domain =&gt; 'localhost'
</code></pre>

<p>Now you should be able to start the server with the command <code>sc-server</code> and take a look at the result in <em>http://localhost:4020/mochi_contacts</em>.</p>

<h2>The Format</h2>

<p>The format SproutCore uses for REST calls are:</p>

<ul>
<li>CREATE = <strong>[POST]</strong>http://somesite/resource/create </li>
<li>READ = <strong>[GET]</strong>http://somesite/resource/list </li>
<li>UPDATE = <strong>[POST]</strong>http://somesite/resource/updateGUIDNUMBER </li>
<li>DELETE = <strong>[POST]</strong>http://somesite/resource/DESTROYGUIDNUMBER </li>
</ul>

<p>The Post values for CREATE and UPDATE methods are like:</p>

<pre><code>"records[0][mobile]" = "555-1234"
"records[0][email]" = "sam.jones@example.com"
"records[0][fullname]" = "Sam Joness"
"records[0][id]" =  "@658"
</code></pre>

<p>The body expected to return for the READ method is in JSON format and looks like:</p>

<pre><code>{"records": [
    { 
    "guid": "@570",
    "type": "Contacts",
    "fullname": "Frank Smith",
    "email": "frank.smith@example.com",
    "mobile": "555-4433"
    },{
    "guid": "@658",
    "type": "Contacts",
    "fullname": "Sam Jones",
    "email": "sam.jones@example.com",
    "mobile": "555-1234"
    }],
"ids": ["@570", "@658"]
}
</code></pre>

<p>Each record needs to have guid and type must be the name of the model it belongs to. ids must be a list of all the guid keys.</p>

<p>For mochijson2:encode/1 to be able to create this from an erlang term the format of the erlang term would be:</p>

<pre><code>{struct,[{&lt;&lt;"records"&gt;&gt;,
          [{struct,[{&lt;&lt;"guid"&gt;&gt;,&lt;&lt;"@570"&gt;&gt;},
                    {&lt;&lt;"type"&gt;&gt;,&lt;&lt;"Contacts"&gt;&gt;},
                    {&lt;&lt;"fullname"&gt;&gt;,&lt;&lt;"Frank Smith"&gt;&gt;},
                    {&lt;&lt;"email"&gt;&gt;,&lt;&lt;"frank.smith@example.com"&gt;&gt;},
                    {&lt;&lt;"mobile"&gt;&gt;,&lt;&lt;"555-4433"&gt;&gt;}]},
           {struct,[{&lt;&lt;"guid"&gt;&gt;,&lt;&lt;"@658"&gt;&gt;},
                    {&lt;&lt;"type"&gt;&gt;,&lt;&lt;"Contacts"&gt;&gt;},
                    {&lt;&lt;"fullname"&gt;&gt;,&lt;&lt;"Sam Jones"&gt;&gt;},
                    {&lt;&lt;"email"&gt;&gt;,&lt;&lt;"sam.jones@example.com"&gt;&gt;},
                    {&lt;&lt;"mobile"&gt;&gt;,&lt;&lt;"555-1234"&gt;&gt;}]}]},
         {&lt;&lt;"ids"&gt;&gt;,[&lt;&lt;"@570"&gt;&gt;,&lt;&lt;"@658"&gt;&gt;]}]}
</code></pre>

<h2>The Mochiweb Server</h2>

<p>Knowing the expected formats it should be easy to write a mochiweb server to handle this. This is my version. Possibly one of my worst Erlang code but after spending way to much time figuring out mochijson2 I'm just putting this out there. (How about some documentation mochiguys? ;)</p>

<pre><code>-module(web_server).
-include_lib("stdlib/include/qlc.hrl").
-export([start/0,stop/0,dispatch_requests/1]).
-record (contacts, {guid, type, fullname, email, mobile}).

start() -&gt;
    mnesia:create_schema([node()]),
    mnesia:start(),
    try
        mnesia:table_info(contacts, type)
    catch
        exit: _ -&gt;
            mnesia:create_table(contacts, 
                [{attributes, record_info(fields, contacts)},
                {type, set},
                {disc_copies, [node()]}])
    end,
    mochiweb_http:start([{port, 8808},{loop, fun dispatch_requests/1}]).

stop() -&gt;
    mochiweb_http:stop().

dispatch_requests(Req) -&gt;
    Path = Req:get(path),
    Method = Req:get(method),
    Post = Req:parse_post(),
    io:format("~p request for ~p with post: ~p~n", [Method, Path, Post]),
    Response = handle(Method, Path, Post),
    Req:respond(Response).


handle('GET', "/contacts/list", _Post) -&gt;
    F = fun() -&gt;
        Q = qlc:q([ build_struct(C) || C &lt;- mnesia:table(contacts) ]),
        Q2 = qlc:q(
            [ list_to_binary(C#contacts.guid) || C &lt;- mnesia:table(contacts) ]),
        Records = qlc:e(Q),
        IDs = qlc:e(Q2),
        Struct = {struct, [{&lt;&lt;"records"&gt;&gt;, Records},{&lt;&lt;"ids"&gt;&gt;, IDs}]},
        JSON = mochijson2:encode(Struct),
        list_to_binary(JSON)
    end,
    {atomic, Result} = mnesia:transaction(F),
    {200, [{"Content-Type", "text/javascript"}], Result };

handle('POST', "/contacts/create", Post) -&gt;
    Guid = proplists:get_value("records[0][_guid]", Post),
    FullName = proplists:get_value("records[0][fullname]", Post),
    Email = proplists:get_value("records[0][email]", Post),
    Mobile = proplists:get_value("records[0][mobile]", Post),
    F = fun() -&gt;
          mnesia:write(#contacts{
            guid=Guid, type="Contacts", fullname=FullName, 
            email=Email, mobile=Mobile}) 
    end,
    mnesia:transaction(F),
    {200, [{"Content-Type", "text/plain"}], &lt;&lt;"Created"&gt;&gt; };

handle('POST', "/contacts/update"++Guid, Post) -&gt;
    FullName = proplists:get_value("records[0][fullname]", Post),
    Email = proplists:get_value("records[0][email]", Post),
    Mobile = proplists:get_value("records[0][mobile]", Post),
    F = fun() -&gt;
          mnesia:write(#contacts{
            guid=Guid, type="Contacts", fullname=FullName, 
            email=Email, mobile=Mobile}) 
    end,
    mnesia:transaction(F),
    {200, [{"Content-Type", "text/plain"}], &lt;&lt;"Updated"&gt;&gt; };

handle('POST', "/contacts/destroy"++Guid, _Post) -&gt;
    F = fun() -&gt;
          mnesia:delete({contacts, Guid}) 
    end,
    mnesia:transaction(F),
    {200, [{"Content-Type", "text/plain"}], &lt;&lt;"Destoyed"&gt;&gt; };

handle(_, _, _) -&gt;
    {404, [{"Content-Type", "text/plain"}], &lt;&lt;"Unknown Request"&gt;&gt;}.

build_struct(Record) -&gt;
    {struct, [
        {&lt;&lt;"guid"&gt;&gt;, list_to_binary(Record#contacts.guid)},
        {&lt;&lt;"type"&gt;&gt;, list_to_binary(Record#contacts.type)},
        {&lt;&lt;"fullname"&gt;&gt;, list_to_binary(Record#contacts.fullname)},
        {&lt;&lt;"email"&gt;&gt;, list_to_binary(Record#contacts.email)},
        {&lt;&lt;"mobile"&gt;&gt;, list_to_binary(Record#contacts.mobile)}
    ]}.
</code></pre>

<p>Just compile this and start with <code>web_server:start()</code>.</p>

<p><a href="http://medevyoujane.com/storage/tutorial-data/erlang/mochi_contacts.zip">Download the source</a></p>
]]></content:encoded></rss:item><rss:item rdf:about="http://medevyoujane.com/blog/2008/10/4/introducing-erlangx-and-erlangxcode.html"><rss:title>Introducing ErlangX and ErlangXCode</rss:title><rss:link>http://medevyoujane.com/blog/2008/10/4/introducing-erlangx-and-erlangxcode.html</rss:link><dc:creator>Jón Grétar Borgþórsson</dc:creator><dc:date>2008-10-04T16:06:51Z</dc:date><dc:subject>Erlang ErlangX ErlangXCode</dc:subject><content:encoded><![CDATA[<p>I just started 2 little projects called ErlangX and ErlangXCode.</p>

<p><strong>ErlangX</strong> is basically an installation of the Erlang/OTP system. Basically it is installed in 2 locations. in <em>/Library/Frameworks/Erlang.framework</em> we have the standard Erlang installation with the standard libraries. In /Library/Erlang/lib there are a few other popular libraries preinstalled for you. In there would also go other libraries you would like to install system wide.</p>

<p>Erlang will also look into the directory <em>/Users/USERNAME/Library/Erlang/lib/</em> for modules if it exists. These are for libraries you want only accessible to a single user.</p>

<p>Even though ErlangX is installed into <em>/Library/Frameworks/Erlang.framework</em> it is not yet set up as a real Cocoa framework. There are 2 reasons for this location. One is that other systems such as Ruby and Python are set up this way. The other is forward compatability. The intention is to create a real Cocoa framework out of this to help with the creation of Erlang ports or other Erlang related software in Objective-C. This is however not the first priority.</p>

<p><strong>ErlangXCode</strong> is a plugin enabling the use of XCode as an IDE for Erlang development. It's all early work. Creating the XCode addons would not be possible without the amazing effort of Damien Bobillot who painstakingly found out how the XCode API works and shared it with us. If you install ErlangXCode without the ErlangX runtime install you have to make sure that <strong>erlc</strong> is available in <strong>/usr/local/bin</strong>. To see the basics of what I have currently you can check out <a href="http://static.jongretar.net/ErlangX/ErlangXCode-tb1-screencast1.html">this screencast</a>(sorry about the watermark).</p>

<p>Now. As I have spent pretty much only 3-4 hours on this and most of it went into finding out how the XCode plugin system works there is a lot of things that need fixing. Syntax highliting is in early stages and a lot is missing. You can help by downloading the source and commiting to me changes or just editing the files installed in <em>/Developer/Library/Xcode/Plug-ins/Erlang.xcplugin</em> and sending me the changes. All help is much appreciated.</p>

<p>You can download the first test <a href="http://code.google.com/p/erlangx/wiki/Downloads?tm=2">here</a>. Although it should work fine be warned that this is an early test and some things may not work as advertised.</p>

<script src="http://feeds.feedburner.com/~s/MeDevYouJane?i=http://medevyoujane.com/blog/2008/10/4/introducing-erlangx-and-erlangxcode.html" type="text/javascript" charset="utf-8"></script>
]]></content:encoded></rss:item><rss:item rdf:about="http://medevyoujane.com/blog/2008/9/10/erlang-tutorial-sysinfo-server.html"><rss:title>Erlang Tutorial: Sysinfo Server</rss:title><rss:link>http://medevyoujane.com/blog/2008/9/10/erlang-tutorial-sysinfo-server.html</rss:link><dc:creator>Jón Grétar Borgþórsson</dc:creator><dc:date>2008-09-10T23:34:20Z</dc:date><dc:subject>Erlang</dc:subject><content:encoded><![CDATA[<p>Say you have been doing some erlang basics and are ready to start an actual program. Luckily your manager has just asked you to create a server that listens for telnet a connection and has an interface to get the environment variables on the running system. Oh and it needs 99.9999999% uptime. I know what you are thinking. <em>"By gosh this is perfect for erlang"</em> was what you thought right?</p>

<p>Well before you start any real software development in Erlang you <strong>really</strong> should start by reading the <a href="http://www.erlang.se/doc/programming_rules.shtml">Programming Rules and Conventions</a> on Ericsson's website. This should be your bible. Go ahead and read it now. Don't worry I'll wait.....</p>

<p>Back? Good. Now we can start this tutorial.</p>

<h3>Housekeeping</h3>

<p>We start by creating a directory for our application. In that directory we create the subdirectories <em>doc</em>, <em>ebin</em> and <em>src</em>. Now we create a file in the project root called <em>Emakefile</em> to ease the compilation of the software. Open up <em>Emakefile</em> and add the following:</p>

<pre><code>{'src/sysinfo_server.erl', [{outdir, "ebin"}]}.
</code></pre>

<p>This basically lists our modules for compilation and tells Erlang to put the finished product into the <em>ebin</em> subdirectory. </p>

<h3>Iteration 1: A Basic Server</h3>

<p>Now lets take a look at the <em>src/sysinfo_server.erl</em> file. First declare the exports and add the start functions.</p>

<pre><code>-module(sysinfo_server).
-export ([start/0, start/1, accept_connection/1, responder_loop/1]).

start() -&gt;
    start(8023).

start(Port) -&gt;
    {ok, ListeningSocket} = gen_tcp:listen(Port, 
       [list, {packet, 0}, {active, false}, {reuseaddr, true}]),
    accept_connection(ListeningSocket).
</code></pre>

<p>In <em>start/1</em> we open up the socket using <strong><a href="http://www.erlang.org/doc/man/gen_tcp.html#listen-2">gen_tcp:listen/2</a></strong> with the first parameter the port we want to use followed by the tcp options. I will not go in to details for the options but you can read about them in the <strong><a href="http://www.erlang.org/doc/man/gen_tcp.html">gen_tcp</a></strong> module. We then pass the created socket to the the <em>accept_connection/1</em> loop that handles accepting incoming connections.</p>

<pre><code>accept_connection(ListeningSocket) -&gt;
    {ok, Socket} = gen_tcp:accept(ListeningSocket),
    spawn_link(?MODULE, responder_loop, [Socket]),
    accept_connection(ListeningSocket).
</code></pre>

<p>Here we take the socket and wait for a connection to it with the command <strong><a href="http://www.erlang.org/doc/man/gen_tcp.html#accept-1">gen_tcp:accept/1</a></strong>. Thing to remember about <em>gen_tcp:accept/1</em> command is that it waits forever for a connection and does not execute the next line until that connection is created. When we get the connection we use <strong><a href="http://www.erlang.org/doc/man/erlang.html#spawn_link-3">spawn_link/3</a></strong> to create a seperate process running the <em>responder_loop/1</em> loop that will handle all the communication to that client. The function then calls itself and waits for the next connection. Always keep this part simple. This way if something fails it will fail in <em>responder_loop/1</em> thus only failing the single socket but our loop that accepts new connections is unlikely to fail and other socket continue to communicate. Lets now get to the responder loop.</p>

<pre><code>responder_loop(Socket) -&gt;
    case gen_tcp:recv(Socket, 0) of
        {ok, "exit\r\n"} -&gt;
            gen_tcp:send(Socket, "Exiting \r\n"),
            gen_tcp:close(Socket);
        {ok, Other} -&gt;
            gen_tcp:send(Socket, Other),
            responder_loop(Socket);
        {error, closed} -&gt;
            ok
    end.
</code></pre>

<p>Here we take the data from <strong><a href="http://www.erlang.org/doc/man/gen_tcp.html#recv-2">gen_tcp:recv</a></strong>. The data includes the return character so we need to include that. If it matches "exit\r\n" we close the socket after sending a message back. Otherwise we echo the data back with <strong><a href="http://www.erlang.org/doc/man/gen_tcp.html#send-2">gen_tcp:send/2</a></strong> and recurse. Lets try it out by building the code and running it. Enter the following into the terminal at the project root.</p>

<pre><code>bash$ erl -make
bash$ erl -pa ebin -run sysinfo_server start
</code></pre>

<p>Now using a telnet client telnet to localhost at port 8023. You should be able to get echoed back all that you type and type exit to break the connection. Close the server by typing in <code>q().</code> in the erlang shell.</p>

<h3>Iteration 2: Improving the server</h3>

<p>First thing we are going to do is add a function that helps us to get the environment variable. As it is not a part of the data communication and might be a reusable function we decide to put it into it's another module called <em>sysinfo_tools.erl</em>. Start by adding it to the <em>Emakefile</em> by adding an identical line to what defines <em>sysinfo_server</em>. </p>

<pre><code>{'src/sysinfo_tools.erl', [{outdir, "ebin"}]}.
</code></pre>

<p>Now create <strong>src/sysinfo_tools.erl</strong> and add the following.</p>

<pre><code>-module (sysinfo_tools).
-export ([get_env/1]).

get_env(Var) -&gt;
[CleanVar|_Rest] = string:tokens(Var, "\r\n\t "),
case os:getenv(CleanVar) of
  false -&gt; "No Such Env";
  Result -&gt; Result
end.
</code></pre>

<p>This is pretty simple. We take the input <em>Var</em> and remove all unwanted characters from it. We then call the <strong><a href="http://www.erlang.org/doc/man/os.html#getenv-1">os:getenv/1</a></strong> function to retreive the environment variable. If it does not exist we return the value "No Such Env" or just simply return the value. no magic here so now we can get to the interesting part.</p>

<p>Now lets turn back to <em>src/sysinfo_server.erl</em></p>

<p>First step is adding a function to assist us with sending data to the client. We want to run it with a list of strings and at the end it prints out a nice prompt for the user. So add this function.</p>

<pre><code>send_lines(Socket,[]) -&gt;
    gen_tcp:send(Socket, "\r\nEnvGet&gt; ");
send_lines(Socket,[First|Rest]) -&gt;
    gen_tcp:send(Socket,First),
    gen_tcp:send(Socket,"\r\n"),
    send_lines(Socket,Rest).
</code></pre>

<p><em>send_lines/2</em> takes a socket and a list as parameters. It prints out the first element and loops back with the rest. Finally when the list is empty it prints out a prompt and exits. Lets put it in use by changing <em>accept_connection/1</em> so it looks like this.</p>

<pre><code>accept_connection(ListeningSocket) -&gt;
    {ok, Socket} = gen_tcp:accept(ListeningSocket),
    send_lines(Socket, ["Welcome to the EnvGet Service", 
        "Available commands are: list, get &lt;env&gt; and exit"]),
    spawn_link(?MODULE, responder_loop, [Socket]),
    accept_connection(ListeningSocket).
</code></pre>

<p>Now we want to add the list and get commands along with changing the code to use <em>send_lines/2</em> so that the respoder loop looks like this.</p>

<pre><code>responder_loop(Socket) -&gt;
    case gen_tcp:recv(Socket, 0) of
        {ok, "get "++Var} -&gt;
            Result = sysinfo_tools:get_env(Var),
            send_lines(Socket, [Result]),
            ?MODULE:responder_loop(Socket);
        {ok, "list\r\n"} -&gt;
            Result = os:getenv(),
            send_lines(Socket, Result),
            ?MODULE:responder_loop(Socket);
        {ok, "exit\r\n"} -&gt;
            send_lines(Socket, ["Exiting"]),
            gen_tcp:close(Socket);
        {ok, _Other} -&gt;
            send_lines(Socket, ["Unknown Command"]),
            ?MODULE:responder_loop(Socket);
        {error, closed} -&gt;
            ok
    end.
</code></pre>

<p>Well. First we take a look at the get command. Here we try to match a string that starts with "get " and add the rest to the variable <strong>Var</strong>. We then call our handy <em>sysinfo_tools:get_env/1</em> function that gets the data for us. Next we try to match the command "list". We call <strong><a href="http://www.erlang.org/doc/man/os.html#getenv-0">os:getenv/0</a></strong> and pass it on to the user. Since <em>os:getenv/0</em>'s output is a list of strings we don't put brackets around like usually.</p>

<p>Now. Let's compile and run.</p>

<pre><code>bash$ erl -make
bash$ erl -pa ebin -run sysinfo_server start
</code></pre>

<p>Try it out by telneting to locahost:8023 and trying out the commands "list" and "get HOME". It should work like a charm.</p>

<p>Well. Done for now. We would propably want to add a lot more before production. Like code reloading so the server doesn't have to go down for upgrades but that is a job for a later tutorial.</p>

<p><a href="http://medevyoujane.com/storage/tutorial-data/erlang/SysInfoServer.zip">download the code</a> if you have any problems.</p>

<script src="http://feeds.feedburner.com/~s/MeDevYouJane?i=http://medevyoujane.com/blog/2008/9/10/erlang-tutorial-sysinfo-server.html" type="text/javascript" charset="utf-8"></script>
]]></content:encoded></rss:item></rdf:RDF>