<?xml version="1.0" encoding="UTF-8"?>
<!--Generated by Squarespace Site Server v5.0.0 (http://www.squarespace.com/) on Thu, 04 Dec 2008 03:10:51 GMT--><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>Me Dev, You Jane</title><link>http://medevyoujane.com/blog/</link><description></description><copyright></copyright><language>en-US</language><generator>Squarespace Site Server v5.0.0 (http://www.squarespace.com/)</generator><item><title>My CouchDBX version</title><category>Erlang</category><category>Cocoa</category><category>CouchDBX</category><dc:creator>Jon Gretar</dc:creator><pubDate>Sun, 23 Nov 2008 21:31:00 +0000</pubDate><link>http://medevyoujane.com/blog/2008/11/23/my-couchdbx-version.html</link><guid isPermaLink="false">257763:2635231:2601575</guid><description><![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>
]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-2601575.xml</wfw:commentRss></item><item><title>Why do you dislike me Apple?</title><category>Personal</category><dc:creator>Jon Gretar</dc:creator><pubDate>Sat, 22 Nov 2008 09:02:40 +0000</pubDate><link>http://medevyoujane.com/blog/2008/11/22/why-do-you-dislike-me-apple.html</link><guid isPermaLink="false">257763:2635231:2597187</guid><description><![CDATA[<p>Dear Apple. I am a loyal customer of Apple product. Out of my top 10 favourite things I own propably 6 of them are from Apple. You make some the greatest products available today. Your attention to detail and ease of use is legendary. So it makes me wonder why in the world you dislike me so much.</p>

<p>I have myself an iPod Touch. And even though you have allowed me to buy it you have deemed me not worthy of using it. You have decided that I should not be allowed to run 3rd party applications on it since my country (Iceland) is not worthy of the holy iTunes store. You have also deemed me not worthy of upgrading it for the same reason. I am not even worthy of developing applications for it since I don't live in the list of countries approved for iPod/iPhone development. And I just must ask you why?</p>

<p>I also have the Apple TV which you allowed me to buy. And again I was allowed to buy it just not use it. I'm not allowed to rent or buy movies. Why? I'm allowed to buy music and movies from Amazon or any other store and have it shipped to me. Suddenly when it's in digital form it's like it's a crime for me to shop it? What gives. And as many Apple TV owners I have installed Boxee to it so I can enjoy some extra features. But you have decided that is not allowed and in your latest update you removed it??!?!? This seems to be on purpouse this time and not some accidental breakage because of things you needed to update. It seems to me like you decided to remove it. And what gives you the right to enter my computer and remove things. I know for a fact that AppleTV is just a Mac Mini with Tiger and an app runnin full screen. I sometimes see glimpses of the window border and the close/minimize/zoom buttons. This is in no way different than if you would use your software update to remove competitor software like Microsoft Office on my iMac. How is this ok? And why would you do that to begin with? It's not like Boxee is in competition with you. I still use Apple TV's built in media player.</p>

<p>I know that the reason for why I'm not allowed to use the iTunes store is because of requirements from the record companies. But let me remind you that it is illegal for you to shut me out of it. It is actually 100% illegal for you to deny me shopping on the Danish iTunes store. I'm not kidding you check with your legal team. Europe is one big economic area and according to European laws I am allowed to shop in any European country and I should pay the same price + shipping and handling. So even though the record companies asked you it does not make it less of a crime. If laws have any meaning to you open up my access to the store. You know that sooner or later someone will force you to do that and force you to pay fines while doing that. So why not just do it now?</p>

<p>So please Apple. Stop hating me.</p>

