<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>You don&apos;t want to read this.</title>
    <link rel="alternate" type="text/html" href="http://geeklair.net/~pratzsch/blog/" />
    <link rel="self" type="application/atom+xml" href="http://geeklair.net/~pratzsch/blog/atom.xml" />
    <id>tag:geeklair.net,2008-03-10:/~pratzsch/blog/14</id>
    <updated>2008-06-01T16:07:52Z</updated>
    <subtitle>Or maybe you do.  I can&apos;t make all your decisions for you.</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type Open Source 4.1</generator>

<entry>
    <title>Erlang Spine Operational</title>
    <link rel="alternate" type="text/html" href="http://geeklair.net/~pratzsch/blog/2008/06/erlang-spine-operational.html" />
    <id>tag:geeklair.net,2008:/~pratzsch/blog//14.1066</id>

    <published>2008-06-01T15:54:32Z</published>
    <updated>2008-06-01T16:07:52Z</updated>

    <summary>I can&apos;t remember if I mentioned this earlier or not, and quite frankly I&apos;m too lazy to look. So here&apos;s the idea. My servers do their internal communication on separate gigabit backbone, leaving the 100Mb NICs free to handle the...</summary>
    <author>
        <name>Phil Ratzsch</name>
        <uri>http://geeklair.net/~pratzsch</uri>
    </author>
    
        <category term="Dev" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="erlang" label="Erlang" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="messaging" label="messaging" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://geeklair.net/~pratzsch/blog/">
        <![CDATA[<p>I can't remember if I mentioned this earlier or not, and quite frankly I'm too lazy to look.  So here's the idea.  My servers do their internal communication on separate gigabit backbone, leaving the 100Mb NICs free to handle the rest of the traffic.  I'd love to have a 10Gb backbone, but I can't afford a Cisco 6500 at the moment.  Or possibly ever.</p>

<p>Anyway, the spine takes advantage of Erlang's ability to interconnect nodes running on different machines virtually transparently.  The code is nothing more than a complicated wrapper around Erlang's '!' primitive, which is used to send messages between nodes.  </p>

<p>My initial use for it is to send relevant entries from the BIND logs on the DNS server to the web server for easy display on the secondary DNS hosting site that's nearing completion.  While this is a very simple application, there are plenty of other uses.  After a few security-related tweaks, a node will be placed on our back-up cluster in Dallas/Fort Worth for doing backups. </p>

<p>The nice thing about having an intelligent spine is the each node can report back on the status of it's host machine.  If, for example, a web server was experiencing difficulties, it could communicate that to a fail-over server which could take over until the problem could be resolved.  It's sort of like a cloud concept - there are merely servers that behave however they have to.  </p>

<p>Since Erlang nodes can pass instructions to other nodes, the network could essentially re-structure itself if needed.</p>

<p>To get a better idea of what it's like, Kevin Smith has a fabulous series of screencasts on the <a href="http://pragprog.com">Pragmattic Programmers</a> site.  Go and buy them.  </p>

<p>Kevin, if you're reading this and would like to team up on a screencast, let me know.</p>]]>
        
    </content>
</entry>

<entry>
    <title>Rackspace Developers Conference</title>
    <link rel="alternate" type="text/html" href="http://geeklair.net/~pratzsch/blog/2008/05/rackspace-developers-conferenc.html" />
    <id>tag:geeklair.net,2008:/~pratzsch/blog//14.1055</id>

    <published>2008-05-18T01:51:00Z</published>
    <updated>2008-05-18T02:46:45Z</updated>

    <summary>Last week was the first Rackspace developers conference. While the majority of the people that attended were employed as software developers, a handful weren&apos;t. I was one of three people from network security who attended, and as the picture below...</summary>
    <author>
        <name>Phil Ratzsch</name>
        <uri>http://geeklair.net/~pratzsch</uri>
    </author>
    
    <category term="conference" label="conference" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="rackspace" label="rackspace" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://geeklair.net/~pratzsch/blog/">
        <![CDATA[<p>Last week was the first Rackspace developers conference.  While the majority of the people that attended were employed as software developers, a handful weren't.  I was one of three people from network security who attended, and as the picture below shows, I apparently was fascinated.</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="rackdevconsmall.jpg" src="http://geeklair.net/~pratzsch/blog/rackdevconsmall.jpg" width="420" height="300" class="mt-image-none" style="" /></span></p>

<p><strong>Lessons learned:</strong><br />
<ul><br />
<li>SyncML is really, really, REALLY clunky.</li><br />
<li>Twisted Python tries WAAAAY to hard to be Erlang.</li><br />
<li>Build your systems for scalability from day one.</li><br />
<li>Stay the hell away from Courier when setting up mail.</li><br />
</ul></p>

<p><strong>Lessons Confirmed</strong><br />
<ul><br />
<li>Nope, I still don't like Python.</li><br />
<li>Keep the UI separate from the rest of the code.</li><br />
<li>It has been confirmed once again that yes, Erlang rules.</li><br />
<li>Ruby's method_missing is pretty bad-ass.</li><br />
<li>People are terrified of things they don't understand.</li><br />
</ul></p>]]>
        
    </content>
</entry>

<entry>
    <title>PAM Error in Heron</title>
    <link rel="alternate" type="text/html" href="http://geeklair.net/~pratzsch/blog/2008/05/pam-error-in-heron.html" />
    <id>tag:geeklair.net,2008:/~pratzsch/blog//14.1044</id>

    <published>2008-05-14T02:37:10Z</published>
    <updated>2008-05-14T02:59:33Z</updated>

    <summary>After recently installing Ubuntu 8.04 on one of my boxes, I have only two complaints. 1) The laptop I have apparently has the only unsupported Atheros wireless chipset in history (AR242X). 2) Every two or three minutes, an error shows...</summary>
    <author>
        <name>Phil Ratzsch</name>
        <uri>http://geeklair.net/~pratzsch</uri>
    </author>
    
        <category term="Network" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="pam" label="PAM" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="error" label="error" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="heron" label="heron" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://geeklair.net/~pratzsch/blog/">
        <![CDATA[<p>After recently installing Ubuntu 8.04 on one of my boxes, I have only two complaints.</p>

<p>1) The laptop I have apparently has the only unsupported Atheros wireless chipset in history (AR242X).</p>

<p>2) Every two or three minutes, an error shows up in /var/log/auth.log (username removed):</p>