<p><em><strong>Regards.
A Loyal Customer.</strong></em></p>
]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-2597187.xml</wfw:commentRss></item><item><title>A knock knock joke</title><category>Erlang</category><dc:creator>Jon Gretar</dc:creator><pubDate>Fri, 21 Nov 2008 12:07:33 +0000</pubDate><link>http://medevyoujane.com/blog/2008/11/21/a-knock-knock-joke.html</link><guid isPermaLink="false">257763:2635231:2594513</guid><description><![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>
]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-2594513.xml</wfw:commentRss></item><item><title>Adding Erlang library locations</title><category>Erlang</category><dc:creator>Jon Gretar</dc:creator><pubDate>Thu, 13 Nov 2008 19:36:05 +0000</pubDate><link>http://medevyoujane.com/blog/2008/11/13/adding-erlang-library-locations.html</link><guid isPermaLink="false">257763:2635231:2559644</guid><description><![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>
]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-2559644.xml</wfw:commentRss></item><item><title>Contact List using SproutCore, Mochiweb and Mnesia</title><category>Erlang</category><category>SproutCore</category><dc:creator>Jon Gretar</dc:creator><pubDate>Sat, 01 Nov 2008 21:01:02 +0000</pubDate><link>http://medevyoujane.com/blog/2008/11/1/contact-list-using-sproutcore-mochiweb-and-mnesia.html</link><guid isPermaLink="false">257763:2635231:2498499</guid><description><![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>
]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-2498499.xml</wfw:commentRss></item><item><title>Introducing ErlangX and ErlangXCode</title><category>Erlang</category><category>ErlangX</category><category>ErlangXCode</category><dc:creator>Jon Gretar</dc:creator><pubDate>Sat, 04 Oct 2008 16:06:51 +0000</pubDate><link>http://medevyoujane.com/blog/2008/10/4/introducing-erlangx-and-erlangxcode.html</link><guid isPermaLink="false">257763:2635231:2387866</guid><description><![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>
]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-2387866.xml</wfw:commentRss></item><item><title>Erlang Tutorial: Sysinfo Server</title><category>Erlang</category><dc:creator>Jon Gretar</dc:creator><pubDate>Wed, 10 Sep 2008 23:34:20 +0000</pubDate><link>http://medevyoujane.com/blog/2008/9/10/erlang-tutorial-sysinfo-server.html</link><guid isPermaLink="false">257763:2635231:2256075</guid><description><![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>
]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-2256075.xml</wfw:commentRss></item><item><title>My top 5 Favourite Erlang Functions</title><category>Erlang</category><dc:creator>Jon Gretar</dc:creator><pubDate>Tue, 02 Sep 2008 12:56:54 +0000</pubDate><link>http://medevyoujane.com/blog/2008/9/2/my-top-5-favourite-erlang-functions.html</link><guid isPermaLink="false">257763:2635231:2211537</guid><description><![CDATA[<p>Well.. After playing around in Erlang for a short while I wanted to share some newly discovered gems. These are my new favourite functions. I challenge some more experienced Erlang programmers to post theirs. I selected here some debugging tools that you just use in the shell but there are a lot more gems available.</p>

<h3>nc/1 and nc/2</h3>

<p>Remember <code>c().</code>? The command you use to compile code from the Erlang shell. Well <em><a href="http://www.erlang.org/doc/man/c.html#nc-1">nc/1</a></em> compiles and loads the code in all connected nodes. The source doesn't even need to exist in the remote nodes. Just try it by creating a bunch of nodes and typing <code>nc(modulename).</code> in one of them.</p>

<h3>l/1 and nl/1</h3>

<p><em><a href="http://www.erlang.org/doc/man/c.html#l-1">l/1</a></em> simply runs <em><a href="http://www.erlang.org/doc/man/code.html#purge-1">code:purge/1</a></em> and <em><a href="http://www.erlang.org/doc/man/code.html#load_file-1">code:load_file/1</a></em> to remove code for a module marked as old. <em><a href="http://www.erlang.org/doc/man/c.html#nl-1">nl/1</a></em> does the same except on all connected nodes. Note that <em>code:purge/1</em> removes old code even if it is in use. Also consider <em><a href="http://www.erlang.org/doc/man/code.html#soft_purge-1">code:soft_purge/1</a></em> that only removes old code if no processes use it.</p>

<h3>i/0 and ni/0</h3>

<p>Another friend for the <em>c</em> module. <em><a href="http://www.erlang.org/doc/man/c.html#i-0">i/0</a></em> gives you a list of processes and some good info on them. A valuable tool. Like you propably guessed the <em><a href="http://www.erlang.org/doc/man/c.html#ni-0">ni/0</a></em> function does the same for all the connected nodes.</p>

<h3>slave:start/2</h3>

<p>When you need to quickly start a bunch of slave nodes you should use <em><a href="http://www.erlang.org/doc/man/slave.html#start-2">slave:start/2</a></em>. I'm not sure on the difference on those nodes and the regular but it still is a valueable tool when testing things.</p>

<h3>toolbar:start/0</h3>

<p>There are loads of valuable GUI tools for debugging in Erlang. <em><a href="http://www.erlang.org/doc/man/toolbar.html#start-0">toolbar:start/0</a></em> gives you a quick access to many of them such as the Mnesia Table Visualizer, Process Manager, The Debugger and the Application Monitor. The Table Visualizer by itself is something I use daily. You can also make your own tools into the toolbar. On a related note also check out <em><a href="http://www.erlang.org/doc/man/webtool.html#start-0">webtool:start/0</a></em> and open up http://127.0.0.1:8888/ and check out how to <a href="http://www.erlang.org/doc/apps/webtool/webtool_chapter.html">make your own webtool</a>.</p>

<script src="http://feeds.feedburner.com/~s/MeDevYouJane?i=http://medevyoujane.com/blog/2008/9/2/my-top-5-favourite-erlang-functions.html" type="text/javascript" charset="utf-8"></script>
]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-2211537.xml</wfw:commentRss></item><item><title>Erlang - Make, Rake and Emake</title><category>Erlang</category><dc:creator>Jon Gretar</dc:creator><pubDate>Thu, 21 Aug 2008 11:40:04 +0000</pubDate><link>http://medevyoujane.com/blog/2008/8/21/erlang-make-rake-and-emake.html</link><guid isPermaLink="false">257763:2635231:2164231</guid><description><![CDATA[<p>When it comes to building your Erlang application there is no shortage of possibilities.</p>

<h3>Directory Setup</h3>

<p>The bare setup of the simplest Erlang program are 2 directories. Namely <em>src</em> and <em>ebin</em>. For beginners these are the ones you will most likely use for your first few programs. There are a few others however. Lets go over the whole list.</p>

<ul>
<li><strong>./bin</strong> 
<em>In here you will put shell applications to, for example, start your application.</em></li>
<li><strong>./doc</strong> 
<em>Your Generated Documents.</em></li>
<li><strong>./ebin</strong> 
<em>Compiled erlang source code for the vm.</em></li>
<li><strong>./include</strong>
<em>Used for include files.</em></li>
<li><strong>./priv</strong>
<em>Used for application specific files. For example, C executables are placed here.</em></li>
<li><strong>./src</strong> 
<em>Your source code goes here.</em></li>
</ul>

<h3>Make-ing</h3>

<p>There are 3 main methods of building Erlang programs. Make, Emake and Rake. I generally dislike makefiles so I will focus on the later 2.</p>

<h3>EMake</h3>

<p><a href="http://www.erlang.org/doc/man/make.html">EMake</a> is Erlangs own make utility. It's quite simple but not very powerful. To get started you can create a file called <em>Emakefile</em> in your project root and list your sourcefiles.</p>

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

<p>Now you can build your Erlang program by typing in you terminal <code>erl -make</code>. Often we the also use a <em>Makefile</em> to trigger the erlang make. The reason is that sometimes we want to add more commands to do various management tasks. Take this <em>Makefile</em> for example.</p>

<pre><code>all: compile

    compile:
        @erl -make

    clean:
        rm -f ebin/*.beam
        rm -f erl_crash.dump

    run:
        erl -sname console -pa ebin
</code></pre>

<p>Here we have 3 available commands in our Terminal. Entering <code>make</code> will compile our code and <code>make clean</code> will remove all the compiled code. <code>make run</code> will start an erlang shell.</p>

<h3>Rake</h3>

<p>The method I prefer is using Rakefiles. <a href="http://rake.rubyforge.org/">Rake</a> is a powerful and simple alternative to Make created in Ruby. Here is my Rakefile based on <a href="http://seangeo.blogspot.com/2007/09/building-erlang-with-rake.html">Sean's example</a>. This goes in your project root in a file called <em>Rakefile</em>.</p>

<pre><code>require 'rake'
require 'rake/clean'

# Configuration
START_MODULE = "myerlang"
TEST_MODULE = "test_myerlang"
MNESIA_DIR = "/tmp"


# No Need to change
PWD = `pwd`.strip
INCLUDE = "include"
ERLC_FLAGS = "-I#{INCLUDE} +warn_unused_vars +warn_unused_import"

SRC = FileList['src/**/*.erl']
OBJ = SRC.pathmap("%{src,ebin}X.beam")
CLEAN.include(['**/*.dump'])
CLOBBER.include(['**/*.beam'])