<p><small><br />
May 13 21:26:03 neon sudo: username_removed : TTY=pts/3 ; PWD=/etc/pam.d ; USER=root ; COMMAND=/usr/bin/vi common-password<br />
May 13 21:26:03 neon sudo: PAM unable to dlopen(/lib/security/pam_smbpass.so)<br />
May 13 21:26:03 neon sudo: PAM [error: /lib/security/pam_smbpass.so: cannot open shared object file: No such file or directory]<br />
May 13 21:26:03 neon sudo: PAM adding faulty module: /lib/security/pam_smbpass.so<br />
May 13 21:26:03 neon sudo: pam_unix(sudo:session): session opened for user root by username_removed(uid=0)<br />
May 13 21:26:03 neon sudo: pam_unix(sudo:session): session closed for user root<br />
</small></p>

<p>This message also appears whenever you sudo anything, filling up the auth log and making it virtually impossible to quickly skim through it and see meaningful messages.  The error appears to be related to an auth mechanism that comes pre-enabled for SAMBA.  Why that would come pre-enabled is beyond me, but the fix appears to be relatively simple.</p>

<p>In /etc/pam.d/common-password, find the line that says:</p>

<p><small><br />
password   optional   pam_smbpass.so nullok use_authtok use_first_pass<br />
</small></p>

<p>...and comment it out.  Next, find</p>

<p><small><br />
auth   optional        pam_smbpass.so migrate<br />
</small></p>

<p>...in /etc/pam.d/common-auth and comment that out as well.</p>

<p>Done and done.  Enjoy your minty-fresh auth log.<br />
</p>]]>
        
    </content>
</entry>

<entry>
    <title>MAC spoofing</title>
    <link rel="alternate" type="text/html" href="http://geeklair.net/~pratzsch/blog/2008/05/mac-spoofing.html" />
    <id>tag:geeklair.net,2008:/~pratzsch/blog//14.1043</id>

    <published>2008-05-13T02:05:32Z</published>
    <updated>2008-05-13T03:22:29Z</updated>

    <summary>I&apos;m studying for my CCNA and while reading a section dealing with how switches learn MAC addresses, a thought occured. The left 24 bits of a MAC is a code unique to each manufacturer while the right 24 bits is...</summary>
    <author>
        <name>Phil Ratzsch</name>
        <uri>http://geeklair.net/~pratzsch</uri>
    </author>
    
        <category term="Network" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="mac" label="MAC" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ccna" label="ccna" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="cisco" label="cisco" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://geeklair.net/~pratzsch/blog/">
        <![CDATA[<p>I'm studying for my CCNA and while reading a section dealing with how switches learn MAC addresses, a thought occured.  The left 24 bits of a MAC is a code unique to each manufacturer while the right 24 bits is a series of bits that manufacturer has never used before (in theory - in large enough runs, you'll get some dups).</p>

<p>I had always assumed that if you connect two NICs with the same MAC to a port security-disabled switch the first one to be learned would be the one to receive all the traffic.  My logic was that when the switch was checking it's lookup table to see to which port MAC "X" was connected, it would see the first entry, stop looking, and send it the data - X' I thought would never actually be seen in the lookup table, since presumably the switch would stop looking when it found X.</p>

<p>Which brings me to a tangential subject: I propose that people who use the phrase "It was in the last place I look" should be deported.  It's yet another phrase with no actual meaning behind it; most people stop looking when they find something, so naturally it's going to be in the last place you look ("Honey, I found the keys but I'm going to check the couch and the front porch and make sure they're not there!").  Anyway...</p>

<p>The effect, I presumed, would be a 'ghost sender' throwing frames at the switch but never receiving a response.  As it turns out, the switch is smarter than that (I didn't REALLY think the people at Cisco hadn't thought of that, it was just an idea).  </p>

<p>Each time a frame is received by the switch, it apparently re-learns the MAC.  When X sends something via port Fa0/1 the switch says 'Oh okay, you're on Fa0/1 - let me write that down'.  Then when X' sends a frame via port Fa0/2 the switch snidely quips 'Wow, you get around, you port-hungry devil, you!' and re-learns the MAC.  This is of course, assuming that switches are capable of 'quipping' (the latest research suggests they are -  I know they can be snidely).</p>

<p>After that happens, let's assume that the traffic in response to the request X sent earlier shows up.  The switch (being worried that the traffic was out that late) says "Where were you, Series Of Bits?! This is not a hotel!  Go to your room it's right..." - the switch examines the lookup table - "...THERE!" and gestures angrily at port Fa0/2.</p>

<p>Series Of Bits, obediently goes to port Fa0/2 to find a very surprised X'.  X' looks at Series Of Bits with a visage similar to when you haven't ordered a pizza and one shows up anyway.  "Anybody order a series of bits??" it hollers.  "Yeah, says Thomas J. Program, peaking head through the NIC's door.  "But not THAT series of bits."</p>

<p>Meanwhile, poor, poor X is waiting for a Series Of Bits that never comes.  We can only assume it begins to cry.  The point of all that (other than that I'm CLEARLY single if I had the time to write all that) is that when two identical MACs are connected to the same switch bot experience seemingly abruptly random traffic as the switch learns and re-learns the MAC.  Why the hell didn't I just SAY that?  Because I was bored.  But now I'm not.</p>

<p>Note: I was tempted to give the NICs a Brooklyn accent and make a "New York NICs" joke, but decided against it.  You can thank me in US Dollars.</p>]]>
        
    </content>
</entry>

<entry>
    <title>Quick update:</title>
    <link rel="alternate" type="text/html" href="http://geeklair.net/~pratzsch/blog/2008/05/quick-update.html" />
    <id>tag:geeklair.net,2008:/~pratzsch/blog//14.1037</id>

    <published>2008-05-02T11:55:02Z</published>
    <updated>2008-05-02T12:00:09Z</updated>

    <summary>I mentioned in the last entry that Jan Lehnardt was also talking about gen_server, and his article is now up: Read it here....</summary>
    <author>
        <name>Phil Ratzsch</name>
        <uri>http://geeklair.net/~pratzsch</uri>
    </author>
    
        <category term="Dev" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="erlang" label="Erlang" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="gen_server" label="gen_server" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://geeklair.net/~pratzsch/blog/">
        <![CDATA[<p>I mentioned in the last entry that Jan Lehnardt was also talking about gen_server, and his article is now up:<br />
<a href="http://jan.prima.de/~jan/plok/archives/135-Designing-for-Freedom-Erlang-Generic-Servers.html">Read it here</a>.</p>]]>
        
    </content>
</entry>

<entry>
    <title>gen_server behaviour in Erlang</title>
    <link rel="alternate" type="text/html" href="http://geeklair.net/~pratzsch/blog/2008/04/gen-server-behaviour-in-erlang.html" />
    <id>tag:geeklair.net,2008:/~pratzsch/blog//14.1036</id>

    <published>2008-05-01T00:58:22Z</published>
    <updated>2008-05-01T13:41:43Z</updated>

    <summary>Those of you playing along at home may have gotten the impression that I kinda like this whole Erlang thing. Correct. Those of you playing along at home (and wayward surfers as well) from outside of Europe may be wondering...</summary>
    <author>
        <name>Phil Ratzsch</name>
        <uri>http://geeklair.net/~pratzsch</uri>
    </author>
    
        <category term="Dev" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="erlang" label="Erlang" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="gen_server" label="gen_server" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="tutorial" label="tutorial" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://geeklair.net/~pratzsch/blog/">
        <![CDATA[<p>Those of you playing along at home may have gotten the impression that I kinda like this whole Erlang thing.  Correct.  Those of you playing along at home (and wayward surfers as well) from outside of Europe may be wondering why there's a bothersome 'u' lurking in the spelling of 'behaviour'.  Erlang came from Ericsson (who denies the connection between 'erlang' and 'ERicsson LANGuage'.  They claim it was named after a mathematician of the same name.) and Ericsson just so happens to reside in Scandanavia.</p>

<p>Linguists theorize that they are allowed to put the letter 'u' wherever they please as a trade-off for having to use that weird o-with-a-line-through-it letter.  Or maybe they just want to show the word how much they love empty sets.  Regardless, that being said let's hope into gen_server.</p>

<p>gen_server is a component of OTP, the Open Telecom Platform.  OTP can be thought of as a sort of application framework for Erlang, much as Python has Pylons, Ruby has Rails, and Windows has Problems Crashing.  OTP is hilariously powerful, and being the relative new-comer that I am, I've only just started to really grasp just how powerful it is.  To quote Joe Armstrong, author of the fantastic book "Programming Erlang":<br><br>
<em>
&nbsp;&nbsp;&nbsp;&nbsp;The power of OTP comes from the fact that properties such as fault tolerance, scalability, dynamic-code upgrade, and so on, can be provided by the behavior itself.  In other words, the writer of the callback does not have to worry about [those things] because this is provided by the behavior.</em></p>

<p>Okay Philip, what's a behaviour?  A behaviour is just what it sounds like - a bucket containing all the common behaviors of a certain kind of system or platform.</p>

<p>In the great tradition of contrived examples, imagine a movie store that would only let you check out one movie at a time.  The code for that might look something like what I've included below.  Just like last time, first the code and then the explanation.  My eternal thanks go out to <a href="http://jan.prima.de">Jan Lehnardt</a> of the <a href="http://incubator.apache.org/couchdb/">CouchDB</a> project for his assistance, patience, and friendship.  In the near future, he's going to be posting a plok entry on this same subject, so by all means go <a href="http://jan.prima.de/plok">see if that's there</a>.  And give him money.</p>

<p>
<small><pre>
  -module(movie_store).
  -behaviour(gen_server).
 
  -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
 
  -export([checkout/2, lookup/1, start_link/0]).
 
  start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
  checkout(Customer, Movie) -> gen_server:call(?MODULE, {checkout, Customer, Movie}).
  lookup(Customer) -> gen_server:call(?MODULE, {lookup, Customer}).

  init([]) ->
       Tab = ets:new(?MODULE, []),
       {ok, Tab}.
 
  handle_call({checkout, Customer, Movie}, _From, Tab) ->
       Response = case ets:lookup(Tab, Customer) of
         [] -> 
               ets:insert(Tab, {Customer, Movie}),
               {ok, Movie};
         [{Customer, OtherMovie}] ->
               {already_checked_out, OtherMovie}
       end,
       {reply, Response, Tab};
 
  handle_call({lookup, Customer}, _From, Tab) ->
        Reply = case ets:lookup(Tab, Customer) of
               [{Customer, Movie}] ->
                   Movie;
               [] ->
                   none
        end,
        {reply, Reply, Tab}.
 
  handle_cast(_Msg, State) -> {noreply, State}.
  handle_info(_Msg, State) -> {noreply, State}.
  terminate(_Reason, _State) -> ok.
  code_change(_OldVersion, State, _Extra) -> {ok, State}.
</pre></small></p>

<p>Okay - it looks terrifying (which incidentally, is Erlang's super power) but it's not.  The first line declares the module name (and 'movie_store.erl' should also be the filename) and is a standard part of every Erlang program.</p>

<p><small>  -behaviour(gen_server).</small>can be thought of a line that declares which 'template' we'll be using for this program.  The gen_server behaviour mandates that we define the functions specified in the first set of exports.</p>

<p<small>  -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).</small> are the functions that gen_server expects to find (and will loudly complain if they are absent).  I'll delve into more detail on these in the next tutorial, as this is going to be a huge entry as it is.  For now, know that all of these have to be defined, even if they do nothing.  As you can see at the bottom of the code, handle_cast/2, handle_info/2, terminate/2, and code_change/3 all do precisely nothing.</p>

<p>
<small>  -export([checkout/2, lookup/1,start_link/0]).</small> makes the custom functions that the server uses available to the outside world.  They are in a separate <strong>-export</strong> statement only for clarity and can be combined with the one above.
</p>

<p> 
<small>  start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).</small><br><br>
The starting point for the program.  This function as you can see, serves as a wrapper for the command that spins up the server.  <em>{local, ?MODULE}</em> shows that the server will be run locally and will not be available to other Erlang nodes in the cluster (as opposed to <em>global</em>).  ?MODULE is a stand-in for the name for the current program name and specifies what we'll use to reference the server.  The second ?MODULE tells the server where to find the callbacks (in this case, the same file).  The remaining options allow you to turn debugging on, log to a file, and a few other things not used in this example.</p>
</p>

<p><small>  checkout(Customer, Movie) -> gen_server:call(?MODULE, {checkout, Customer, Movie}).<br>
  lookup(Customer) -> gen_server:call(?MODULE, {lookup, Customer}).</small>
<br>
These lines tie in the custom functions and tell gen_server what to do when (in this case) movie_store:checkout(...) and movie_store:lookup(....) are called.  <em>?MODULE</em> indicates where the function is,  and <em>{some_name,Arg1, Arg2,...}</em> gives the function name and the arguments to be passed.</p>
</p>

<p><small><pre>  init([]) ->
       Tab = ets:new(?MODULE, []),
       {ok, Tab}.</pre></small>
creates an database table using ets, the built-in memory database and returns it.  In a deployed program, this would probably be something a bit more...permanent.  A key component of a gen_server program is the program state.  In this example, you'll see Tab getting thrown around into everything as it contains the present state of the movie store (who has which movie checked out).</p>

<p><small><pre>
  handle_call({checkout, Customer, Movie}, _From, Tab) ->
       Response = case ets:lookup(Tab, Customer) of
         [] -> 
               ets:insert(Tab, {Customer, Movie}),
               {ok, Movie};
         [{Customer, OtherMovie}] ->
               {already_checked_out, OtherMovie}
       end,
       {reply, Response, Tab};
</pre></small>

Remember the gen_server:call(....) statements a little bit ago?  This is what gen_server calls.  You might wonder how there can be two handle_call functions defined with the same arity (the number of arguments, represented by the /x as in "functioname/2").  Look at the first argument, the three element tuple.  Now look again at <br><br><small>checkout(Customer, Movie) -> gen_server:call(?MODULE, {checkout, Customer, Movie}).</small><br><br>
The first elements match, which is how gen_server knows which handle_call to call to handle...the..call.  Waay too many 'handle's and 'call's in that last bit.  The important thing is that, like a lot of other things in Erlang, is based on pattern matching.</p><p>
Notice that the table, Tab, has also been passed in.  We go right into a <strong>case/of</strong> block that checks the table for the customer to see if they already have a movie checked out.  If nothing is found ([] ->...) the movie is checked out to them and {ok, <em>moviename</em>} is returned by the block.  If they already have a movie checked out, {already_checked_out, <em>moviename</em>} is returned by the block and they are not allowed to check out another movie (note: for this example, there is no way for a customer to return a movie.  That is left as an exercise for the reader.).  <br><br>
In either case, the block's return value is stuffed into a tuple and shot back at whoever called the function.  Before moving on to the next handle_call(...), notice the last line: <small>       {reply, Response, Tab};</small>.  You'd probably expect a period and not a semi-colon.  The clauses of the handle_call(...) block are semi-colon delimited and will not work if they are terminated like other functions.  I found that one out the hard way.</p>
<p>
<small><pre>
  handle_call({lookup, Customer}, _From, Tab) ->
        Reply = case ets:lookup(Tab, Customer) of
               [{Customer, Movie}] ->
                   Movie;
               [] ->
                   none
        end,
        {reply, Reply, Tab}.
</pre></small>

This handle_call/3 defines a function to check and see if someone has a movie checked out.  If so, it returns a tuple containing the customer's name and the movie title.  Otherwise, the word 'none' is returned.  I'm not going to spend a lot of time on this since it's so similar to the handle_call/3 we just looked at.</p>

<p><small><pre>
  handle_cast(_Msg, State) -> {noreply, State}.
  handle_info(_Msg, State) -> {noreply, State}.
  terminate(_Reason, _State) -> ok.
  code_change(_OldVersion, State, _Extra) -> {ok, State}.</pre></small>
The block of functions that need to be there for gen_server to work, but we're not using this time around.  I'll cover these in a later tutorial.  A quick note though - code_change/3 is really, really cool.  It allows the server's code to be hot-swapped while the server is running.  After all, why bother bringing a server down just because the code is changing, right?</p>

<p>
Finally, here's how to run it:<br>
<small>
2> <strong>c(movie_store).</strong><br>
{ok,movie_store}<br>
3> <strong>movie_store:start_link().</strong><br>
{ok,<0.42.0>}<br>
4> <strong>movie_store:checkout(phil, "Sneakers").</strong><br>
{ok,"Sneakers"}<br>
5><strong> movie_store:lookup(phil).</strong><br>
"Sneakers"<br>
6> <strong>movie_store:checkout(phil, "Koyaanisqatsi").</strong><br>
{already_checked_out, "Sneakers"}<br>
7> <strong>movie_store:lookup(phil).</strong><br>
"Sneakers"<br>
</small>
<br>
One problem is that the program doesn't compliment you on your choice of movie if you try to check out 'Koyaanisqatsi'.  Well, I've been long-winded enough for one day.  I hope this was at the very least, interesting for you.  If you improve on this, change it around, or whatever, by all means let me know.
</p>
]]>
        
    </content>