directory 'ebin'


rule ".beam" =&gt;  ["%{ebin,src}X.erl"] do |t|
  sh "erlc -pa ebin -W #{ERLC_FLAGS} -o ebin #{t.source}"
end

desc "Compile all"
task :compile =&gt; ['ebin'] + OBJ

desc "Open up a shell"
task :shell =&gt; [:compile] do
    sh("erl -sname #{START_MODULE} -pa #{PWD}/ebin")
end

desc "Open up a shell and run #{START_MODULE}:start()" 
task :run =&gt; [:compile] do
    sh("erl -sname #{START_MODULE} -pa #{PWD}/ebin -run #{START_MODULE} start")
end

desc "Run Unit Tests" 
task :test do
  sh("erl -noshell -s #{TEST_MODULE} test -s init stop")
end


desc "Generate Documentation"
task :doc do
    sh("cd doc &amp;&amp; erl -noshell -run edoc files ../#{SRC.join(" ../")} -run init stop")
end


task :default =&gt; :compile
</code></pre>

<p>You can get a list of functions to run by typing in <code>rake -T</code> in the project root. As <em>compile</em> is the default you can just build your code by entering simply <code>rake</code> in you terminal.</p>

<script src="http://feeds.feedburner.com/~s/MeDevYouJane?i=http://medevyoujane.com/blog/2008/8/21/erlang-make-rake-and-emake.html" type="text/javascript" charset="utf-8"></script>
]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-2164231.xml</wfw:commentRss></item><item><title>Setting up a Ruby 1.9 Sandbox on Leopard</title><category>Ruby</category><dc:creator>Jon Gretar</dc:creator><pubDate>Thu, 21 Aug 2008 09:44:07 +0000</pubDate><link>http://medevyoujane.com/blog/2008/8/21/setting-up-a-ruby-19-sandbox-on-leopard.html</link><guid isPermaLink="false">257763:2635231:2164092</guid><description><![CDATA[<p>The next version of Ruby is right around the corner and it is propably time to start getting used to the changes and start making your code compatable to the new version. Since it's not a good idea to overwrite your existing ruby installation you should propably install a Ruby 1.9 sandbox with the following directions. Although I did this on a Mac OS X.5 machine the directions should work fine for Linux. Lets start with downloading Ruby and installing in <em>/opt</em>.</p>

<pre><code>cd /tmp
curl http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.0-3.tar.gz | tar zx
cd ruby-1.9.0-r18217

autoconf
./configure --prefix=/opt/ruby19
make
sudo make install
</code></pre>

<p>Now lets set up a command that puts you in the 1.9 sandbox when needed. Open up the file <em>.profile</em> in your home directory or create it if it does not exist. Add the following line</p>

<pre><code>alias ruby19="export PATH=/opt/ruby19/bin:$PATH"
</code></pre>

<p>Close the Terminal window and open up again. Now everytime you need to put a terminal window into the Ruby 1.9 mode just type in the command <code>ruby19</code>. Try it out with the command <code>ruby -v</code> and you should see the reply:</p>

<pre><code>ruby 1.9.0 (2008-07-25 revision 18217) [i686-darwin9.4.0]
</code></pre>

<p>Now just have fun in the sandbox. Remember that there now is a seperate gem repository so you need to get the gems you need with the <code>gem</code> command. For info on changes in Ruby 1.9 take a look at the <a href="http://slideshow.rubyforge.org/ruby19.html">Ruby 1.9: What To Expect</a> or <a href="http://codefluency.com/articles/2008/04/13/migrating-to-ruby-1-9/">Migrating to Ruby 1.9</a> slideshows.</p>

<script src="http://feeds.feedburner.com/~s/MeDevYouJane?i=http://medevyoujane.com/blog/2008/8/21/setting-up-a-ruby-19-sandbox-on-leopard.html" type="text/javascript" charset="utf-8"></script>
]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-2164092.xml</wfw:commentRss></item></channel></rss>