</entry>

<entry>
    <title>Neon : Take Three</title>
    <link rel="alternate" type="text/html" href="http://geeklair.net/~pratzsch/blog/2008/04/neon-take-three.html" />
    <id>tag:geeklair.net,2008:/~pratzsch/blog//14.1035</id>

    <published>2008-04-30T03:38:05Z</published>
    <updated>2008-04-30T04:12:11Z</updated>

    <summary>Alright - it turns out the RocketRAID is both a snare and a delusion. The claims of hardware RAID are simply false - all processing is pawned off onto the system CPU. The &apos;open-source drivers&apos; are actually open-source wrappers for...</summary>
    <author>
        <name>Phil Ratzsch</name>
        <uri>http://geeklair.net/~pratzsch</uri>
    </author>
    
        <category term="Network" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://geeklair.net/~pratzsch/blog/">
        <![CDATA[<p>Alright - it turns out the RocketRAID is both a snare and a delusion.  <br />
<ul><br />
<li>The claims of hardware RAID are simply false - all processing is pawned off onto the system CPU.</li><br />
<li>The 'open-source drivers' are actually open-source wrappers for closed-source drivers.  In either event, they're impossible to slip stream during OS installation.</li><br />
<li>Supports every major linux distro my ass.</li><br />
</ul><br />
So.....we've since purchased an LSI MegaRAID 150-6 RAID controller.  I know for a fact this is a hardware RAID card.  It also has a nifty little battery backup so it can finish writes in the event of a power failure.  Since that battery can't possibly power the connected drives, I'm guessing that it just writes the data to on-board flash memory or something and completes the writes the next time the device is powered on.  Regardless, it's a nice piece of equipment.</p>

<p>Now of course the OS install disk we're using is informing us that we don't have a valid CD drive attached.  Keep in mind that this is coming from a program loaded off a CD.  A problem for tomorrow.</p>

<p>On May 9th, I'm leaving the IS department at <a href="http://www.rackspace.com">Rackspace</a>.  I like doing dev work on my own, but there is not the place to do it for me.  I'm a single Ruby coder surrounded by Python guys and the end result is that I just have nothing to do.  I'm looking for something internally, so we'll see how that goes.</p>]]>
        
    </content>
</entry>

<entry>
    <title>Neon : Take Two</title>
    <link rel="alternate" type="text/html" href="http://geeklair.net/~pratzsch/blog/2008/04/neon-take-two.html" />
    <id>tag:geeklair.net,2008:/~pratzsch/blog//14.1031</id>

    <published>2008-04-26T22:13:26Z</published>
    <updated>2008-04-27T14:00:22Z</updated>

    <summary>It seems that 64-bit Heron has some trouble recognizing RAID arrays. The machine booted and the RAID controller&apos;s configuration screen came up. After tweaking the necessary settings, we bounced the box and prayed that Heron would see it - which...</summary>
    <author>
        <name>Phil Ratzsch</name>
        <uri>http://geeklair.net/~pratzsch</uri>
    </author>
    
        <category term="Network" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="erlang" label="Erlang" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="fedora" label="Fedora" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="raid" label="RAID" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="heron" label="heron" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="installation" label="installation" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="neon" label="neon" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="shellscripting" label="shell scripting" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://geeklair.net/~pratzsch/blog/">
        <![CDATA[<p>It seems that 64-bit Heron has some trouble recognizing RAID arrays.  The machine booted and the RAID controller's configuration screen came up.  After tweaking the necessary settings, we bounced the box and prayed that Heron would see it - which it didn't.</p>

<p>When we got to the installation section where we were going to do the partitioning, we were given prompted to choose between the twin 250GB Western Digital drives.  Thinking that perhaps, somehow, someway the installed OS would see it we continued through the installation only to hit repeated checksum verification errors during the base system install.  </p>

<p>Desperately hoping that this was a fluke, we shut off the machine, coated ourselves in honey, and sacrificed our entire apartment complex to the gods of data integrity and MD5 hashing.  No luck (which means the install disk was probably corrupt - I'm having a chat with my LightScribe drive once I finish here).  Once the honey had been removed and the police had left, we decided that we'd give Fedora a shot instead - the RAID controller specifically says that it plays nicely with it.</p>

<p>So that's where we stand now - even though Fedora 9 is coming out in about two weeks, we can't wait that long.  If there are any hardware issues, we have less than two weeks to find them and get the equipment returned.  At least for the time being, a Fedora machine is being added to the rack.  I used Fedora at the last place I worked and while I didn't have anything specific against it, I didn't feel particularly attached to it.</p>

<p>As long as we're at it, we might as well trade bash in for tcsh - it's about time I learned some C and from what I understand The C SHell is a good place to learn as a lot of the syntax is similar.  I don't have any first had experience though so we'll see.</p>

<p>Switching gears, I've found that a good way to gain some basic day-to-day experience with a language is to use it for any shell scripting needs I have.  Erlang being my most recent language of study, that's what I'm going to do.  If you'd like to give it a shot, Erlang programs can be run outside of the <small>erl</small> VM by typing:</p>

<p><small><br />
pratzsch@carbon:/home/pratzsch/shell$<strong>erl -compile timely_message.erl</strong><br />
pratzsch@carbon:/home/pratzsch/shell$<strong>erl -noshell -s timely_message message -s init stop</strong><br />
Excuse me, your forehead's on fire<br />
pratzsch@carbon:/home/pratzsch/shell$<br />
</small></p>

<p>...while it works, I'll probably end up aliasing that set of commands minus the program name to a bash script (oh, the irony) so I don't have to type that novella every time I want to run an Erlang program from the command line.</p>]]>
        
    </content>
</entry>

<entry>
    <title>Welcome to neon!</title>
    <link rel="alternate" type="text/html" href="http://geeklair.net/~pratzsch/blog/2008/04/welcome-to-neon.html" />
    <id>tag:geeklair.net,2008:/~pratzsch/blog//14.1028</id>

    <published>2008-04-26T14:31:04Z</published>
    <updated>2008-04-26T17:12:45Z</updated>

    <summary> These are the insides of &apos;neon&apos;, (not quite fully assembled) the latest web server. This is the first machine I&apos;ve ever had that has hardware RAID. The chip is an 3.0GHz Intel Core 2 Duo of the 45nm variety,...</summary>
    <author>
        <name>Phil Ratzsch</name>
        <uri>http://geeklair.net/~pratzsch</uri>
    </author>
    
        <category term="Network" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="neon" label="neon" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="webserver" label="web server" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://geeklair.net/~pratzsch/blog/">
        <![CDATA[<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://geeklair.net/~pratzsch/blog/neon_inside_labeled.html" onclick="window.open('http://geeklair.net/~pratzsch/blog/neon_inside_labeled.html','popup','width=640,height=480,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://geeklair.net/~pratzsch/blog/neon_inside_labeled-thumb-200x150.jpg" width="200" height="150" alt="neon_inside_labeled.jpg" class="mt-image-none" style="" /></a></span></p>

<p>These are the insides of 'neon', (not quite fully assembled) the latest web server.  This is the first machine I've ever had that has hardware RAID.  The chip is an 3.0GHz Intel Core 2 Duo of the 45nm variety, also a first.  </p>

<p>The motherboard supports both DDR2 and DDR3 RAM, but it was decided that we'd rather have 4GB of DDR2 than 2GB of DDR3.  Naturally, having 4GB mandates a 64-bit OS.  We figured we'd give Heron a shot and see how that goes.</p>]]>
        
    </content>
</entry>

<entry>
    <title>Rerlang</title>
    <link rel="alternate" type="text/html" href="http://geeklair.net/~pratzsch/blog/2008/04/rerlang.html" />
    <id>tag:geeklair.net,2008:/~pratzsch/blog//14.1027</id>

    <published>2008-04-23T02:40:54Z</published>
    <updated>2008-04-26T17:14:11Z</updated>

    <summary>One thing I hate doing in Ruby (or any language for that matter) is setting up a web service or anything that requires a read/write socket. That&apos;s one of the reasons I like Erlang so much - the messaging takes...</summary>
    <author>
        <name>Phil Ratzsch</name>
        <uri>http://geeklair.net/~pratzsch</uri>
    </author>
    
        <category term="Dev" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="erlang" label="erlang" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="messaging" label="messaging" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="rerlang" label="rerlang" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ruby" label="ruby" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://geeklair.net/~pratzsch/blog/">
        <![CDATA[<p>One thing I hate doing in Ruby (or any language for that matter) is setting up a web service or anything that requires a read/write socket.  That's one of the reasons I like Erlang so much - the messaging takes a lot of the hassle out of the equation.</p>

<p>You build a module, register it (so you can address the module by name instead of PID), and send messages (see my tutorial a few entries ago).  I've also become interested in the message bus idea.  All concerned processes are tied into a communication circuit wherein they listen for messages addressed to them and send replies as appropriate.  </p>

<p>Erlang offers fantastic stability (one project that involved 2 million lines of Erlang code achieved a nine nines reliability, which is absolutely unheard of) but is somewhat counter-intuitive when you're getting started.  Ruby (or Python, PHP, etc) is very fast to write and generally makes sense but I find it's a pain in the ass to do network I/O.  God help you people who do it in C or Java.</p>

<p>So I got to thinking that having an Erlang-powered 'spine' may be just the thing for a SOA.  If one bites the bullet and writes an Erlang back-bone to handle the interconnectivity between machines and act as a central nerve fiber between interpreted language processes.</p>

<p>The hard part in my mind would be adding a smooth interface between Ruby and Erlang but once that's done it's trivial to hang another Erlang endpoint off the bus to do the talking.  </p>

<p>I'm probably not describing this well and as such it may come out sounding really, really stupid.  But I think it will at the very least be a good learning experience.  The more I work with Erlang the more I like it and the more potential I see in it.  If you haven't looked at it, I strongly suggest you at least give it a try.  It can look very strange and will challenge some of the basic ways you think about coding, but it is very worth it.</p>]]>
        
    </content>
</entry>

<entry>
    <title>man page humor</title>
    <link rel="alternate" type="text/html" href="http://geeklair.net/~pratzsch/blog/2008/04/man-page-humor.html" />
    <id>tag:geeklair.net,2008:/~pratzsch/blog//14.1026</id>

    <published>2008-04-20T04:32:25Z</published>
    <updated>2008-04-20T04:34:49Z</updated>

    <summary>Taken from the man page for syslogd (yes, another wild Saturday night): There are a number of methods of protecting a machine: 1. Implement kernel firewalling to limit which hosts or networks have access to the 514/UDP socket. 2. Logging...</summary>
    <author>
        <name>Phil Ratzsch</name>
        <uri>http://geeklair.net/~pratzsch</uri>
    </author>
    
        <category term="Network" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="syslogd" label="syslogd" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://geeklair.net/~pratzsch/blog/">
        <![CDATA[<p>Taken from the man page for syslogd (yes, another wild Saturday night):<br />
<p><br />
       There are a number of methods of protecting a machine:</p>

<p>       1.     Implement kernel firewalling to limit which hosts or networks have access to the 514/UDP socket.</p>

<p>       2.     Logging can be directed to an isolated or non-root filesystem which, if filled, will not impair the machine.</p>

<p>       3.     The ext2 filesystem can be used which can be configured to limit a certain percentage of a filesystem to usage by root  only.   NOTE  that<br />
              this will require syslogd to be run as a non-root process.  ALSO NOTE that this will prevent usage of remote logging since syslogd will be<br />
              unable to bind to the 514/UDP socket.</p>

<p>       4.     Disabling inet domain sockets will limit risk to the local machine.</p>

<p>       5.     Use step 4 and if the problem persists and is not secondary to a rogue program/daemon, get a 3.5 ft (approx. 1 meter) length of sucker rod*<br />
              and have a chat with the user in question.</p>

<p>              Sucker rod def. -- 3/4, 7/8 or 1in. hardened steel rod, male threaded on each end.  Primary use in the oil industry in Western North Dakota<br />
              and other locations to pump 'suck' oil from oil wells.  Secondary uses are for the construction of cattle feed lots and for  dealing  with<br />
              the occasional recalcitrant or belligerent individual.<br />
</p></p>]]>
        
    </content>
</entry>

<entry>
    <title>Messaging in Erlang</title>
    <link rel="alternate" type="text/html" href="http://geeklair.net/~pratzsch/blog/2008/04/messaging-in-erlang.html" />
    <id>tag:geeklair.net,2008:/~pratzsch/blog//14.1025</id>

    <published>2008-04-19T15:11:06Z</published>
    <updated>2008-04-22T15:19:10Z</updated>

    <summary>Erlang is a language that has fascinated me for lo, these last few weeks. For the unfamiliar, it was developed to implement high-availability, distributed, fault-tolerant systems for the telecom world decades ago and in recent years has witnessed a resurgence...</summary>
    <author>
        <name>Phil Ratzsch</name>
        <uri>http://geeklair.net/~pratzsch</uri>
    </author>
    
        <category term="Dev" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="erlang" label="erlang" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="messaging" label="messaging" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="tutorial" label="tutorial" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://geeklair.net/~pratzsch/blog/">
        <![CDATA[<p>Erlang is a language that has fascinated me for lo, these last few weeks.  For the unfamiliar, it was developed to implement high-availability, distributed, fault-tolerant systems for the telecom world decades ago and in recent years has witnessed a resurgence as multi-core processors become the norm, rather than the exception.</p>

<p>At first, Erlang is bit daunting.  Variables aren't, line endings vary by location, and recursion is common-place, among others.  After a few hours of playing with the language however, these 'problems' turn into 'features' and you begin to see the benefits of the language.</p>

<p>A key component of Erlang are processes.  Processes, unlike threads in other languages, have no shared environment or data.  The only manner of communicating things between processes is through messaging.  Processes listen for messages addressed to them and take appropriate action.  I've been playing with inter-processes messaging and wanted to share a simple example.  First, I'll list the code and then walk you through it.  The code is based on the 'Getting Started' tutorial at <a href="http://www.erlang.org">http://www.erlang.org</a></p>

<h2>The Code:</h2>

<small>
<pre>
-module(messagetest).
-export([start/0, first/2, second/0]).

first(N, SecondPID) ->
  SecondPID ! {N + 1, self()},
  receive
    continue ->
      io:format("First Continuing... ~n", []),
      first(N + 1, SecondPID);
    stop ->
      io:format("First Received 'Stop' command.  Stopping.~n", []),
      SecondPID ! done
  end.

second() ->
  receive
    done ->
      io:format("Second Received 'done'~n", []);
    {N, FirstPID} ->
      case (N < 10) of
        false -> FirstPID ! stop;
        true -> FirstPID ! continue
      end,
      io:format("Second got ~p ~n", [N]),
      second()
  end.

start() ->
  SecondPID = spawn(messagetest, second, []),
  spawn(messagetest, first, [0, SecondPID]).
</pre>
</small>

<h3>The Explanation:</h3>
<p>The first two lines define the module name and give a directory of the functions that are externally callable along with their argument counts.  The last three lines are where the fun begins.  Save the code in a file named 'messagetest.erl' and from the Erlang interpreter, compile it by typing:
</p>
<p>
<small><strong><pre>
c(messagetest). 
</pre></strong></small>
</p>
<p>
Next, run the 'start' function by typing:
</p>
<small><strong><pre>
messagetest:start().
</pre></strong></small>
<p>
You'll see output similar to:
</p>
<p>
<small><em><pre>
<0.71.0>Second got 1 

First Continuing... 
Second got 2 
First Continuing... 
Second got 3 
First Continuing... 
Second got 4 
First Continuing... 
Second got 5 
First Continuing... 
Second got 6 
First Continuing... 
Second got 7 
First Continuing... 
Second got 8 
First Continuing... 
Second got 9 
First Continuing... 
Second got 10
First Received 'Stop' command.  Stopping. 
Second Received 'done'
</pre></em></small>
</p>
<p>
The &lt;0.71.0&gt; is the process id (not to be confused with a *nix PID) and will very likely be different on your machine.  Let's look at the 'start' function.</p>
<p>
<small><pre>
start() ->
  SecondPID = spawn(messagetest, second, []),
  spawn(messagetest, first, [0, SecondPID])
</pre></small>
</p>

<p>
The first line is the function definition.  Simple enough.  The second line executes the <small><strong>spawn</strong></small> command which kicks off an Erlang process that executes the function called 'second' in the 'messagetest' module.  No parameters are passed ('[]').  The return value of <small><strong>spawn</strong></small> is the process ID of the started process.</p>

<p>
The second line also spawns another Erlang process, passing it a value of 0 as well as the process ID of the process that was just spawned.</p>

<p>
Ironically enough, we'll examine the function called 'second' first as it's a bit easier to understand, I think.  'second' consists entirely of a <small><strong>receive/end</strong></small> block who's job is to receive messages passed to the function.  Inter-process messages are sent via:</p>

<p>
<small><strong><em>process_id_of_recipient</em> ! <em>message</em></strong></small>
</p>

<p>
When a process receives a message, it is placed in a FIFO queue and the next message is examined when a <small><strong>receive/end</strong></small> is encountered.  Message processing is very similar to a case/switch in other languages in that the message is compared against a list of expected values and when a match is found the corresponding code is evaluated.  If no match is found, the next message is examined while keeping the first message in the queue.  If the second doesn't match, the third is examined and so on until either a message matches at which point it is removed from the queue, or there are no more messages.  In the case of the latter, the process blocks and waits for a message it knows how to process.
</p>

<p>
<small><pre>
second() ->
  receive
    done ->
      io:format("Second Received 'done'~n", []);
    {N, FirstPID} ->
      case (N < 10) of
        false -> FirstPID ! stop;
        true -> FirstPID ! continue
      end,
      io:format("Second got ~p ~n", [N]),
      second()
  end.
</pre></small>
</p>

<p>
Here we can see that the function is written to respond to either the word 'done' or a tuple matching a {x,y} pattern.  In the case of the word 'done' for example, a notice is printed and the function ends.
</p>

<p>In the event the second pattern matches the message, the value of 'N' is evaluated to see if it's less than 10.  If it isn't, a 'stop' message is sent to whatever process has a PID of 'FirstPID' - I'll show where this comes from in a moment.  If it is, the message 'continue' is sent instead.</p>

<p>In either case, the number it received in the variable 'N' is printed and the function calls itself to begin listening again.  Now over to the 'first' function.</p>

<p><small><pre>
first(N, SecondPID) ->
  SecondPID ! {N + 1, self()},
  receive
    continue ->
      io:format("First Continuing... ~n", []),
      first(N + 1, SecondPID);
    stop ->
      io:format("First Received 'Stop' command.  Stopping.~n", []),
      SecondPID ! done
  end.
</pre></small></p>

<p>'first' expects two parameters, a number and a PID.  As you recall from the 'start' function, this information was supplied by calling:</p>

<p><small><pre>
spawn(messagetest, first, [0, SecondPID]).</pre></small></p>

<p>'first' uses: <small><pre>SecondPID ! {N + 1, self()},</pre></small> to send a message to the process with a PID of 'SecondPID' consisting of the number it received plus one and it's own PID.  It then enters a <small><strong>receive/end</strong></small> loop to wait for a response from the 'second' function.  As you remember, 'second' checks to see if this number is greater than 10 and sends either 'stop' or 'continue' accordingly.  In this case, the number is 1 so 'second' tells 'first' to continue.</p>

<p>
This matches the <small><pre>
continue ->
  io:format("First Continuing... ~n", []),
  first(N + 1, SecondPID);
</pre></small></p>

<p>
block, so a message is printed and 'first' calls itself passing N + 1 and the PID of the 'second' function's process.  This cycle repeats until 'first' tells 'second' it's reached the number 10.</p>

<p>At this point, 'second' send a message consisting of 'stop' back to 'first'.</p>

<p><small><pre>
stop ->
  io:format("First Received 'Stop' command.  Stopping.~n", []),
  SecondPID ! done
</pre></small>
</p>

<p>'first' processes the message and prints that it is shutting down.  Finally, the message 'done' is sent back to 'second'.  'first' shuts itself down as it has nothing left to do.</p>

<p>
<small><pre>
done ->
  io:format("Second Received 'done'~n", []);
</pre></small></p>

<p>'second' receives the 'done' message from 'first', prints an acknowledgment, and decides it's going out for a beer or something so it shuts down.  The program terminates.</p>

<p>There's a lot going on and it can take some time to wrap your head around it, but probably significantly less time than you might think.  I find Erlang to be really enjoyable to write, although I think the error messages could use some work.  The people who wrote Erlang apparently founded the 'Obscure Error Message College' (note: in the 1990s, it was renamed to 'The Javascript "Has No Properties" Academy').</p>

<p>I hope this was useful to someone and that you enjoy working in Erlang.</p>]]>
        
    </content>
</entry>

<entry>
    <title>Ruby Vector extensions, DNS</title>
    <link rel="alternate" type="text/html" href="http://geeklair.net/~pratzsch/blog/2008/04/ruby-vector-extensions-dns.html" />
    <id>tag:geeklair.net,2008:/~pratzsch/blog//14.1024</id>

    <published>2008-04-16T14:08:16Z</published>
    <updated>2008-04-16T14:23:32Z</updated>

    <summary> Finally got all the zones configured properly and transferred to my DNS server. In celebration, here are some additions to the Vector class. Enjoy. require &apos;matrix&apos; class Vector def include?(search_term) self.to_a.include?(search_term) end def to_float new_elements = [] self.to_a.each do...</summary>
    <author>
        <name>Phil Ratzsch</name>
        <uri>http://geeklair.net/~pratzsch</uri>
    </author>
    
        <category term="Dev" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Network" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="dns" label="dns" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ruby" label="ruby" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="vector" label="vector" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://geeklair.net/~pratzsch/blog/">
        <![CDATA[<p>
Finally got  all the zones configured properly and transferred to my DNS server.  In celebration, here are some additions to the Vector class.  Enjoy.
</p>
<small><br><pre>
require 'matrix'

class Vector
 
  def include?(search_term)
    self.to_a.include?(search_term)
  end
   
  def to_float
    new_elements = []
    self.to_a.each do |element|
        element = element.to_f if element.class == Fixnum
        new_elements << element
      end
          
      Vector.elements(new_elements)
  end

  def pretty  
    counter = 0 
    self.map do |element|
      puts "[#{counter}] = #{element}"
      counter += 1
    end
  end

  def empty?
    return true if self.nil?  
    empty = true
    self.map do |element|
      if case(element)
           when Fixnum
             element == 0
           when nil
             true
           when String
             element.empty? or element == ' '
           when Float
             element == 0.0
           end
        next
      else
        empty = false
        break
      end
    end

    empty
  end

  def self.random(size, max_value = 50)
    elements = []
    (1..size).each do |i|
      elements << rand(max_value) + 1
    end

    Vector.elements(elements)
  end

end
</pre></small>]]>
        
    </content>
</entry>

<entry>
    <title>Wordpress on Nginx, DNS troubles</title>
    <link rel="alternate" type="text/html" href="http://geeklair.net/~pratzsch/blog/2008/04/wordpress-on-nginx-dns-trouble.html" />
    <id>tag:geeklair.net,2008:/~pratzsch/blog//14.1023</id>

    <published>2008-04-16T01:21:01Z</published>
    <updated>2008-04-16T01:48:22Z</updated>

    <summary>Taken from http://whois.domaintools.com/wordpress.com Server Type: nginx/0.6.29 So it appears that Wordpress, which gets about 4 million hits a day has switched to an Nginx front-end! I really wish that tomorrow someone at work would say that no high-traffic sites uses...</summary>
    <author>
        <name>Phil Ratzsch</name>
        <uri>http://geeklair.net/~pratzsch</uri>
    </author>
    
        <category term="Dev" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Network" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="dns" label="DNS" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="nginx" label="nginx" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ruby" label="ruby" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://geeklair.net/~pratzsch/blog/">
        <![CDATA[<p>Taken from <a href="http://whois.domaintools.com/wordpress.com">http://whois.domaintools.com/wordpress.com</a></p>

<p><small><br />
Server Type:  	 nginx/0.6.29<br />
</small></p>

<p>So it appears that Wordpress, which gets about 4 million hits a day has switched to an Nginx front-end!  I really wish that tomorrow someone at work would say that no high-traffic sites uses Nginx.  Of course I'd settle for an ignorant quip about how no there are no enterprise-level uses for Ruby or Rails.</p>

<p>It appears that the project I was on at work which was killed has risen from the proverbial ashes and is once again active.</p>

<p>I've been having DNS troubles since yesterday.  First the serials weren't getting updated, then a full zone transfer wouldn't complete without an error, and now I've FINALLY eliminated all the errors in the DNS side of things.  Not that it's working, of course.  Now the trouble is that the external IPs of two of my boxes have been switched.  So while it's resolving the domain names to the correct IP, that IP is tied to the wrong box.  I should have it fixed by morning.</p>]]>
        
    </content>
</entry>

<entry>
    <title><![CDATA[Nginx and Pure Ruby, &pi; calculus]]></title>
    <link rel="alternate" type="text/html" href="http://geeklair.net/~pratzsch/blog/2008/04/nginx-and-pure-ruby-calculus.html" />
    <id>tag:geeklair.net,2008:/~pratzsch/blog//14.1021</id>

    <published>2008-04-15T03:19:27Z</published>
    <updated>2008-04-15T03:38:39Z</updated>

    <summary>Apparently, it&apos;s tantamount to heresy to propose to use Nginx for anything Ruby-related other than Rails. I&apos;ve scoured the internet (read: a good half-hour in between bites of Spaghettios) and I can&apos;t find anything on the subject. So, it looks...</summary>
    <author>
        <name>Phil Ratzsch</name>
        <uri>http://geeklair.net/~pratzsch</uri>
    </author>
    
        <category term="Dev" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="actormodel" label="actor model" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="nginx" label="nginx" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="picalculus" label="pi calculus" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="revactor" label="revactor" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ruby" label="ruby" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://geeklair.net/~pratzsch/blog/">
        <![CDATA[<p>Apparently, it's tantamount to heresy to propose to use Nginx for anything Ruby-related other than Rails.  I've scoured the internet (read: a good half-hour in between bites of Spaghettios) and I can't find anything on the subject.  So, it looks like I'm going to have to 'figger it out my own sef'.</p>

<p>I doubt if either one of my readers has any experience on this front, feel free to chime in at any time. </p>

<p>Failing that, Ezra, on the off-chance you're reading this, send help.  And sandwiches.  </p>

<p>I had great plans for work this evening, but the better part of my night went to helping Roomie.male track down the reason why our zones weren't propagating (we think we have it, but we've got to wait and see). </p>

<p>I'm going to spend some time tomorrow digging into 'revactor', a gem which "...is an application framework for Ruby which uses the Actor model to simplify the creation of high-performance network services".  In my unending attempt to get as low-level as possible with this stuff, I've started reading about &pi; calculus.  Initial impressions are that things like "&isin; R/apple &sum; ramalama-ding-dong &otimes; 5% &clubs; that's what she said" roughly translate to "Introduction".  Still looks pretty cool, though.</p>]]>
        
    </content>
</entry>

</feed>
