<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5746251571102358624</id><updated>2012-01-29T17:45:34.088-08:00</updated><category term='ruby'/><category term='ramaze'/><category term='ajax'/><category term='tutorial'/><category term='github'/><category term='dynamic programming'/><category term='sequel'/><category term='cellular automata'/><category term='fullcalendar'/><category term='shjs'/><category term='webby'/><category term='jquery'/><category term='programming praxis'/><category term='praxis'/><category term='data structures'/><category term='interviewing'/><category term='rails'/><category term='search'/><category term='design'/><category term='vim'/><category term='heroku'/><category term='ubuntu'/><category term='webrick'/><category term='nanoc'/><category term='inkscape'/><title type='text'>SteamCode</title><subtitle type='html'>A blog about code, music, books, etc.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>84</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-4930587332113488566</id><published>2012-01-29T16:34:00.000-08:00</published><updated>2012-01-29T17:45:34.147-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><title type='text'>Rails / Ajax / Autocomplete</title><content type='html'>As you all know if you're regular readers here, I started out in the Ruby web framework world with Ramaze and I'm definitely glad that I did. However, it doesn't seem like there's much of a job market for Ramaze programmers, so I've taken up using Rails, specifically Rails 3.1. There's a number of great books for Rails and the one I'd recommend is Ruby on Rails 3 Tutorial by Michael Hartl. In this book, he develops a Twitter like application in Rails starting with basic pages and moving on to more complex topics. &lt;br /&gt;&lt;br /&gt;I've been working on a simple project for a greeting card application and I came up with a little something that might be interesting. The cards have a recipient and can have multiple signers. I added autocomplete for the recipient, but it was a bit harder for the comma separated list of signers. What I ended up doing was was simply grabbing the last piece of the list in the controller and passing that back to the view. &lt;br /&gt;&lt;br /&gt;Here's the view code ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;&lt;h1&gt; Create a Card &lt;/h1&gt;&lt;br /&gt;&lt;%= image_tag "card_images/#{@template.image_name}", :size =&gt; "200x200" %&gt;&lt;br /&gt;&lt;%= form_tag ("create_from_image") do %&gt;&lt;br /&gt;&lt;br /&gt;    &lt;%= label_tag("Add the recipient's email: ") %&gt;&lt;p/&gt;&lt;br /&gt;    &lt;%= text_field_tag(:recipient_email, "#{@recipient_email}")%&gt;&lt;p/&gt;&lt;br /&gt;&lt;br /&gt;    &lt;%= label_tag("Add A Greeting: ") %&gt;&lt;p/&gt;&lt;br /&gt;    &lt;%= text_field_tag(:greeting, "#{@greeting}")%&gt;&lt;p/&gt;&lt;br /&gt;&lt;br /&gt;    &lt;%= label_tag("Add the signers' emails (comma separated): ") %&gt;&lt;p/&gt;&lt;br /&gt;    &lt;%= text_field_tag(:signers_email, "#{@signers}")%&gt;&lt;p/&gt;&lt;br /&gt;&lt;br /&gt;    &lt;%= hidden_field_tag :template_id, @template.id %&gt;&lt;br /&gt;&lt;br /&gt;    &lt;%= submit_tag("Preview the card!") %&gt;&lt;br /&gt;    &lt;%= submit_tag("Send the card!") %&gt;&lt;br /&gt;&lt;% end %&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;There's nothing very interesting in here, but the main field we're interested in is the :signers_email text field.&lt;br /&gt;&lt;br /&gt;Here's the javascript code for it ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_javascript"&gt;&lt;br /&gt;$(document).ready(function(){&lt;br /&gt;    // Below is the name of the textfield that will be autocomplete&lt;br /&gt;    $('#recipient_email, #signers_email').autocomplete({&lt;br /&gt;        // This shows the min length of charcters that must be &lt;br /&gt;        // typed before the autocomplete looks for a match.&lt;br /&gt;                    minLength: 2,&lt;br /&gt;        // This is the source of the auocomplete suggestions. In this case a &lt;br /&gt;        // list of emails from the users controller, in JSON format.&lt;br /&gt;                    source: '/users/index.json'&lt;br /&gt;    })&lt;br /&gt;&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What this says is that for both the recipient_email and signers_email fields, use autocomplete, send when we have two characters, and use the /users/index.json function to get the data we need.&lt;br /&gt;&lt;br /&gt;Finally, we have the controller code ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;    def index&lt;br /&gt;        @title = "All users"&lt;br /&gt;        @suggestion = "Pick someone and send them a card!"&lt;br /&gt;        if params[:term]&lt;br /&gt;            search_term = params[:term].split(",").last.strip&lt;br /&gt;            @users = User.find(:all, :conditions =&gt; ['email LIKE ?', "#{search_term}%"])&lt;br /&gt;            @users_hash = []&lt;br /&gt;            @users.each do |user|&lt;br /&gt;                @users_hash &lt;&lt; { "label" =&gt; user.email }&lt;br /&gt;            end&lt;br /&gt;&lt;br /&gt;        else&lt;br /&gt;            @users = User.where(:active =&gt; true).paginate(:page =&gt; params[:page])&lt;br /&gt;        end&lt;br /&gt;&lt;br /&gt;        respond_to do |format|&lt;br /&gt;            format.html&lt;br /&gt;&lt;br /&gt;            # Here is where you can specify how to handle the request for "/people.json"&lt;br /&gt;            format.json { render :json =&gt; @users_hash }&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here, we have a couple of things going on ... for the Ajax side, we'll get the params[:term] field so we know that we need to get the constrained list. First, we're going to grab the params[:term] value, which should look something like "abc@test.com, def". Here we'd like to look for emails that start with the "def" and ignore the "abc@test.com" piece. So ... we split on the comma, grab the final element in the array, and then remove any leftover spaces at the end or beginning of the string. Next, we'll create an array where each element is a hash of the form { "label" =&gt; "defghi@test.com" }. This is the form that the jquery autocomplete needs. Finally, we use the respond_to section to send this back as json.&lt;br /&gt;&lt;br /&gt;As always, let me know if you have questions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-4930587332113488566?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/4930587332113488566/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2012/01/rails-ajax-autocomplete.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/4930587332113488566'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/4930587332113488566'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2012/01/rails-ajax-autocomplete.html' title='Rails / Ajax / Autocomplete'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-3539328928164266188</id><published>2011-12-18T18:22:00.000-08:00</published><updated>2011-12-18T18:30:46.580-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='interviewing'/><category scheme='http://www.blogger.com/atom/ns#' term='praxis'/><title type='text'>Majority Voting</title><content type='html'>I saw this one over at &lt;a href="http://programmingpraxis.com/2011/12/16/majority-voting/"&gt;Programming Praxis&lt;/a&gt;. It's pretty simple with ruby, but there's one slightly interesting piece in there that might come in handy sometime. Here's the code ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;def majority(l)&lt;br /&gt;    h = Hash.new(0)&lt;br /&gt;    l.each { |v| h[v] += 1 }&lt;br /&gt;    max = h.max {|a,b| a[1] &lt;=&gt; b[1]}&lt;br /&gt;    max[1] &gt;= l.length / 2.0 ? "#{max[0]} won with #{max[1]} out of #{l.length} total votes" : "No winner"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;v1 = %w[A A A C C B B C C C B C C]&lt;br /&gt;v2 = %w[A B C A B C A]&lt;br /&gt;&lt;br /&gt;puts "v1 = #{majority(v1)}"&lt;br /&gt;puts "v2 = #{majority(v2)}"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;OK, so we create a Hash where the value in the key/value pair is initialized to 0 and we add one each time time we see a vote. Here's the cool part, we use the max function from Enumerable knowing that max itself uses &lt;code&gt;each&lt;/code&gt; which will give us the key/value pair as a two element array. So, we set the function to compare the second element, the value, of the pair. The max that gets returned will also be a two element array and we use that to calculate whether there's a winner or not.&lt;br /&gt;&lt;br /&gt;These types of problems are great for sharpening your programming skills in general and your ruby skills in particular. They're exactly the types of questions that end up on programming interview tests.&lt;br /&gt;&lt;br /&gt;Let me know if you have questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-3539328928164266188?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/3539328928164266188/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2011/12/majority-voting.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/3539328928164266188'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/3539328928164266188'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2011/12/majority-voting.html' title='Majority Voting'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-288827975552473811</id><published>2011-11-14T19:52:00.000-08:00</published><updated>2011-11-14T20:19:54.327-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Centroids</title><content type='html'>Here's another one from my clustering code, slightly modified for explanatory purposes. This post was spurred by a conversation with a couple of friends when we were talking about programming, who said that programming languages mostly had the same things (i.e. everything old is new again). While I'm not completely in opposition to that, I think that some of the newer languages (read Ruby) do have a lot to offer when it comes to compactness. &lt;br /&gt;&lt;br /&gt;Here the problem is to find the centroid of a number of points. Basically, we want the averages of all the first values of the points, the second values of the points, etc. Let's show an example ... &lt;br /&gt;&lt;br /&gt;If we have [[x0, y0, z0], [x1, y1, z1], ... [xn, yn, zn]] as our points then the centroid would be the point given by [sum(x's) / n, sum(y's)/n, sum(z's) / n] (and here I'm too lazy to figure out how to create the capital Sigma for sum). Think about how you might solve this in your favorite programming language. In C/C++ anyway, you'd need to know in advance how many points and how many dimensions (the example above uses three, but it could be more or less). In Java, you don't need that, but I don't think you could do something like this ...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;    def centroid(x)&lt;br /&gt;        x[0].zip(*x[1..x.length-1]).map { |v| v.inject(:+) / v.length.to_f }&lt;br /&gt;    end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;OK, so what's going on here? First up we're going to take the first element of the array (above the [x0, y0, z0]) and &lt;code&gt;zip&lt;/code&gt; it with the rest of the array with &lt;code&gt;*x[1..x.length-1]&lt;/code&gt;. This should give us, once again from the example above [[x0, x1, ...xn], [y0, y1, ... yn], [z0, z1 ... zn]]. So basically, a new array with all the x's gathered together, the y's, etc. Now comes &lt;code&gt;map&lt;/code&gt;. Here, we'll take each element, which is itself an array and then use &lt;code&gt;inject&lt;/code&gt; to run through each of the items, say [x0, x1, ... xn] and sum them together. Finally, we'll divide by the length of the element to get an average. If it's hard to see this, break it into pieces and then run it through using irb. It should be a bit easier to see there.&lt;br /&gt;&lt;br /&gt;So, what's the point here. Well, essentially you could this in any programming language or in fact any Turing machine, but the language itself can make it easier freeing you to do other things or harder.&lt;br /&gt;&lt;br /&gt;Let me know if you have any questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-288827975552473811?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/288827975552473811/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2011/11/centroids.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/288827975552473811'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/288827975552473811'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2011/11/centroids.html' title='Centroids'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-438711893860407882</id><published>2011-11-11T13:45:00.000-08:00</published><updated>2011-11-11T13:57:01.543-08:00</updated><title type='text'>Monty Hall Problem</title><content type='html'>A friend of mine got asked this question in an interview yesterday and I thought it'd make an interesting programming problem. It goes something like this ... Suppose you're on a game show and are offered the choice of one of three doors. Behind one of the doors is a car and behind the other two are goats. Let's say you choose door number three (see Jimmy Buffet song). At this point Monty Hall shows you that behind door number one is a goat and offers to let you switch to door number two. The question is, should you do it? The easy (and incorrect answer) is that it doesn't matter. The correct answer is that, yes you should. Why? I'll let you look it up or you can just run the following program ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;possible_doors = [:goat, :goat, :car].permutation.to_a&lt;br /&gt;bad_choice = 0&lt;br /&gt;tries = 100000&lt;br /&gt;1.upto tries do |mc|&lt;br /&gt;    test_doors = possible_doors[Random.rand(possible_doors.length)]&lt;br /&gt;    bad_choice += 1 if test_doors[Random.rand(test_doors.length)] == :car&lt;br /&gt;end&lt;br /&gt;puts "bad_choice percent = #{bad_choice.to_f / tries.to_f * 100} good_choice percent = #{100.0 - (bad_choice.to_f / tries.to_f * 100)}"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;First up, we get a list of all the possible ways the doors could be arranged and set the number of times that switching would be a bad choice to 0. We'll run this 100000 times in a Monte (not Monty) Carlo loop. In the loop we get one of the possible arrangements of test doors randomly selected and then increment the bad_choice variable if the door we pick contains the car (in other words switching from where we are would be a "bad choice"). When we run this program we see that switching is a bad choice only about 33% of the time and a good choice about 66% of the time (one might guess that these are really 33.333333...% and 66.6666666%). So, then answer in this case is that yes you should switch.&lt;br /&gt;&lt;br /&gt;Let me know if you have questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-438711893860407882?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/438711893860407882/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2011/11/monty-hall-problem.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/438711893860407882'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/438711893860407882'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2011/11/monty-hall-problem.html' title='Monty Hall Problem'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-5985095586144796416</id><published>2011-11-01T18:30:00.000-07:00</published><updated>2011-11-01T18:47:02.341-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Ruby Distance Calculation</title><content type='html'>I was just looking at a clustering algorithm and needed a distance calculation between two points in n-dimensional space. If you remember your high school geometry (or even earlier) the distance between two points in the xy plane is the sqrt((x1 - x2)**2 + (y1-y2)**2). Where the two points are represented by (x1, y1) and (x2, y2). For more dimensions, just add values inside the sqrt as in (z1-z2)**2 for a third dimension. Given that here's a one line function that I came up with &lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;def distance(a, b)&lt;br /&gt;    Math.sqrt(a.zip(b).inject(0) { |d, c| d + (c[0] - c[1]) ** 2 })&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It's a bit tricky, so let's go through it. First we have the &lt;code&gt;Math.sqrt&lt;/code&gt; which will just take the square root of whatever is inside it. Next the &lt;code&gt;a.zip(b)&lt;/code&gt; will take two arrays (here the input parameters) and take the first values of each of the arrays, create a new array from them and then add that to the output array (see also this &lt;a href="http://steamcode.blogspot.com/2011/05/arrayzip-and-upside-up-numbers.html"&gt;post&lt;/a&gt; for more information on zip). Same with the second values of the arrays and so on. For example if we have &lt;code&gt;[x1, y1, z1].zip([x2, y2, z2])&lt;/code&gt; this will return &lt;code&gt;[[x1, x2], [y1, y2], [z1, z2]]&lt;/code&gt; (hopefully, this looks like something we can use to you). Next we're going to use &lt;code&gt;inject&lt;/code&gt; to run through this array with a starting value of 0 (d) and add to it the square of the difference of the two values in the array. Finally as noted before, take the square root and return. &lt;br /&gt;&lt;br /&gt;If you have any problems with this, break it up into multiple lines and check the intermediate values. As always, let me know if you have any questions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-5985095586144796416?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/5985095586144796416/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2011/11/ruby-distance-calculation.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/5985095586144796416'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/5985095586144796416'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2011/11/ruby-distance-calculation.html' title='Ruby Distance Calculation'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-4569746197532669716</id><published>2011-10-05T18:35:00.000-07:00</published><updated>2011-10-05T18:51:21.205-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='data structures'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>Heaps</title><content type='html'>I noted in my &lt;a href="http://steamcode.blogspot.com/2011/10/phone-interview-1.html"&gt;last post&lt;/a&gt; that I had a technical phone interview. When it was scheduled, the HR person told me that it would include "data structures, algorithms, and architecture". I decided that it wouldn't be a bad idea to review a bit and so I got a copy of Steven Skiena's "&lt;a href="http://www.amazon.com/Algorithm-Design-Manual-Steven-Skiena/dp/1849967202/ref=sr_1_1?ie=UTF8&amp;qid=1317865138&amp;sr=8-1"&gt;The Algorithm Design Manual&lt;/a&gt;" and started rummaging through it. &lt;br /&gt;&lt;br /&gt;One of the data structures that I came across was a heap (as in heapsort if you've forgotten). A heap is a binary tree data structure that has the property that the parent is smaller for a min-heap or larger for a max-heap than its children. They can be used for priority queues as the minimum or maximum is always at the top of the heap or for sorting assuming that you a) take the top element and then b) recalculate the tree. &lt;br /&gt;&lt;br /&gt;The code here follows Skiena's pretty closely excepting he starts his array at 1 and I use the more natural (for me anyway) 0 start. This code also implements only a min-heap, but you should take a bit of time to see if you can figure out how to make it either a min-heap or a max-heap as an initialization parameter. A couple of other things aren't that pretty (&lt;code&gt;extract_min!&lt;/code&gt; in particular bugs me), but mostly it's not bad and is straight forward. &lt;br /&gt;&lt;br /&gt;So ... here's the code &lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;class Heap&lt;br /&gt;    def initialize(a)&lt;br /&gt;        @q = []&lt;br /&gt;        a.each { |v| insert(v) } if a&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def parent(n)&lt;br /&gt;        n == 0 ? -1 : (n-1) / 2&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def young_child(n)&lt;br /&gt;        (2 * n) + 1&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def insert(v)&lt;br /&gt;        @q &lt;&lt; v&lt;br /&gt;        bubble_up(@q.size-1)&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def bubble_up(n)&lt;br /&gt;        return if parent(n) == -1 # Root of heap, no parent &lt;br /&gt;        if @q[parent(n)] &gt; @q[n]&lt;br /&gt;            swap(n, parent(n))&lt;br /&gt;            bubble_up(parent(n))&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def swap(n, pn)&lt;br /&gt;        @q[n], @q[pn] = @q[pn], @q[n]&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def min&lt;br /&gt;        @q.first&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def extract_min!&lt;br /&gt;        m, @q[0] = @q.first, @q.last&lt;br /&gt;        @q.pop&lt;br /&gt;        bubble_down(0)&lt;br /&gt;        m&lt;br /&gt;    end&lt;br /&gt; &lt;br /&gt;    def bubble_down(n)&lt;br /&gt;        c = young_child(n)&lt;br /&gt;        min_index = n&lt;br /&gt;&lt;br /&gt;        0.upto(1) { |i| min_index = c+i if ((c+i) &lt;= @q.size-1) &amp;&amp;(@q[min_index] &gt; @q[c+i]) }&lt;br /&gt;&lt;br /&gt;        if (min_index != n)&lt;br /&gt;            swap(n, min_index)&lt;br /&gt;            bubble_down(min_index)&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def sort!&lt;br /&gt;        a = []&lt;br /&gt;        while v = extract_min! do a &lt;&lt; v end&lt;br /&gt;        a&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;h = Heap.new([12, 14, 6, 10, 8, 27, 1, 4, 9])&lt;br /&gt;puts "extract_min! = #{h.extract_min!}"&lt;br /&gt;puts "extract_min! = #{h.extract_min!}"&lt;br /&gt;puts "extract_min! = #{h.extract_min!}"&lt;br /&gt;puts "extract_min! = #{h.extract_min!}"&lt;br /&gt;puts "min = #{h.min}"&lt;br /&gt;puts "min = #{h.min}"&lt;br /&gt;puts "sort! = #{h.sort!}"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Let me know if you have any questions or comments and if you make improvements, post those too.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-4569746197532669716?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/4569746197532669716/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2011/10/heaps.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/4569746197532669716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/4569746197532669716'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2011/10/heaps.html' title='Heaps'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-2487559531052671074</id><published>2011-10-04T10:10:00.000-07:00</published><updated>2011-10-04T10:50:47.473-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='interviewing'/><title type='text'>Phone Interview - 1</title><content type='html'>I had a phone interview with a great company yesterday and thought I'd share some of the questions, my answers, what I think might have been better answers, and some additional potential questions that might have been asked. First, this was for a manager position and the fact that they're asking technical questions as part of the interview process and as the first interview really impressed me. It shows that they value technical abilities and respect their engineers and developers enough to hire managers that are technically capable as a top priority. We started out, as is usually the case with a bit of small talk about myself, the interviewer, and the company. Nothing too interesting there. I don't recall the actual order of the questions, but I think I got them all.&lt;br /&gt;&lt;br /&gt;1. What are horizontal and vertical scaling? Here I knew what horizontal scaling was, but I don't believe I've heard the term vertical scaling. Horizontal scaling means adding more servers to give more processing power while vertical scaling (as I learned when I looked it up) is beefing up the capabilities of an existing server by adding say memory, CPUs, or CPU power. A reasonable follow up to this would have been to discuss the advantages and disadvantages to each.&lt;br /&gt;&lt;br /&gt;2. What is object oriented programming? Here I discussed encapsulation and inheritance. I probably should have mentioned polymorphism and message passing. The &lt;a href="http://en.wikipedia.org/wiki/Object_oriented_programming"&gt;Wikipedia article&lt;/a&gt; is pretty decent and wouldn't be a bad place to do a high level review for this sort of question. I was a little surprised that I didn't get a question on a specific problem. I always would as someone to list out objects and methods for a card game or for a file system (stolen I believe from Steve Yegge if I remember correctly). &lt;br /&gt;&lt;br /&gt;3. Given an unsorted list, how would you find a duplicate element. This one was interesting because it had recently appeared on &lt;a href="http://programmingpraxis.com/2011/09/23/array-duplicates/"&gt;Programming Praxis&lt;/a&gt;. I solved it there and used a hash table. The idea is to run through each element of the list and put it on the hash table. If when you go to put it on the hash table, there's something already there, then you've found the duplicate and should return it.&lt;br /&gt;&lt;br /&gt;4. In the above question, what's the complexity using Big O notation. Here, since we're running through the list just once, it should be O(n) where n is the size of the list.&lt;br /&gt;&lt;br /&gt;5. How does a hash table work or how is it implemented "under the hood"? There are actually a couple of ways of implementing hash tables. I gave the answer of an array of linked lists. You have an array of size n and then use the element that you're going to put on the table to generate a hash value using a hash function. Then use this mod n and add it to the linked list that's at that element. &lt;br /&gt;&lt;br /&gt;6. How would you count the number of 1's in an integer? This is pretty classic. Probably the easiest is to use a shift/and technique. You would "and" the value with "1" and if it's non-zero (actually it'll be 1) then add one to the bit count. Shift right and repeat until the value is 0.&lt;br /&gt;&lt;br /&gt;7. The final question was about Design Patterns and whether I knew about them and why they're useful. My response was that they're useful in that they give us a way to discuss our designs with a common language. People were using design patterns before the GoF book, but they codified the patterns and gave them names. This makes it much easier to talk about these things.&lt;br /&gt;&lt;br /&gt;I think that was all of the questions. We then talked a bit about the position and the company in general. As I said, I was very impressed with them and their "corporate culture". &lt;br /&gt;&lt;br /&gt;So ... what sorts of things do you ask or have you been asked in technical phone interviews? Anything interesting or unique? Let us know in the comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-2487559531052671074?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/2487559531052671074/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2011/10/phone-interview-1.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/2487559531052671074'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/2487559531052671074'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2011/10/phone-interview-1.html' title='Phone Interview - 1'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-1030334987210760184</id><published>2011-09-13T20:03:00.000-07:00</published><updated>2011-09-13T20:16:02.312-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='dynamic programming'/><title type='text'>Tetrahedral Numbers</title><content type='html'>Here's another one from &lt;a href="http://programmingpraxis.com/2011/09/13/tetrahedral-numbers/"&gt;Programming Praxis&lt;/a&gt; this one on tetrahedral numbers. I'll leave you to read the description and just jump straight into the ruby solution. The interesting thing here is to use a &lt;code&gt;lambda&lt;/code&gt; to create a method that we can pass around. Here's the entire program ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;&lt;br /&gt;def linear(target, f)&lt;br /&gt;    n = 1&lt;br /&gt;    while ( f.call(n) != target)&lt;br /&gt;        n = n + 1&lt;br /&gt;    end&lt;br /&gt;    n&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def binary(target, f)&lt;br /&gt;    low, high = 1, 2&lt;br /&gt;    while (f.call(high) &lt; target) do high = high*2 end&lt;br /&gt;    mid = (high + low) / 2&lt;br /&gt;    while (fmid = f.call(mid)) != target do&lt;br /&gt;        fmid &lt; target ?  (low, mid = mid, (mid + high) / 2) : (high, mid = mid, (low + mid) / 2)&lt;br /&gt;    end&lt;br /&gt;    mid&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;tetrahedral = lambda { |n| n * (n + 1) * (n + 2) / 6 }&lt;br /&gt;&lt;br /&gt;1.upto(10) { |i| puts tetrahedral.call(i) }&lt;br /&gt;&lt;br /&gt;puts linear(169179692512835000, tetrahedral)&lt;br /&gt;puts binary(169179692512835000, tetrahedral)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We start out with two methods &lt;code&gt;linear&lt;/code&gt; and &lt;code&gt;binary&lt;/code&gt; which are pretty straightforward with the exception that both take a function (in this case &lt;code&gt;f&lt;/code&gt;) as a parameter. For linear, we start at 1 and continue calling &lt;code&gt;f&lt;/code&gt; until the value of &lt;code&gt;f(n)&lt;/code&gt; is the same as &lt;code&gt;target&lt;/code&gt;. &lt;code&gt;binary&lt;/code&gt; is similar, but here we keep doubling the &lt;code&gt;high&lt;/code&gt; value until we're above the &lt;code&gt;target&lt;/code&gt; and then we calculate the &lt;code&gt;fmid&lt;/code&gt; and use it as a high or low value until we converge. &lt;br /&gt;&lt;br /&gt;The &lt;code&gt;tetrahedral&lt;/code&gt; function itself is created with a lambda so that we can pass it to the other two methods. The next lines are simply tests. Note how much longer the &lt;code&gt;linear&lt;/code&gt; method takes than the &lt;code&gt;binary&lt;/code&gt;. &lt;br /&gt;&lt;br /&gt;As always, let me know if you have questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-1030334987210760184?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/1030334987210760184/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2011/09/tetrahedral-numbers.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/1030334987210760184'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/1030334987210760184'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2011/09/tetrahedral-numbers.html' title='Tetrahedral Numbers'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-6153248533045655076</id><published>2011-09-03T17:10:00.001-07:00</published><updated>2011-09-03T17:25:32.718-07:00</updated><title type='text'>Two String Exercise via Programming Praxis</title><content type='html'>Here's another one (or two rather) from &lt;a href="http://programmingpraxis.com/2011/09/02/two-string-exercises/"&gt;Programming Praxis&lt;/a&gt;. Let's take a look at the second one first as it's trivial in ruby. If we're given a string, how do we replace multiple spaces with single spaces. F/or example the string &lt;code&gt;"a    b       c"&lt;code&gt; would become &lt;code&gt;"a b c"&lt;/code&gt;. For both of these, we're going to monkey patch the string class. Here's the code ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;class String&lt;br /&gt;    def remove_consecutive_spaces&lt;br /&gt;        self.gsub(/ +/, " ")&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;All we do is do a global substitution of one or more spaces with a single space. This would be quite a bit trickier in C say which is why it ends up in interview questions.&lt;br /&gt;&lt;br /&gt;The second (or first) problem is to remove duplicate characters from a string. For example, &lt;code&gt;"aaaabbbb"&lt;/code&gt; becomes &lt;code&gt;"ab"&lt;/code&gt; and &lt;code&gt;"abcbd"&lt;/code&gt; becomes &lt;code&gt;"abcd"&lt;/code&gt;. This one is a bit trickier but shows another good example of how useful &lt;code&gt;inject()&lt;/code&gt; can be. Here's the code ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;class String&lt;br /&gt;    def remove_duplicate_characters&lt;br /&gt;        self.split(//).inject([]) { |a, c| a &lt;&lt; c if !a.include?(c); a }.join&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Going through it from left to right, we have first the &lt;code&gt;split(//)&lt;/code&gt; which will turn the array into a string of characters. With that string of characters we do an &lt;code&gt;inject([])&lt;/code&gt; which a) initializes a new empty array (sometimes called the "memo") and then runs through the character array adding a character "c" to the array "a" if it's not already there &lt;code&gt;include?&lt;/code&gt;. The &lt;code&gt;; a&lt;/code&gt; returns the current array back to the &lt;code&gt;inject&lt;/code&gt;. Finally, we recreate the string by doing a &lt;code&gt;join&lt;/code&gt; on the character string array.&lt;br /&gt;&lt;br /&gt;Let me know if you have questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-6153248533045655076?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/6153248533045655076/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2011/09/two-string-exercise-via-programming.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/6153248533045655076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/6153248533045655076'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2011/09/two-string-exercise-via-programming.html' title='Two String Exercise via Programming Praxis'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-3461006653792100239</id><published>2011-08-11T17:04:00.000-07:00</published><updated>2011-08-11T17:35:24.975-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programming praxis'/><title type='text'>Hett's Problem</title><content type='html'>Sorry for not writing for a while, I've been busy looking for a new job. If you've got one, you can contact me here or at slabounty at large search company that starts with "g".&lt;br /&gt;&lt;br /&gt;Anyway ... over at &lt;a href="http://programmingpraxis.com/2011/08/09/hetts-problem-128/"&gt;Programming Praxis&lt;/a&gt; there's a problem via &lt;a href="https://sites.google.com/site/prologsite/prolog-problems/1"&gt;PrologSite&lt;/a&gt; concerning lists. Here's the problem statement ...&lt;br /&gt;&lt;blockquote&gt;1.28 (**) Sorting a list of lists according to length of sublists&lt;br /&gt;a) We suppose that a list (InList) contains elements that are lists themselves. The objective is to sort the elements of InList according to their length. E.g. short lists first, longer lists later, or vice versa.&lt;br /&gt;&lt;br /&gt;Example:&lt;br /&gt;?- lsort([[a,b,c],[d,e],[f,g,h],[d,e],[i,j,k,l],[m,n],[o]],L).&lt;br /&gt;L = [[o], [d, e], [d, e], [m, n], [a, b, c], [f, g, h], [i, j, k, l]]&lt;br /&gt;&lt;br /&gt;b) Again, we suppose that a list (InList) contains elements that are lists themselves. But this time the objective is to sort the elements of InList according to their length frequency; i.e. in the default, where sorting is done ascendingly, lists with rare lengths are placed first, others with a more frequent length come later.&lt;br /&gt;&lt;br /&gt;Example:&lt;br /&gt;?- lfsort([[a,b,c],[d,e],[f,g,h],[d,e],[i,j,k,l],[m,n],[o]],L).&lt;br /&gt;L = [[i, j, k, l], [o], [a, b, c], [f, g, h], [d, e], [d, e], [m, n]]&lt;br /&gt;&lt;br /&gt;Note that in the above example, the first two lists in the result L have length 4 and 1, both lengths appear just once. The third and forth list have length 3; there are two list of this length. And finally, the last three lists have length 2. This is the most frequent length.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;So how can we solve these two problems in Ruby? The first one is pretty much trivial. Here's the code ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;list = [%w[a, b, c], %w[d], %w[e, f], %w[g, h, i, j, k], %w[l], %w[m, n, o]]&lt;br /&gt;list_sort_length = list.sort {|a, b| a.length &lt;=&gt; b.length}&lt;br /&gt;p list_sort_length&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;All we're going to do is use the option to &lt;code&gt;sort&lt;/code&gt; that takes a block. The block will get two values and instead of the default, we're going to use the values &lt;code&gt;length&lt;/code&gt;. Run this and you should see ...&lt;br /&gt;&lt;output&gt;[["l"], ["d"], ["e,", "f"], ["a,", "b,", "c"], ["m,", "n,", "o"], ["g,", "h,", "i,", "j,", "k"]]&lt;/output&gt;.&lt;br /&gt;&lt;br /&gt;The next piece is a bit trickier. Here, we can't do just a one-liner (that I could see anyway). Here's the code ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;hist = Hash.new{|h, k| h[k] = []}&lt;br /&gt;list.each { |l| hist[l.length] &lt;&lt; l }&lt;br /&gt;list_sort_hist = []&lt;br /&gt;hist.sort {|a,b| a.length &lt;=&gt; b.length}.each { |key, value| value.each {|e| list_sort_hist &lt;&lt; e } }&lt;br /&gt;p list_sort_hist&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We start out creating the histogram hash and passing a block so that each element is initialized with an empty array. Then, we work through the list and add each element to an array at the appropriate histogram hash location. Next, create the empty sorted histogram array. Finally, we're going to sort the histogram the same way that we did in the earlier problem (we can do this because they both are Enumerable. We take the result of that and do and &lt;code&gt;each&lt;/code&gt; for every item in the histogram. For each of the &lt;code&gt;value&lt;/code&gt;s (which remember are arrays), we add them to the &lt;code&gt;list_sort_hist&lt;/code&gt; array. Finally, we print that out. If it makes it easier to see, split that long line in two. First create a sorted histogram array and then for each value loop through the value and add it to the list_sort_hist array. &lt;br /&gt;&lt;br /&gt;Let me know if you have any comments, questions, or jobs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-3461006653792100239?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/3461006653792100239/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2011/08/hetts-problem.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/3461006653792100239'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/3461006653792100239'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2011/08/hetts-problem.html' title='Hett&apos;s Problem'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-2460706984704019620</id><published>2011-05-28T15:08:00.000-07:00</published><updated>2011-05-28T15:25:55.209-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='programming praxis'/><title type='text'>Array.zip() and Upside Up Numbers</title><content type='html'>I've known about the zip method for arrays but have never really found much of a use for it. I was working a problem on &lt;a href="http://programmingpraxis.com/2011/05/27/upside-up/"&gt;Programming Praxis&lt;/a&gt; the other day and saw some Python solutions that used it, so I decided to give it a try in my solution. Let's start out with how it works.&lt;br /&gt;&lt;br /&gt;In the simplest case, we have an array and we zip it with an array of the same size. Here's what it looks like ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;a = [1, 2, 3]&lt;br /&gt;b = [4, 5, 6]&lt;br /&gt;a.zip(b) =&gt; [[1,4], [2,5], [3,6]]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We can see that we end up with an array that's the same size as the original arrays made up of elements of each of the arrays. We can also zip multiple arrays ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;a = [1, 2, 3]&lt;br /&gt;b = [4, 5, 6]&lt;br /&gt;c = [7, 8, 9]&lt;br /&gt;d = %w[a, b, c]&lt;br /&gt;a.zip(b, c, d) =&gt; [[1, 4, 7, "a,"], [2, 5, 8, "b,"], [3, 6, 9, "c"]] &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;With that here's the documented code for the upside_up program including, at the beginning, the original requirements from Programming Praxis ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;# An “upside up” number is a number that reads the same when it is rotated&lt;br /&gt;# 180°. For instance, 689 and 1961 are upside up numbers.&lt;br /&gt;&lt;br /&gt;# Your task is to find the next upside up number greater than 1961, and to&lt;br /&gt;# count the number of upside up numbers less than ten thousand. When you are&lt;br /&gt;# finished, you are welcome to read or run a suggested solution, or to post&lt;br /&gt;# your own solution or discuss the exercise in the comments below.&lt;br /&gt;#&lt;br /&gt;# Create an array of pairs that can match. We should end up with&lt;br /&gt;# UPSIDE_DICT = [[0, 0], [1, 1], [6, 9], [8, 8], [9, 6]] &lt;br /&gt;UPSIDE_DICT = %w[0 1 6 8 9].zip(%w[0 1 9 8 6])&lt;br /&gt;&lt;br /&gt;# Open the Integer class and add the upside_up? method that returns true/false&lt;br /&gt;# based on whether the integer is an upside number or not.&lt;br /&gt;# Let's take this a piece at a time:&lt;br /&gt;# 1) self.to_s.split(//) will give us an array of characters for the given number&lt;br /&gt;#    such as [1, 9, 6, 1]&lt;br /&gt;# 2) zip this array with&lt;br /&gt;# 3) self.to_s.split(//).reverse will give us the array above reversed ...&lt;br /&gt;#    [1, 6, 9, 1]&lt;br /&gt;# 4) and zipping the two together should give us something like ...&lt;br /&gt;#    [[1, 1], [9, 6], [6, 9], [1, 1]]&lt;br /&gt;# 5) Now, we'll loop through the above zipped array using inject and make sure that every pair&lt;br /&gt;#    in it is also in the UPSIDE_DICT array. If all of them are, then we'll return&lt;br /&gt;#    true otherwise the inject() will return false.&lt;br /&gt;class Integer&lt;br /&gt;    def upside_up?&lt;br /&gt;        self.to_s.split(//).zip(self.to_s.split(//).reverse).inject(true) { |r,v| r &amp;&amp; UPSIDE_DICT.include?(v) }&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Find all the upside values up to 10000 and print them.&lt;br /&gt;(1..10000).each do |v|&lt;br /&gt;    puts "#{v} is an upside number" if v.upside_up?&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Be sure to let me know if you have questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-2460706984704019620?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/2460706984704019620/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2011/05/arrayzip-and-upside-up-numbers.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/2460706984704019620'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/2460706984704019620'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2011/05/arrayzip-and-upside-up-numbers.html' title='Array.zip() and Upside Up Numbers'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-2743314780073796839</id><published>2011-05-18T05:57:00.000-07:00</published><updated>2011-05-18T07:44:02.830-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='interviewing'/><title type='text'>Interviewing</title><content type='html'>I had a young person come in for an internship interview a couple of days ago and it made me realize that I've never posted anything outside the programming world. I'm going to try to do a few different posts on the subject of interviews and resumes to hopefully help give some perspective to the hiring process from someone who actually hires rather than someone who tries to get you hired (head hunter). Is my perspective better than theirs? No probably not, but it may be a bit different.&lt;br /&gt;&lt;br /&gt;With any interview there are going to be both soft questions and hard questions. By this I don't mean easy and hard but personality questions and technical questions. Let's start by looking at some of the soft questions you might get and why they're asked in the first place. The first thing to remember here is that you're going to be part of a group (as an aside, I hate the term "team" unless you're all dressed the same). Because of this, the hiring manager is going to want to know how you're going to fit in with the rest of the group and the soft questions will be used to try to ascertain that.&lt;br /&gt;&lt;br /&gt;One question that seems to get asked is "Tell me about yourself". This is where you should discuss your interests related to the job. Since the interviewer is most likely going to ask about job related items later, now is a good time to bring up any outside projects that might relate. Open source projects that you've done or contributed to or a blog that you write (programming/technical related) are things that will get the interviewer's attention. Just about anything technically related is a good thing to bring up.&lt;br /&gt;&lt;br /&gt;You're also almost certain to get a question on a group project that you worked on. Here, it won't matter if you're a developer with 20 years experience or a new grad, you'll probably have to talk about working with other people. The question may be as straight forward as "Tell me about a project that you worked on with other people." or it may be more subtle "Tell me about your last project" with the expectation that this involved other people. As you talk about this project, you may get follow on questions such as "Were there any personal issues between people in the group?" or "Was there anyone in the group who didn't pull their weight?". Then these will be followed up with "How did these issues get resolved?". All of these questions are geared towards finding out how well you will fit in in a group situation. And, as a subtext, the interviewer will be looking for your "leadership" capabilities. All of these questions are a chance for you to show that you will work well in a group and not just work well but make the whole group work better. In the example of someone not pulling their weight, stating that you noticed that Fred wasn't doing what was expected, you could tell how you talked with Fred and let him know that you'd noticed his work wasn't as good as it had been and then worked with him to get him back up to speed. In the case of personality issues, discuss how in a meeting where things were getting tense, you played the peacemaker by making sure that both sides got heard and then working through the issues.&lt;br /&gt;&lt;br /&gt;There's probably more, but these are the types of questions that I'll usually pursue, these (or similar ones) and then follow ons based on the responses I receive. The thing to remember though is that all of these soft questions are designed for better or worse to figure out if you will fit in the group structure. Try to approach them in this way and you should do fine.&lt;br /&gt;&lt;br /&gt;As always, let me know if you have questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-2743314780073796839?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/2743314780073796839/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2011/05/interviewing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/2743314780073796839'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/2743314780073796839'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2011/05/interviewing.html' title='Interviewing'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-8472672802638137644</id><published>2011-04-20T06:28:00.000-07:00</published><updated>2011-04-20T06:47:49.290-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='dynamic programming'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><title type='text'>All True</title><content type='html'>I was working a problem on &lt;a href="http://programmingpraxis.com/2011/04/19/same-five-digits/"&gt;Programming Praxis&lt;/a&gt; yesterday and ended up writing a little piece of code that returned true if every element in a hash was true. It used inject and I thought it would be worth posting a generalized version here.&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;module Enumerable&lt;br /&gt;    def all_true&lt;br /&gt;        self.inject(true) { |r, v| r &amp;&amp; (yield v) }&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We start by &lt;a href="http://en.wikipedia.org/wiki/Monkey_patch"&gt;monkey patching&lt;/a&gt; the &lt;code&gt;Enumerable&lt;/code&gt; module which will make it available for &lt;code&gt;Array&lt;/code&gt;s, &lt;code&gt;Hash&lt;/code&gt;es, etc., basically anything that includes &lt;code&gt;Enumerable&lt;/code&gt;. Next, we define the method &lt;code&gt;all_true&lt;/code&gt;. The only line in the method is an &lt;code&gt;inject&lt;/code&gt; which we initialize with &lt;code&gt;true&lt;/code&gt; and then give it a block with two parameters, the r(esult) and the v(alue). We then &lt;code&gt;and/&amp;&amp;&lt;/code&gt; the r(esult) with whatever the yield of the v(alue) returns.&lt;br /&gt;&lt;br /&gt;You can test it with the following code ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;puts "#{[2, 4, 6, 8].all_true { |n| n%2 == 0 }}"&lt;br /&gt;puts "#{[2, 4, 7, 8].all_true { |n| n%2 == 0 }}"&lt;br /&gt;&lt;br /&gt;puts "#{{ 2=&gt;2, 4=&gt;4, 6=&gt;6, 8=&gt;8}.all_true { |n| n[0]%2 == 0 &amp;&amp; n[1]%2 == 0 }}"&lt;br /&gt;puts "#{{ 2=&gt;2, 4=&gt;4, 7=&gt;7, 8=&gt;8}.all_true { |n| n[0]%2 == 0 &amp;&amp; n[1]%2 == 0 }}"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The first two of each set will return true, the second false.&lt;br /&gt;&lt;br /&gt;As I've been doing the &lt;a href="http://programmingpraxis.com/"&gt;Programming Praxis&lt;/a&gt; problems, I've found myself using &lt;code&gt;inject&lt;/code&gt; and its close relative &lt;code&gt;map/collect&lt;/code&gt; more and more. I think this is partly because of the types of problems posted there and the influence of the solutions that are generated which tend to be &lt;a href="http://en.wikipedia.org/wiki/Functional_programming"&gt;functional programming&lt;/a&gt; based. At any rate, having a good understanding of both &lt;code&gt;inject&lt;/code&gt; and &lt;code&gt;map/collect&lt;/code&gt; will serve you well and simplify many of your day to day programming tasks.&lt;br /&gt;&lt;br /&gt;Let me know if you have questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-8472672802638137644?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/8472672802638137644/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2011/04/all-true.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/8472672802638137644'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/8472672802638137644'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2011/04/all-true.html' title='All True'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-5354108223945634398</id><published>2011-03-29T14:02:00.001-07:00</published><updated>2011-03-29T14:09:20.213-07:00</updated><title type='text'>Nanoc and No Compiling or Routing</title><content type='html'>Here's a short post on using nanoc with files that you just want copied from the content directory to the output directory unchanged. For these types of files, it's best if you have them in their own subdirectory (say images or css). Let's say we have some images (.jpg, .png, etc.). First just put them in an images directory under content. Then we need to add a couple of rules to our Rules files ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;compile '/images/*/' do &lt;br /&gt;  # Leave everything in the images directory as is.&lt;br /&gt;end &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and then a bit later on in the routing section ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;route '/images/*/' do &lt;br /&gt;    # Make sure that /images/some_image/ is routed to &lt;br /&gt;    # /images/some_image.jpg or /images/some_image.png or so &lt;br /&gt;    item.identifier.chop + '.' + item[:extension] &lt;br /&gt;end &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I didn't do an actual project and put it up on GitHub for this one, but if this isn't clear, then let me know and I can do that too.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-5354108223945634398?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/5354108223945634398/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2011/03/nanoc-and-no-compiling-or-routing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/5354108223945634398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/5354108223945634398'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2011/03/nanoc-and-no-compiling-or-routing.html' title='Nanoc and No Compiling or Routing'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-4546751812144046619</id><published>2011-03-25T09:21:00.000-07:00</published><updated>2011-03-25T09:46:27.887-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='nanoc'/><title type='text'>Nanoc and Multiple Layout Templates</title><content type='html'>A while back we took a &lt;a href="http://steamcode.blogspot.com/2011/01/nanoc-and-static-web-sites.html"&gt;quick look&lt;/a&gt; at &lt;a href="http://nanoc.stoneship.org/"&gt;nanoc&lt;/a&gt; for generating static web sites. I've been using it a bit both experimenting and for a simple web site for an author friend of mine. I'm going to do a few short articles on using it, documenting what I've learned in much the same way I've tried to do with Ramaze. &lt;br /&gt;&lt;br /&gt;Let's start with some simple code that uses multiple layout templates. You have this often with web sites where there's a home page that uses a different layout than the rest of the pages of the site. Let's start with creating a new site. We do that the same way we did last time with ...&lt;br /&gt;&lt;br /&gt;&lt;code&gt;nanoc create_site multiple_templates&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;and let's add a couple of pages to go along with them ...&lt;br /&gt;&lt;br /&gt;&lt;code&gt;nanoc create_item page1&lt;/code&gt;&lt;br /&gt;&lt;code&gt;nanoc create_item page2&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;We didn't really talk about the Rules in the last post and I'm only going to touch on them now. You should take a few minutes and read a bit about them &lt;a href="http://nanoc.stoneship.org/docs/4-basic-concepts/#rules"&gt;here&lt;/a&gt;. We'll discuss them a bit more as we go through future posts.&lt;br /&gt;&lt;br /&gt;Now, we need to modify the Rules file to tell it to use an alternate layout for the content/page[12].html files. I'm not going to show the entire file, just the compile rule for these ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;compile '/page*/' do&lt;br /&gt;  filter :erb&lt;br /&gt;  layout 'page'&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What this rule says is that when we "compile" files in our content/ directory, we should first run them through the &lt;a href="http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/"&gt;erb&lt;/a&gt; (embedded ruby) and then use the page template in the layouts directory.&lt;br /&gt;&lt;br /&gt;Here's the default which will get use by everything else (essentially our main page at content/index.html).&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;compile '*' do&lt;br /&gt;  filter :erb&lt;br /&gt;  layout 'default'&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This along with the code for all of this up on &lt;a href="https://github.com/slabounty/multiple_templates"&gt;github&lt;/a&gt; should be enough to get you started. As always though, let me know if you have questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-4546751812144046619?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/4546751812144046619/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2011/03/nanoc-and-multiple-layout-templates.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/4546751812144046619'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/4546751812144046619'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2011/03/nanoc-and-multiple-layout-templates.html' title='Nanoc and Multiple Layout Templates'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-5875962732779558304</id><published>2011-03-01T14:05:00.000-08:00</published><updated>2011-03-01T14:22:26.136-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='inkscape'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>Inkscape</title><content type='html'>This one is going to be short since I'm not a designer. I've been reading &lt;a href="http://www.amazon.com/Web-Design-Developers-Programmers-Techniques/dp/1934356131/ref=sr_1_1?s=books&amp;ie=UTF8&amp;qid=1299017288&amp;sr=1-1"&gt;"Web Design for Developers"&lt;/a&gt; by Brian P. Hogan and he recommends using &lt;a href="http://www.adobe.com/products/illustrator/"&gt;Illustrator&lt;/a&gt; for parts of his book. Since the cost was a bit umm... prohibitive for learning purposes, I started looking around for a suitable alternative. What I found was &lt;a href="http://inkscape.org/"&gt;Inkscape&lt;/a&gt;. This is a nice little program for generating SVG (Scalable Vector Graphics) files. You can use it for generating files for say logos or banners on websites. While I won't say it's simple to use (and this probably says more about me than the program), with the tutorials available, you shouldn't have too much problem getting it to work. Additionally, there's a book on it that's reviewed on &lt;a href="http://books.slashdot.org/story/11/02/28/1430231/Book-Review-Inkscape-048-Essentials-for-Web-Designers"&gt;Slashdot&lt;/a&gt;. I haven't read the book yet but do have it on order and if it seems worthwhile, I'll post here about it.&lt;br /&gt;&lt;br /&gt;To install ...&lt;br /&gt;&lt;br /&gt;&lt;kbd&gt;sudo apt-get install inkscape&lt;/kbd&gt; &lt;br /&gt;&lt;br /&gt;and you should have an inkscape selection Applications/Graphics or at least on Ubuntu.&lt;br /&gt;&lt;br /&gt;Once again, I'm not sure how much I'll be able to help, but if you have questions, be sure and let me know.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-5875962732779558304?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/5875962732779558304/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2011/03/inkscape.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/5875962732779558304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/5875962732779558304'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2011/03/inkscape.html' title='Inkscape'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-1549276932396837219</id><published>2011-01-28T05:43:00.000-08:00</published><updated>2011-01-28T06:37:04.195-08:00</updated><title type='text'>Nanoc and Static Web Sites</title><content type='html'>A few days ago we &lt;a href="http://steamcode.blogspot.com/2011/01/webby-and-static-web-sites.html"&gt;looked at&lt;/a&gt; &lt;a href="http://webby.rubyforge.org/"&gt;Webby&lt;/a&gt; for generating static web sites. I had a couple of issues with it, including the fact that it didn't work with ruby 1.9.2 and it hasn't been updated for a couple of years now. Someone on the Ramaze email list suggested that I should take a look at &lt;a href="http://nanoc.stoneship.org/"&gt;nanoc&lt;/a&gt; too. It seems to have many of the same features as webby, but is actively maintained and runs on ruby 1.9.2. So let's take a look at getting it up, running, and generating a site. First, we'll need to add a few gems ...&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;gem install nanoc&lt;br /&gt;gem install kramdown&lt;br /&gt;gem install adsf&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Here we're installing nanoc itself, &lt;a href="http://kramdown.rubyforge.org/"&gt;kramdown&lt;/a&gt;, which is a Markdown converter, and &lt;a href="http://stoneship.org/software/adsf/"&gt;adsf&lt;/a&gt;, which is used as a web server for showing the site.&lt;br /&gt;&lt;br /&gt;With that out of the way, let's go ahead and create a new site ...&lt;br /&gt;&lt;br /&gt;&lt;code&gt;nanoc create_site my_site&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This should create a new site in the directory my_site that has a few different files and directories. Go ahead and cd into the directory and then&lt;br /&gt;&lt;br /&gt;&lt;code&gt;nanoc compile&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;which should "compile" the site. In this case, compile will create an output directory where the resulting HTML files will reside. OK, now we can start a web server with &lt;br /&gt;&lt;br /&gt;&lt;code&gt;nanoc view&lt;/code&gt; &lt;br /&gt;&lt;br /&gt;and then point our browser at http://localhost:3000. At this point you should see the default site for nanoc. For viewing, you could also use&lt;br /&gt;&lt;br /&gt;&lt;code&gt;nanoc autocompile&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;which will also compile a file when changes are made to the site automatically. For "real" work, this is probably the option to use. &lt;br /&gt;&lt;br /&gt;OK, let's take a look at the content directory. This is where nanoc will keep the files that will get compiled and moved to the output directory. Go ahead and open up content/index.html in your &lt;a href="http://www.vim.org/"&gt;favorite text editor&lt;/a&gt; and make a few changes. Go back to the browser, reload, and you should see your changes there. Now, take a look at layout/default.html. If you make a change in there, say adding an h1 tag before the h2 Documentation tag, it will appear in all the pages that are generated. &lt;br /&gt;&lt;br /&gt;Finally, we're going to need to add new pages if this is going to be useful. Try this ...&lt;br /&gt;&lt;br /&gt;&lt;code&gt;nanoc create_item test&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This will create a test.htnml in the content directory and when it gets compiled, you should be able to go to http://localhost:3000/test/ (don't forget the final "/") and see the page. A couple of things to note here. In the output directory, this will be output/test/index.html. &lt;br /&gt;&lt;br /&gt;This should be enough to get you started. Definitely check out the &lt;a href="http://nanoc.stoneship.org/"&gt;nanoc site&lt;/a&gt; for more information. I'm going to use this to generate a personal site, so I'll let you know how it goes and what good/bad things I see.&lt;br /&gt;&lt;br /&gt;Let me know if you have questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-1549276932396837219?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/1549276932396837219/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2011/01/nanoc-and-static-web-sites.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/1549276932396837219'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/1549276932396837219'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2011/01/nanoc-and-static-web-sites.html' title='Nanoc and Static Web Sites'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-5676981930142660580</id><published>2011-01-25T18:07:00.000-08:00</published><updated>2011-01-25T18:13:48.470-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='praxis'/><title type='text'>Ruby and Rational Numbers</title><content type='html'>Here's a problem over on &lt;a href="http://programmingpraxis.com/2011/01/25/rational-numbers/"&gt;Programming Praxis&lt;/a&gt; that for whatever reason I wasn't having much luck posting there. Their loss, your gain ;-). Here's the code ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;class Fraction&lt;br /&gt;&lt;br /&gt;    attr_reader :n, :d&lt;br /&gt;&lt;br /&gt;    def initialize(n, d)&lt;br /&gt;        raise "Can't have zero denominator." if d == 0 &lt;br /&gt;&lt;br /&gt;        n, d = -n, -d if d &lt; 0&lt;br /&gt;&lt;br /&gt;        g = n.gcd(d)&lt;br /&gt;        if g == 1&lt;br /&gt;            @n = n&lt;br /&gt;            @d = d&lt;br /&gt;        else&lt;br /&gt;            @n = n / g&lt;br /&gt;            @d = n / g&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def plus(f)&lt;br /&gt;        Fraction.new((@n*f.d)+(@d*f.n), @d*f.d)&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def minus(f)&lt;br /&gt;        Fraction.new((@n*f.d)-(@d*f.n), @d*f.d)&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def times(f)&lt;br /&gt;        Fraction.new(@n*f.n, @d*f.d)&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def divide(f)&lt;br /&gt;        Fraction.new(@n*f.d, @d*f.n)&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def to_s&lt;br /&gt;        "#{@n}/#{@d}"&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;f1 = Fraction.new(1, 3)&lt;br /&gt;f2 = Fraction.new(-1, 7)&lt;br /&gt;puts "#{f1} + #{f2} = #{f1.plus(f2)}"&lt;br /&gt;puts "#{f1} + #{f2} = #{f1.minus(f2)}"&lt;br /&gt;puts "#{f1} + #{f2} = #{f1.times(f2)}"&lt;br /&gt;puts "#{f1} + #{f2} = #{f1.divide(f2)}"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Nothing too awfully complex here, but if you have questions, let me know.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-5676981930142660580?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/5676981930142660580/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2011/01/ruby-and-rational-numbers.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/5676981930142660580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/5676981930142660580'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2011/01/ruby-and-rational-numbers.html' title='Ruby and Rational Numbers'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-2944061882678316714</id><published>2011-01-24T19:13:00.001-08:00</published><updated>2011-01-24T19:35:49.281-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='webby'/><title type='text'>Webby and Static Web Sites</title><content type='html'>I was trying to figure out recently how to build a static site with Ramaze and didn't really come up with anything, but someone pointed me in the direction of &lt;a href="http://webby.rubyforge.org/"&gt;Webby&lt;/a&gt; that's designed with just this use case in mind. It seems pretty cool, so I thought I'd document how to get it up and running on Ubuntu. &lt;br /&gt;&lt;br /&gt;First I tried just doing a gem install, but that didn't work because I'm using ruby 1.9.2 so ...&lt;br /&gt;&lt;br /&gt;&lt;code&gt;rvm install 1.8.7&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;to get the right ruby (assuming you're using rvm to manage this). Then, you'll need to set the correct ruby with &lt;br /&gt;&lt;br /&gt;&lt;code&gt;rvm 1.8.7&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;to add the following gems for ruby 1.8.7&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;gem install webby&lt;br /&gt;gem install RedCloth&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The RedCloth gem is needed for the default, but if you decide to use a different templating system, you don't need to install it.&lt;br /&gt;&lt;br /&gt;OK, let's create a web site now.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;webby-gen website my_site&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;There should now be a directory called my_site with a few different directories. Now you can&lt;br /&gt;&lt;code&gt;&lt;br /&gt;cd my_site&lt;br /&gt;webby&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;and this should create a new directory called output with some HTML files and the css for the site. If you modify the file index.txt in the content directory, and then rerun the &lt;code&gt;webby&lt;/code&gt; command, you should see the output/index.html change. &lt;br /&gt;&lt;br /&gt;Since you've been reading this blog, you probably have a pretty good idea of how templating works, so there really shouldn't be too much here that you haven't seen in general even if you haven't looked at the RedCloth templating. webby also supports a number of other templating systems that you can use by setting a filter in the content file. This is documented in the &lt;a href="http://webby.rubyforge.org/"&gt;User Manual&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;To be honest, I just started looking at this today, so I'm not sure how much help I'm going to be with questions, but let me know if you have any and I'll give them a shot.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-2944061882678316714?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/2944061882678316714/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2011/01/webby-and-static-web-sites.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/2944061882678316714'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/2944061882678316714'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2011/01/webby-and-static-web-sites.html' title='Webby and Static Web Sites'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-1486543029614470464</id><published>2010-11-30T05:52:00.000-08:00</published><updated>2010-11-30T06:11:09.650-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='ramaze'/><title type='text'>Ruby 1.9.2 and Ramaze</title><content type='html'>OK, I just found out something interesting about ruby 1.9.2. They've changed the default LOAD_PATH to not include "." (current directory). What's this actually mean? Well, for starters just about every example that I and most others have written will no longer work. Here's an example with something from the current Ramaze prototype (generated when you do a &lt;code&gt;ramaze create foo&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;require 'model/user'&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;this will generate errors if you run it with ruby 1.9.2. What you'll need to do instead is either&lt;br /&gt;&lt;br /&gt;&lt;code&gt;__DIR__('user')&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;or &lt;br /&gt;&lt;br /&gt;&lt;code&gt;require_relative 'user'&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The first version is compatible between 1.9 and 1.8 and the 2nd is 1.9 only. Both examples assume that the file this code is in is already in the model directory. &lt;br /&gt;&lt;br /&gt;I should also note that Lee Jarvis has fixed the problem with the prototype already and it should be in the next update of Ramaze.&lt;br /&gt;&lt;br /&gt;Like I said, most of my examples from previous posts are now wrong, but they should be pretty easy to fix once you know how. If you have any problems, be sure to let me know and I'll try to help get them worked out with you.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-1486543029614470464?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/1486543029614470464/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/11/ruby-192-and-ramaze.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/1486543029614470464'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/1486543029614470464'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/11/ruby-192-and-ramaze.html' title='Ruby 1.9.2 and Ramaze'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-8525884989171238901</id><published>2010-11-24T08:52:00.000-08:00</published><updated>2010-11-24T08:55:29.321-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Ruby Book  - $10</title><content type='html'>This is a pretty good deal for the latest Ruby pickaxe book from Dave Thomas and the Pragmatic Programmer group. It's $10 each for the paper or electronic version of the book. Head over &lt;a href="http://www.pragprog.com/titles/ruby3/programming-ruby-1-9?utm_source=MadMimi&amp;utm_medium=email&amp;utm_content=[Bookshelf]+Updated+Programming+Ruby+now+in+epub%2C+mobi+and+on+sale&amp;utm_campaign=[Bookshelf]+Updated+Programming+Ruby+now+in+epub%2C+mobi+and+on+sale&amp;utm_term=pragprog_com_2Ftitles_2Fruby3"&gt;here&lt;/a&gt; to grab it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-8525884989171238901?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/8525884989171238901/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/11/ruby-book-10.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/8525884989171238901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/8525884989171238901'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/11/ruby-book-10.html' title='Ruby Book  - $10'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-1000275973265994406</id><published>2010-10-16T14:17:00.000-07:00</published><updated>2010-10-16T15:26:06.976-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='dynamic programming'/><title type='text'>Log Monitoring with a Ruby DSL</title><content type='html'>&lt;a href="http://en.wikipedia.org/wiki/Domain-specific_language"&gt;DSLs (Domain Specific Languages)&lt;/a&gt; are small languages built on top of general purpose languages to accomplish specific tasks. Examples of DSLs are things like rake/make for building executables, bc (the Unix/Linux calculator), and macro systems like the C/C++ precompiler and M4. Ruby, because of its syntax provides a great platform for building DSLs.&lt;br /&gt;&lt;br /&gt;Recently, at work, we ended up needing to monitor a log file for a particular string. Our OPS group implemented this, but it turned out that we were getting quite a few false positives from the string by itself. We could however do a database check on a couple of items in the string to remove these false positives. The logging software we use didn't really allow this so we ended up putting together a .NET application (Windows box) that would be called when the string was found, it would do the database check, and then do the notifications as necessary. I started thinking that it would be nice if you could match a string and then provide some code to do whatever you'd like in a monitoring type system. Since I'd been looking at DSLs, this seemed like it might be a natural application for them.&lt;br /&gt;&lt;br /&gt;Let's start out with a simple program to provide us a log file to monitor ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;while true&lt;br /&gt;    v = rand&lt;br /&gt;    if v &lt; 0.1&lt;br /&gt;        s = "Error"&lt;br /&gt;    elsif v &lt; 0.2&lt;br /&gt;        s = "Warn"&lt;br /&gt;    else&lt;br /&gt;        s = "Info"&lt;br /&gt;    end&lt;br /&gt;    puts "#{Time.new}: #{s}"&lt;br /&gt;    $stdout.flush&lt;br /&gt;    sleep 1&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So essentially, do forever, get a random number, 1/10 of the time put out an Error, 1/10 of the time put out a Warning, and the rest of the time put out an Info. These will all be preceded by the date/time. Obviously, in a real system, you'd just use your own logs. For this, I just ran this and redirected the output to &lt;code&gt;mylog.txt&lt;/code&gt;. &lt;br /&gt;&lt;br /&gt;OK, here's the DSL we'd like to implement. I put it in &lt;code&gt;monitor.mon&lt;/code&gt; and when we run the program, we'll "interpret" this file. Here it is ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;monitor "Er.*r" do |line, match|&lt;br /&gt;    puts "Error in: #{line} "&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;monitor "Warn" do |line, m|&lt;br /&gt;    puts "Warning in: Match: #{m[0]}: #{line} "&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;monitor "Info"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So in the first item to monitor, we look for something like an "Error" (the ".*" is in there really just to show this can really be a regular expression. The second thing to monitor is the word "Warn", and finally the work "Info". In the first two cases we print a message, with the 2nd one actually showing the "match". We don't give a block to the 3rd one, but the default is to print a message too. Now even though we've done something pretty simple here, there is nothing preventing us from doing whatever we'd like in them that we can do in Ruby. Here, I'm thinking of things like emailing using possibly &lt;a href="http://github.com/manveru/mailit"&gt;mailit&lt;/a&gt;) or database access as in our above problem using &lt;a href="http://sequel.rubyforge.org/"&gt;Sequel&lt;/a&gt;. At this point, we can "shell out" to the general purpose programming language of Ruby.&lt;br /&gt;&lt;br /&gt;So, now we need to interpret the above file. Here's the code for this &lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;require 'file/tail'&lt;br /&gt;&lt;br /&gt;class MonitorLog &lt;br /&gt;&lt;br /&gt;    def initialize(filename, number)&lt;br /&gt;        @filename = filename&lt;br /&gt;        @number = number&lt;br /&gt;        @monitors = []&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # Add a new monitor (regex/block).&lt;br /&gt;    def add_monitor(monitor)&lt;br /&gt;        @monitors &lt;&lt; monitor&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # Monitor the log using the filename passed in. For each&lt;br /&gt;    # line we'll check for a monitor match.&lt;br /&gt;    def monitor&lt;br /&gt;        File::Tail::Logfile.open(@filename) do |log|&lt;br /&gt;            log.backward(@number).tail do |line| &lt;br /&gt;                @monitors.each do |m|&lt;br /&gt;                    m.match line&lt;br /&gt;                end&lt;br /&gt;            end&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# The Monitor class which is a type of Regexp with a block given for checking.&lt;br /&gt;class Monitor&lt;br /&gt;&lt;br /&gt;    # Create a new monitor with a regex and a block.&lt;br /&gt;    def initialize(regex, block)&lt;br /&gt;        @regex = Regexp.new regex&lt;br /&gt;        @block = block&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # Match a line. If we match, then we'll call the block&lt;br /&gt;    # with the line and the MatchData.&lt;br /&gt;    def match(line)&lt;br /&gt;        m = @regex.match(line)&lt;br /&gt;        @block.call(line, m) if m != nil&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# This will normally come from the monitor file where there will be a regular&lt;br /&gt;# expression and a block to execute when it is found. If no block is given,&lt;br /&gt;# we'll just print the line.&lt;br /&gt;def monitor(regex, &amp;block)&lt;br /&gt;    if block_given?&lt;br /&gt;        $monitor_log.add_monitor Monitor.new(regex, block)&lt;br /&gt;    else&lt;br /&gt;        $monitor_log.add_monitor Monitor.new(regex, lambda { |l, m| puts "Match: #{l}" })&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;if __FILE__ == $PROGRAM_NAME&lt;br /&gt;&lt;br /&gt;require 'getoptlong'&lt;br /&gt;&lt;br /&gt;def usage&lt;br /&gt;    puts "Usage #$0 [-n number] [-f filename] [-m monitor_filename]"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Set up the command line options&lt;br /&gt;opts = GetoptLong.new(&lt;br /&gt;    ["--number", "-n", GetoptLong::REQUIRED_ARGUMENT],&lt;br /&gt;    ["--filename", "-f", GetoptLong::REQUIRED_ARGUMENT],&lt;br /&gt;    ["--monitor_file", "-m", GetoptLong::REQUIRED_ARGUMENT],&lt;br /&gt;    ["--verbose", "-v", GetoptLong::NO_ARGUMENT],&lt;br /&gt;    ["--help", "-h", GetoptLong::NO_ARGUMENT]&lt;br /&gt;    )&lt;br /&gt;&lt;br /&gt;# Set the default values for the options&lt;br /&gt;number = 10&lt;br /&gt;filename = 'monitor.log'&lt;br /&gt;monitor_filename = 'monitor.mon'&lt;br /&gt;$verbose = false&lt;br /&gt;&lt;br /&gt;# Parse the command line options. If we find one we don't recognize&lt;br /&gt;# an exception will be thrown and we'll rescue with a usage.&lt;br /&gt;begin&lt;br /&gt;    opts.each do | opt, arg|&lt;br /&gt;        case opt&lt;br /&gt;        when "--number"&lt;br /&gt;            number = arg.to_i&lt;br /&gt;        when "--filename"&lt;br /&gt;            filename = arg&lt;br /&gt;        when "--monitor_filename"&lt;br /&gt;            monitor_filename = arg&lt;br /&gt;        when "--verbose"&lt;br /&gt;            $verbose = true&lt;br /&gt;        when "--help"&lt;br /&gt;            usage&lt;br /&gt;            exit&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;rescue&lt;br /&gt;    usage&lt;br /&gt;    exit&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# Create the montior log. We make it global as it's used for the monitor()&lt;br /&gt;# creation method above.&lt;br /&gt;$monitor_log = MonitorLog.new(filename, number)&lt;br /&gt;&lt;br /&gt;# Load in the monitor file DSL.&lt;br /&gt;load(monitor_filename)&lt;br /&gt;&lt;br /&gt;# Start monitoring.&lt;br /&gt;$monitor_log.monitor&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Our first class is &lt;code&gt;MonitorLog&lt;/code&gt; which takes a filename to monitor and a number the number of lines to start back in the file. We also have an array for the different monitors we define in the &lt;code&gt;monitor.mon&lt;/code&gt; file. There's a &lt;code&gt;add_monitor&lt;/code&gt; which takes a monitor and adds it to the array and finally, the &lt;code&gt;monitor&lt;/code&gt; (I know too many monitor variables) which uses the &lt;a href="http://github.com/flori/file-tailhttp://github.com/flori/file-tail"&gt;file-tail gem&lt;/a&gt;. This method will simply tail the file and for each line call each of the monitors. The &lt;code&gt;Monitor&lt;/code&gt; class contains a regular expression to match and a block to execute on a match. In the &lt;code&gt;match&lt;/code&gt; method, we check the regular expression and if it matches, we'll call the block with the line we matched and the &lt;code&gt;MatchData&lt;/code&gt;. Here, if we had a more interesting regex than I've shown so far, you could grab out things like login IDs or similar from the &lt;code&gt;MatchData&lt;/code&gt; if you needed it for something rather than reparsing the line. &lt;br /&gt;&lt;br /&gt;Now comes the "interesting" piece, the &lt;code&gt;monitor&lt;/code&gt; (I know, I know). Note that this matches with the &lt;code&gt;monitor.mon&lt;/code&gt; name and indeed this is what gets called when that file is loaded (see below). The two parameters are the regex and potentially a block. If the block is given we create a &lt;code&gt;Monitor&lt;/code&gt; using them and if there's no block, as in the &lt;code&gt;Info&lt;/code&gt; then we'll create a &lt;code&gt;lambda&lt;/code&gt; that will print out "Match" and the line. &lt;br /&gt;&lt;br /&gt;The rest of the code is the "main" program, getting the command line arguments, creating a new &lt;code&gt;$monitor_log&lt;/code&gt; (made global for use in the &lt;code&gt;monitor&lt;/code&gt; method, here, I'd be interested in a better way to do this), loading the &lt;code&gt;monitor.mon&lt;/code&gt; file, and finally starting the monitoring. &lt;br /&gt;&lt;br /&gt;Here's how to run this code &lt;kbd&gt;ruby Monitor.rb -n 20 -f mylog.txt -m monitor.mon&lt;/kbd&gt;.&lt;br /&gt;&lt;br /&gt;There's quite a bit missing here to make this a truely useful application. Certainly adding email would get you a long way towards this and is really easy to do. The slightly more difficult thing is to make this work with rotating log files or even multiple log files and these are left as an exercise for the reader ;-).&lt;br /&gt;&lt;br /&gt;Let me know if you have questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-1000275973265994406?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/1000275973265994406/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/10/log-monitoring-with-ruby-dsl.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/1000275973265994406'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/1000275973265994406'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/10/log-monitoring-with-ruby-dsl.html' title='Log Monitoring with a Ruby DSL'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-660556445731577725</id><published>2010-10-12T05:35:00.000-07:00</published><updated>2010-10-12T05:54:19.714-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='praxis'/><title type='text'>Zeller's Congruence and Five Fr/Sa/Su in October</title><content type='html'>I saw a comment from one of my Facebook friends that October 2010 had five Fridays, Saturdays, and Sundays and that this occurred only once every 823 years. Now this didn't sound exactly right to me and it didn't take much time to figure out why. Take a look at the following calendar&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;   Su  Mo  Tu  We  Th  Fr  Sa&lt;br /&gt;                        1   2&lt;br /&gt;    3   4   5   6   7   8   9&lt;br /&gt;   10  11  12  13  14  15  16&lt;br /&gt;   17  18  19  20  21  22  23&lt;br /&gt;   24  25  26  27  28  29  30&lt;br /&gt;   31&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You can see pretty easily from this, that a) we'll have the five Fr/Sa/Su anytime we start October on a Friday and b) no other configuration will have this. Now just thinking about this off the top of my head, I figured that this should happen about ever 7 years (disregarding leap years). &lt;br /&gt;&lt;br /&gt;Now as it happens, I'd also just finished a short ruby method for Zeller's Congruence that I'd written from an &lt;a href="http://programmingpraxis.com/2010/10/08/zellers-congruence/"&gt;article&lt;/a&gt; on Programming Praxis. So, I combined the two and came up with the following ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;# Zeller’s Congruence is a simple mathematical method for determining the day&lt;br /&gt;# of the week for a given date.&lt;br /&gt;# &lt;br /&gt;# In the 1880s, Christian Zeller, a German mathematician, noticed that, if you&lt;br /&gt;# run a year from March through February, the cumulative number of days in each&lt;br /&gt;# month forms a nearly straight line; that works because February, which would&lt;br /&gt;# normally perturb the straight line, is moved to the end. He worked out the&lt;br /&gt;# formula ⌊(13m−1)/5⌋ to give the number of weekdays that the start of the&lt;br /&gt;# month moves each month, where m is the month number.&lt;br /&gt;# &lt;br /&gt;# Then it is easy to calculate the day of the week for any given day: add the&lt;br /&gt;# day of the month, the offset for the number of months since March, an offset&lt;br /&gt;# for each year, and additional offsets for leap years and leap centuries&lt;br /&gt;# (remembering to subtract one year for dates in January and February), taking&lt;br /&gt;# the whole thing mod 7. It’s fun to work out the arithmetic yourself, but if&lt;br /&gt;# you don’t want to take the time, the whole formula is shown in the solution.&lt;br /&gt;# &lt;br /&gt;# Your task is to write a function that uses Zeller’s Congruence to calculate&lt;br /&gt;# the day of the week for any given date. When you are finished, you are&lt;br /&gt;# welcome to read or run a suggested solution, or to post your own solution or&lt;br /&gt;# discuss the exercise in the comments below.#&lt;br /&gt;#&lt;br /&gt;# f = k + floor(13m - 1) / 5) + d + floor(d / 4) + floor(c / 4) - 2c mod 7&lt;br /&gt;#&lt;br /&gt;#   Su  Mo  Tu  We  Th  Fr  Sa&lt;br /&gt;#                        1   2&lt;br /&gt;#    3   4   5   6   7   8   9&lt;br /&gt;#   10  11  12  13  14  15  16&lt;br /&gt;#   17  18  19  20  21  22  23&lt;br /&gt;#   24  25  26  27  28  29  30&lt;br /&gt;#   31&lt;br /&gt;#&lt;br /&gt;#&lt;br /&gt;#&lt;br /&gt;def zeller(year, month, day)&lt;br /&gt;    months = %w[march april may june july august september october november december january february]&lt;br /&gt;    weekdays = %w[Sunday Monday Tuesday Wednesday Thursday Friday Saturday]&lt;br /&gt;    k = day&lt;br /&gt;    m = months.index(month.downcase) + 1&lt;br /&gt;    y = (m &lt;= 10) ? year : year-1&lt;br /&gt;    d = y % 100&lt;br /&gt;    c = y / 100&lt;br /&gt;    f = (k + (((13*m) - 1) / 5).floor + d + (d/4).floor + (c/4).floor - (2*c)) % 7&lt;br /&gt;    weekdays[f]&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;1900.upto(2300) do |y|&lt;br /&gt;    puts "Five Friday, Saturday, and Sundays for October, #{y}" if zeller(y, "october", 1) == "Friday"&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here, we'll just go through the years from 1900 to 2300 or about 400 years and see how many times the five Fr/Sa/Su pattern occurs. If we run this and pipe it through &lt;code&gt;wc -l&lt;/code&gt;, we end up with &lt;code&gt;56&lt;/code&gt;. Interestingly enough, 400 / 7 is 57 which is what we originally calculated above ignoring the leap years.&lt;br /&gt;&lt;br /&gt;Let me know if you have any questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-660556445731577725?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/660556445731577725/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/10/zellers-congruence-and-five-frsasu-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/660556445731577725'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/660556445731577725'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/10/zellers-congruence-and-five-frsasu-in.html' title='Zeller&apos;s Congruence and Five Fr/Sa/Su in October'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-6768761067052998742</id><published>2010-09-22T05:36:00.000-07:00</published><updated>2010-09-22T09:08:37.930-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='cellular automata'/><title type='text'>One Dimensional Cellular Automata</title><content type='html'>While in Texas on a recent business trip, I picked up a copy of "Cellular Automata, A Discrete View of the World" by Joel L. Schiff from Half Priced Books in Richardson, TX. I haven't finished the book yet, but I did write a bit of code to generate one dimensional cellular automata. There are many different varieties of these explored in the book, but we're going to look a simple set where the cells can have two values, in our case black or white, and to generate the next generation, we only look at the cell and it's two immediate neighbors. In this case we're going to end up with 2**8 (or 256) rules for generating the next generation. Here is a good &lt;a href="http://mathworld.wolfram.com/CellularAutomaton.html"&gt;writeup&lt;/a&gt; on this type of cellular automata.&lt;br /&gt;&lt;br /&gt;Here's the code:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;#!ruby&lt;br /&gt;# == Synopsis&lt;br /&gt;# Runs the CA program&lt;br /&gt;#&lt;br /&gt;# == Usage&lt;br /&gt;# ruby CA.rb [-g max_generations] [-r rule] [-c num_cells] [-s] [-v] [-h]&lt;br /&gt;# &lt;br /&gt;# == Author&lt;br /&gt;# Scott LaBounty&lt;br /&gt;#&lt;br /&gt;# == Copyright&lt;br /&gt;# Copyright(c) 2010 Scott LaBounty&lt;br /&gt;#&lt;br /&gt;#&lt;br /&gt;&lt;br /&gt;require 'getoptlong'&lt;br /&gt;&lt;br /&gt;def usage&lt;br /&gt;    puts "Usage: ruby CA.rb [-g max_generations] [-r rule] [-c num_cells] [-s] [-v] [-h]"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# The cellular automata class. This is a one-dimensional cellular automata and &lt;br /&gt;# will use the rules as defined by Wolfram and that I got from Joel L. Schiff's &lt;br /&gt;# "Cellular Automata, A Discrete View of the World".&lt;br /&gt;class CA&lt;br /&gt;&lt;br /&gt;    # Initialize the cellular automata with the number of cells, the rule we'll&lt;br /&gt;    # use to update each time next is called and whether to initialize the&lt;br /&gt;    # first generation with a single black cell in the middle or a random mix&lt;br /&gt;    # of "W" and "B" cells.&lt;br /&gt;    def initialize(num_cells, rule, random_init=false)&lt;br /&gt;        @rule = rule&lt;br /&gt;&lt;br /&gt;        # We add a cell at each end that will always be white.&lt;br /&gt;        @total_cells = num_cells+2 &lt;br /&gt;&lt;br /&gt;        # Initialize the current generation (in this case the first) and&lt;br /&gt;        # the next_cell array (explained more fully in initialize_next_cell).&lt;br /&gt;        initialize_current_gen(random_init)&lt;br /&gt;        initialize_next_cell(rule)&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # Calculate the next generation from the current generation.&lt;br /&gt;    def next&lt;br /&gt;        # Initialize the next generation array.&lt;br /&gt;        next_gen = Array.new(@total_cells, "W")&lt;br /&gt;&lt;br /&gt;        # Calculate the next generation based on the current generation and the&lt;br /&gt;        # rule we're using.&lt;br /&gt;        @current_gen.each_with_index do |cell, i|&lt;br /&gt;            # Skip the ends which will by definition always be white.&lt;br /&gt;            next if (i == 0) || (i == @total_cells-1)&lt;br /&gt;&lt;br /&gt;            # Calculate the next_gen[i] by using the i cell and the two next to&lt;br /&gt;            # it. Get the next value from the next_cell array.&lt;br /&gt;            next_gen[i] = &lt;br /&gt;                case @current_gen[i-1, 3].join&lt;br /&gt;                when "WWW"&lt;br /&gt;                    @next_cell[0]&lt;br /&gt;                when "WWB"&lt;br /&gt;                    @next_cell[1]&lt;br /&gt;                when "WBW"&lt;br /&gt;                    @next_cell[2]&lt;br /&gt;                when "WBB"&lt;br /&gt;                    @next_cell[3]&lt;br /&gt;                when "BWW"&lt;br /&gt;                    @next_cell[4]&lt;br /&gt;                when "BWB"&lt;br /&gt;                    @next_cell[5]&lt;br /&gt;                when "BBW"&lt;br /&gt;                    @next_cell[6]&lt;br /&gt;                when "BBB"&lt;br /&gt;                    @next_cell[7]&lt;br /&gt;                end&lt;br /&gt;        end&lt;br /&gt;&lt;br /&gt;        # Set the current_gen to the next gen.&lt;br /&gt;        @current_gen = next_gen&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def to_s&lt;br /&gt;        @current_gen.join&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    private&lt;br /&gt;&lt;br /&gt;    # Initialize the current_gen array with either a&lt;br /&gt;    # single "B" cell in the middle or with a random&lt;br /&gt;    # mix of "B" and "W" cells.&lt;br /&gt;    def initialize_current_gen(random_init)&lt;br /&gt;        @current_gen = Array.new(@total_cells, "W")&lt;br /&gt;        if random_init&lt;br /&gt;            @current_gen.each_index do |i|&lt;br /&gt;                @current_gen[i] = (rand &lt; 0.5) ? "W" : "B"&lt;br /&gt;            end&lt;br /&gt;        else&lt;br /&gt;            @current_gen[@total_cells/2] = "B"&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;        &lt;br /&gt;    # Initialize the next_cell array based on the rule we're using. If the ith&lt;br /&gt;    # bit is a 0, we'll set it to a "W" and if it's a 1, we'll set it to be a&lt;br /&gt;    # "B". See the "next" method for how this array is actually used. If the&lt;br /&gt;    # cell and its two neighbors are "W" (white), then we use next_cell of 0,&lt;br /&gt;    # If the cell is "W" and its neighbor to the left is "W" and its neighbor&lt;br /&gt;    # to the right is "B" then we use next_cell of 1, and so on.&lt;br /&gt;    def initialize_next_cell(rule)&lt;br /&gt;        @next_cell = Array.new(8)&lt;br /&gt;        @next_cell.each_index do |i| &lt;br /&gt;            @next_cell[i] =  (rule % 2 == 0) ? "W" : "B"&lt;br /&gt;            rule /= 2&lt;br /&gt;        end&lt;br /&gt;        puts "@next_cell = #{@next_cell.join}" if $verbose&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Only run this if this is the main program. This way we&lt;br /&gt;# can use the CA class above from other programs with a &lt;br /&gt;# require.&lt;br /&gt;if __FILE__ == $0&lt;br /&gt;&lt;br /&gt;# Set up the command line options&lt;br /&gt;opts = GetoptLong.new(&lt;br /&gt;    ["--max_generations", "-g", GetoptLong::REQUIRED_ARGUMENT],&lt;br /&gt;    ["--rule", "-r", GetoptLong::REQUIRED_ARGUMENT],&lt;br /&gt;    ["--num_cells", "-c", GetoptLong::REQUIRED_ARGUMENT],&lt;br /&gt;    ["--random_init", "-R", GetoptLong::NO_ARGUMENT],&lt;br /&gt;    ["--verbose", "-v", GetoptLong::NO_ARGUMENT],&lt;br /&gt;    ["--help", "-h", GetoptLong::NO_ARGUMENT]&lt;br /&gt;    )&lt;br /&gt;&lt;br /&gt;# Set the default values for the options&lt;br /&gt;max_generations = 100&lt;br /&gt;rule = 100&lt;br /&gt;num_cells = 31&lt;br /&gt;random_init = false&lt;br /&gt;&lt;br /&gt;$verbose = false&lt;br /&gt;&lt;br /&gt;# Parse the command line options. If we find one we don't recognize&lt;br /&gt;# an exception will be thrown and we'll rescue with a RDoc::usage&lt;br /&gt;begin&lt;br /&gt;    opts.each do | opt, arg|&lt;br /&gt;        case opt&lt;br /&gt;        when "--max_generations"&lt;br /&gt;            max_generations = arg.to_i&lt;br /&gt;        when "--rule"&lt;br /&gt;            rule = arg.to_i&lt;br /&gt;        when "--num_cells"&lt;br /&gt;            num_cells = arg.to_i&lt;br /&gt;        when "--random_init"&lt;br /&gt;            random_init = true&lt;br /&gt;        when "--verbose"&lt;br /&gt;            $verbose = true&lt;br /&gt;        when "--help"&lt;br /&gt;            usage&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;rescue&lt;br /&gt;    usage&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;puts "max_generations = #{max_generations} rule = #{rule} num_cells = #{num_cells}" if $verbose&lt;br /&gt;&lt;br /&gt;# Create a new cellular automata using the correct&lt;br /&gt;# number of cells (width) and rule.&lt;br /&gt;ca = CA.new(num_cells, rule, random_init)&lt;br /&gt;&lt;br /&gt;1.upto(max_generations) do |g|&lt;br /&gt;    puts "#{ca} Generation: #{g}"&lt;br /&gt;    ca.next&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We start out with a comment header (leftover from the days when rdoc/usage would work. We'll skip over the CA class itself for now and then we see the line &lt;code&gt;if __FILE__ == $0&lt;br /&gt;&lt;/code&gt;. This lets ruby know that we shouldn't run this if it's not the "main" routine as $0 will be the file that is run on the command line. Next, we set up our command line options for the number of generations to run, which rule (we'll discuss this more later), the number of cells in our automata, and whether to initialize with a single cell in the middle (the default) or to initialize the automata with a random mix of black and white cells. Then we process the command line options, create a new CA using the various options, and then run the CA up to the appropriate number of generations. We should get a long number of lines with a mix of "B" and "W" characters followed by the generation. Obviously, for doing any real work, we'd like a better display, but this will let us get started.&lt;br /&gt;&lt;br /&gt;Let's go back and look at the CA class now. We start out with our &lt;code&gt;initialize&lt;/code&gt; method which takes a few of the command line options and creates the CA with them. We create the CA with two extra cells, one on each end, that are always "W". This allows us to have the correct number of cells in the CA. We then initialize the current generation with either the single black cell in the middle or a mix of black and white cells. Finally, we initialize the &lt;code&gt;next_cell&lt;/code&gt; array. This array contains, based on the rule that's passed in, the new value of the cell based on the cell's current value and the value of its neighbors. It's calculated from the rule based on the rule's binary representation where if the rule has a one in a particular bit position, we will put a "B" in the corresponding position in the &lt;code&gt;next_cell&lt;/code&gt; array otherwise a "W". For example let's take a look at rule say Rule 30. Its binary representation is "00011110" and our &lt;code&gt;next_cell&lt;/code&gt; array will be "WWWBBBBW". We'll use this array to as we check the cell and its neighbors to decide what should be in that cell in the next generation. For "WWW" we'll use &lt;code&gt;next_cell[0]&lt;/code&gt;, for "WWB", we'll use &lt;code&gt;next_cell[1]&lt;/code&gt; and so on up to "BBB" where we'll use &lt;code&gt;next_cell[7]&lt;/code&gt;. This leads us back to the &lt;code&gt;next&lt;/code&gt; method which is the heart of the program. We create a &lt;code&gt;next_gen&lt;/code&gt; array first that is of size &lt;code&gt;total_cells&lt;/code&gt; initialized with all "W" (recall the ends are going to always be white). Then we loop through all the cells, skipping the first and last, and using our &lt;code&gt;next_cell&lt;/code&gt; array and the &lt;code&gt;current_gen&lt;/code&gt; array to generate the &lt;code&gt;next_gen&lt;/code&gt; array. The case statement with the &lt;code&gt;join&lt;/code&gt; will create a string based on the cell and its neighbors that we'll use to decide which of the &lt;code&gt;next_cell&lt;/code&gt; values to use. Finally, we'll assign &lt;code&gt;current_gen&lt;/code&gt; to &lt;code&gt;next_gen&lt;/code&gt; and return. The last method &lt;code&gt;to_s&lt;/code&gt; just returns a string version of the &lt;code&gt;current_gen&lt;/code&gt; for display purposes.&lt;br /&gt;&lt;br /&gt;As always, let me know if you have questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-6768761067052998742?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/6768761067052998742/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/09/one-dimensional-cellular-automata.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/6768761067052998742'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/6768761067052998742'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/09/one-dimensional-cellular-automata.html' title='One Dimensional Cellular Automata'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-6593851188219824908</id><published>2010-09-21T18:01:00.001-07:00</published><updated>2010-09-21T18:18:18.376-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='praxis'/><title type='text'>Kaprekar Numbers</title><content type='html'>I saw this one over on &lt;a href="http://programmingpraxis.com/2010/09/21/kaprekar-numbers/"&gt;Programming Praxis&lt;/a&gt; and thought that it would be a good ruby problem and probably something that I might use as an interview question for a programmer. Once again, like our post on &lt;a href="http://steamcode.blogspot.com/2010/07/happy-numbers.html"&gt;Happy Numbers&lt;/a&gt;, it has both math and string work plus it can be done relatively quickly. Here's the introduction from Programming Praxis ...&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Wolfram’s MathWorld describes Kaprekar numbers like this:&lt;br /&gt;&lt;br /&gt;    Consider an n-digit number k. Square it and add the right n digits to the left n or n-1 digits. If the resultant sum is k, then k is called a Kaprekar number. For example, 9 is a Kaprekar number since 92 = 81 and 8 + 1 = 9 and 297 is a Kaprekar number since 2972 = 88209 and 88 + 209 = 297.&lt;br /&gt;&lt;br /&gt;Your task is to write a function that identifies Kaprekar numbers and to determine the Kaprekar numbers less than a thousand. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;And here's the ruby code for this ...&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;# Wolfram’s MathWorld describes Kaprekar numbers like this:&lt;br /&gt;# &lt;br /&gt;#     Consider an n-digit number k. Square it and add the right n digits to the&lt;br /&gt;#     left n or n-1 digits. If the resultant sum is k, then k is called a&lt;br /&gt;#     Kaprekar number. For example, 9 is a Kaprekar number since 92 = 81 and 8&lt;br /&gt;#     + 1 = 9 and 297 is a Kaprekar number since 2972 = 88209 and 88 + 209 =&lt;br /&gt;#     297.&lt;br /&gt;# &lt;br /&gt;# Your task is to write a function that identifies Kaprekar numbers and to&lt;br /&gt;# determine the Kaprekar numbers less than a thousand. When you are finished,&lt;br /&gt;# you are welcome to read or run a suggested solution, or to post your own&lt;br /&gt;# solution or discuss the exercise in the comments below.&lt;br /&gt;&lt;br /&gt;def kaprekar?(k)&lt;br /&gt;    # Get the number of digits in k.&lt;br /&gt;    n = k.to_s.length&lt;br /&gt;&lt;br /&gt;    # Get the number squared and convert it to a string.&lt;br /&gt;    k_sqr_str = (k**2).to_s&lt;br /&gt;&lt;br /&gt;    # Get the right side of n digits. Here we use the ruby array function that&lt;br /&gt;    # starts from the end of the array and counts back n digits and then grabs&lt;br /&gt;    # n digits.&lt;br /&gt;    right = k_sqr_str[-n, n]&lt;br /&gt;&lt;br /&gt;    # Grab the remaining n or n-1 digits.&lt;br /&gt;    left = k_sqr_str[0, k_sqr_str.length-right.length]&lt;br /&gt;&lt;br /&gt;    # Sum the left and right sides.&lt;br /&gt;    sum = left.to_i + right.to_i&lt;br /&gt;&lt;br /&gt;    # Check if the sum that we just computed is the same&lt;br /&gt;    # as k that we passed in. If so return true for a kaprekar&lt;br /&gt;    # number otherwise false.&lt;br /&gt;    sum == k ? true : false&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Find the kaprekar numbers up to 1000 and print &lt;br /&gt;# the ones we find.&lt;br /&gt;1.upto(1000) do |k|&lt;br /&gt;    puts "#{k} is a kaprekar number" if kaprekar?(k)&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This is a relatively "naive" implementation and you can see that the &lt;a href="http://programmingpraxis.com/2010/09/21/kaprekar-numbers/2/"&gt;implementations&lt;/a&gt; given on the Praxis site are a bit more interesting. This though is something like what I'd expect someone to come up with as part of an interview. Also, I managed to misspell Kaprekar when I did this over at Praxis and this contains the correct spelling.&lt;br /&gt;&lt;br /&gt;Let me know if you have questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-6593851188219824908?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/6593851188219824908/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/09/kaprekar-numbers.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/6593851188219824908'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/6593851188219824908'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/09/kaprekar-numbers.html' title='Kaprekar Numbers'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-8818521664971283085</id><published>2010-09-13T17:25:00.000-07:00</published><updated>2010-09-13T17:45:14.788-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='ramaze'/><category scheme='http://www.blogger.com/atom/ns#' term='github'/><category scheme='http://www.blogger.com/atom/ns#' term='heroku'/><category scheme='http://www.blogger.com/atom/ns#' term='sequel'/><title type='text'>Snippet Highlighting with Ramaze and Sequel</title><content type='html'>A few days ago I saw this &lt;a href="http://blog.zerosum.org/2008/7/2/clone-pastie-with-sinatra-datamapper-redux"&gt;post&lt;/a&gt; on creating a pastie "clone" using Sinatra and Datamapper. I thought that it might be cool to try something similar in Ramaze and Sequel. It actually ended up being pretty easy (and similar to the other post (especially since I "stole" most of his CSS, etc.)), so I thought I'd share it here. If you've read much of this blog, then you should be pretty familiar with most of this, so I won't go through all of the code here but just hit the highlights. Here's the controller, controller/main.rb: &lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;# controllers/main.rb&lt;br /&gt;#&lt;br /&gt;# The MainController has methods for index/main (to create a new snippet) and show (to show&lt;br /&gt;# an existing snippet).&lt;br /&gt;&lt;br /&gt;# Require syntaxi for syntax highlighting.&lt;br /&gt;require 'syntaxi'&lt;br /&gt;Syntaxi::line_number_method = 'floating'&lt;br /&gt;Syntaxi::wrap_enabled = false&lt;br /&gt;Syntaxi::wrap_at_column = 120&lt;br /&gt;&lt;br /&gt;class MainController &lt; Controller&lt;br /&gt;&lt;br /&gt;    # The main/index page that shows a text area where we can put in a &lt;br /&gt;    # title and a snippet. We'll grab the title and snippet text, create a new&lt;br /&gt;    # snippet, and then go to the snippet display page to see it.&lt;br /&gt;    def index&lt;br /&gt;        @title = "Snippet!"&lt;br /&gt;&lt;br /&gt;        # We've got a post, so grab the title and the snippet and then create&lt;br /&gt;        # a new Snippet with them and the current time. We'll then go ahead and &lt;br /&gt;        # redirect to the show method with the id that we get from the snippet.&lt;br /&gt;        if  request.post?&lt;br /&gt;            title = request[:title]&lt;br /&gt;            snippet_text = request[:snippet]&lt;br /&gt;            snippet = Snippet.create(:title =&gt; title, :body =&gt; snippet_text, :created_at =&gt; Time.now)&lt;br /&gt;            redirect rs(:show, snippet.id)&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # The show page that shows an existing snippet. It takes the id of an existing &lt;br /&gt;    # snippet and if it exists shows it nicely highlighted. If it doesn't exist, we'll&lt;br /&gt;    # just go back to the main page after setting the flash.&lt;br /&gt;    def show(id)&lt;br /&gt;        @title = "Show Snippet!"&lt;br /&gt;&lt;br /&gt;        # Find the snippet if it exists&lt;br /&gt;        @snippet = Snippet[id]&lt;br /&gt;&lt;br /&gt;        if @snippet != nil&lt;br /&gt;            # Get some text we can use to substitute for the "[/code]" text so that it doesn't&lt;br /&gt;            # mess up Syntaxi.&lt;br /&gt;            replacer = Time.now.strftime('[code-%d]')&lt;br /&gt;&lt;br /&gt;            # Do the syntax highlighting of the text with Syntaxi after we've done our&lt;br /&gt;            # substitution.&lt;br /&gt;            @snippet_highlight = Syntaxi.new("[code lang='ruby']#{@snippet.body.gsub('[/code]', replacer)}[/code]").process&lt;br /&gt;&lt;br /&gt;            # Substitute the '[/code]' back in for our replacement text.&lt;br /&gt;            @snippet_highlight = "#{@snippet_highlight.gsub(replacer, '[/code]')}"&lt;br /&gt;        else&lt;br /&gt;            # The snippet doesn't exist, so set a message and just redirect&lt;br /&gt;            # to the main/index page.&lt;br /&gt;            flash[:message] = "Snippet #{id} not found."&lt;br /&gt;            redirect rs :index&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We start out requiring &lt;a href="http://syntaxi.rubyforge.org/"&gt;syntaxi&lt;/a&gt; which can be used with a &lt;kbd&gt;sudo gem install syntaxi&lt;/kbd&gt;. The next three lines set a few variables which can be read about at the link. The &lt;code&gt;index&lt;/code&gt; method will all the user to put in a snippet in a text area and then we'll create the Snippet (see &lt;code&gt;model/models.rb&lt;/code&gt; and &lt;code&gt;dbMigration/001_RamazeSnippet.rb&lt;/code&gt; for the information in this table/model). After we've created the new snippet, we'll redirect to the &lt;code&gt;show&lt;/code&gt; method with the &lt;code&gt;id&lt;/code&gt; of the new snippet. &lt;br /&gt;&lt;br /&gt;The &lt;code&gt;show&lt;/code&gt; method takes the &lt;code&gt;id&lt;/code&gt; of the snippet and then displays the syntax highlighted version of it. It grabs the snippet from the database and if the snippet is not nil, it creates a "replacer" for &lt;code&gt;[/code]&lt;/code&gt; which signals syntaxi to quit highlighting. We then substitute this replacer for the a [/code] and process the snippet. When this is complete, we resubstitute the [/code] for replacer and save it so the view can get to it. The &lt;code&gt;view/show.xhtml&lt;/code&gt; is pretty simple and just displays the title, the highlighted snippet, and the creation date. &lt;br /&gt;&lt;br /&gt;Like I said, not too much other than the syntax highlighting that we haven't seen before here. You can check all of the code on &lt;a href="http://github.com/slabounty/RamazeSnippets"&gt;GitHub&lt;/a&gt; and run the code on &lt;a href="http://simple-galaxy-31.heroku.com/"&gt;Heroku&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Let me know if you have questions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-8818521664971283085?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/8818521664971283085/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/09/snippet-highlighting-with-ramaze-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/8818521664971283085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/8818521664971283085'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/09/snippet-highlighting-with-ramaze-and.html' title='Snippet Highlighting with Ramaze and Sequel'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-7224988876875422883</id><published>2010-09-08T05:45:00.001-07:00</published><updated>2010-09-08T06:07:23.071-07:00</updated><title type='text'>Sequel Models one_to_one Associations</title><content type='html'>We looked in the past at both &lt;a href="http://steamcode.blogspot.com/2009/03/sequel-models-manytoone-onetomany.html"&gt;one to many/many to one&lt;/a&gt; and &lt;a href="http://steamcode.blogspot.com/2009/03/sequel-models-manytomany-manytomany.html"&gt;many to many/many to many&lt;/a&gt; associations, but we haven't looked at one to one associations yet. I was looking at this for addresses where a couple of different classes would use them so I wouldn't want to embed them in each table. The documentation &lt;a href="http://sequel.rubyforge.org/rdoc/files/doc/association_basics_rdoc.html"&gt;here&lt;/a&gt; is good, but I needed a bit of help (and straightening out) from Jeremy Evans and the Sequel group, so I thought this might be a good topic. Here's the code we'll be using ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'sequel'&lt;br /&gt;&lt;br /&gt;# Create an in-memory database.&lt;br /&gt;DB = Sequel.sqlite &lt;br /&gt;&lt;br /&gt;# Create a businesses table with a name an address.&lt;br /&gt;DB.create_table :businesses do &lt;br /&gt;    primary_key :id&lt;br /&gt;    String :name, :text=&gt;true, :unique=&gt;true&lt;br /&gt;    foreign_key :address_id&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Create a people table with a name and an address.&lt;br /&gt;DB.create_table :people do &lt;br /&gt;    primary_key :id&lt;br /&gt;    String :name, :text=&gt;true, :unique=&gt;true&lt;br /&gt;    foreign_key :address_id&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Create a table of addresses that can be used by both people&lt;br /&gt;# and businesses. This is just an example and real addresses would&lt;br /&gt;# be done with street addresses, cities, states, countries, etc.&lt;br /&gt;DB.create_table :addresses do&lt;br /&gt;    primary_key :id&lt;br /&gt;    String :address&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# From the documentation ...&lt;br /&gt;# Differences Between many_to_one and one_to_one&lt;br /&gt;# If you want to setup a 1-1 relationship between two models, you have to use&lt;br /&gt;# many_to_one in one model, and one_to_one in the other model. How do you know&lt;br /&gt;# which to use in which model?  The simplest way to remember is that the model&lt;br /&gt;# whose table has the foreign key uses many_to_one, and the other model uses&lt;br /&gt;# one_to_one:  &lt;br /&gt;#&lt;br /&gt;# For our case, the people and businesses have the foreign key and use the many_to_one and&lt;br /&gt;# addresses will use one_to_one for both.&lt;br /&gt;&lt;br /&gt;# The business model backed by the businesses table. Note the&lt;br /&gt;# many to one for addresses.&lt;br /&gt;class Business &lt; Sequel::Model&lt;br /&gt;    many_to_one :address # Note this is singular.&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# The person model backed by the people table. Note the&lt;br /&gt;# many to one for addresses.&lt;br /&gt;class Person &lt; Sequel::Model&lt;br /&gt;    many_to_one :address # Note this is singular.&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# The address model backed by the addresses table. Note the&lt;br /&gt;# one to one for both business and person.&lt;br /&gt;class Address &lt; Sequel::Model&lt;br /&gt;    one_to_one :business # Note this is singular.&lt;br /&gt;    one_to_one :person # Note this is singular.&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# Create a new business and person.&lt;br /&gt;business = Business.create(:name =&gt; "The Business")&lt;br /&gt;person = Person.create(:name =&gt; "Bob")&lt;br /&gt;&lt;br /&gt;# Create new addresses for each of the above.&lt;br /&gt;address_1 = Address.create(:address =&gt; "123 W. Lane, Anytown, CA 91110")&lt;br /&gt;address_2 = Address.create(:address =&gt; "124 W. Lane, Anytown, CA 91110")&lt;br /&gt;&lt;br /&gt;# Add the addresses for each of the above. Note that these use setter methods and not the &lt;br /&gt;# add_ that you would see for many_to_one and many_to_many relationships.&lt;br /&gt;business.address = address_1&lt;br /&gt;person.address = address_2&lt;br /&gt;&lt;br /&gt;# Print them out to show we got them correct.&lt;br /&gt;puts "Business: #{business.name} at #{business.address.address}"&lt;br /&gt;puts "Person: #{person.name} at #{person.address.address}"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We start out creating the database and the tables we'll use. The businesses and people tables both contain foreign keys to the addresses table and a name (in real life, these would be much more complex). The addresses table simply contains the address. Next we have the models that represent the tables. Be sure to read the comments that come directly from the documentation and that will help your understanding. Basically, in the table that has the foreign key (in this case businesses and people), the corresponding models will have a many_to_one association with the other model (in this case addresses). Note that both the many_to_one and one_to_one associations should take a singular identifier. After this, we'll create a business and a person, a couple of addresses, and then link them together. Here, we need to use the setter method (&lt;code&gt;.address&lt;/code&gt; and not &lt;code&gt;add_address()&lt;/code&gt; as I first tried (once again, it's in the documentation, but I obviously missed it)). Finally, just to make sure we print everything out.&lt;br /&gt;&lt;br /&gt;Let me know if you have questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-7224988876875422883?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/7224988876875422883/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/09/sequel-models-onetoone-associations.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/7224988876875422883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/7224988876875422883'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/09/sequel-models-onetoone-associations.html' title='Sequel Models one_to_one Associations'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-3960822999424816567</id><published>2010-09-04T19:55:00.000-07:00</published><updated>2010-09-04T20:30:01.649-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='ramaze'/><title type='text'>Ramaze and Partial Rendering</title><content type='html'>Over on the Ramaze list, we had quite a &lt;a href="http://groups.google.com/group/ramaze/browse_thread/thread/5af436f21f7cdf03/f5cdb27d364086bd?show_docid=f5cdb27d364086bd"&gt;conversation&lt;/a&gt; going on about the MVC paradigm. In response to that, I ended up doing some research on partial rendering (rendering a piece of a view using another view). I ended up writing some code and it's available on GitHub &lt;a href="http://github.com/slabounty/RenderPartial"&gt;here&lt;/a&gt;. The original code was generated using &lt;code&gt;ramaze create RenderPartial&lt;/code&gt; and then modified to its present form.&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;class MainController &lt; Controller&lt;br /&gt;  # the index action is called automatically when no other action is specified&lt;br /&gt;  def index&lt;br /&gt;    @title = "Welcome to Ramaze!"&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def page_1&lt;br /&gt;    @title = "Page 1"&lt;br /&gt;    @colors = ["blue", "brown", "hazel"]&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def page_2&lt;br /&gt;    @title = "Page 2"&lt;br /&gt;    @colors = ["blue", "brown", "hazel"]&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The colors are predefined here in the controller, but in a real example, you would normally get them from a model probably from a database. The use of colors itself comes from the question in the email trail about dolls and the different color of eyes they could be. There's nothing particularly complex in here, we've seen it quite a few times, there's an index method and then two additional page methods where the latter are pretty much exactly the same. &lt;br /&gt;&lt;br /&gt;The views are where the interesting part is though. Here's the page 1 view contained in view/page_1.xhtml&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;p&amp;gt;&lt;br /&gt;    Page 1&lt;br /&gt;    #{ render_partial :color }&lt;br /&gt;&amp;lt;/p&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;and the page 2 view, view/page_2.xhtml&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;p&amp;gt;&lt;br /&gt;    Page 2&lt;br /&gt;    #{ render_partial :color }&lt;br /&gt;&amp;lt;/p&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;and finally, the view/color.xhtml, the partial that we render:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;ul&amp;gt;&lt;br /&gt;    &amp;lt;?r @colors.each do | color | ?&amp;gt;&lt;br /&gt;        &amp;lt;li&amp;gt; #{color} &amp;lt;/li&amp;gt;&lt;br /&gt;    &amp;lt;?r end ?&amp;gt;&lt;br /&gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Here, we simply take the colors that were defined in the controller methods and use them to generate a list (obviously, we could have done whatever we wanted with them). The lines in the two page views &lt;code&gt;#{ render_partial :color }&lt;/code&gt; tells the view to fill in this spot with the view/color.xhtml code. Although, we haven't here, you can also pass parameters to the partial. Here's a &lt;a href="http://blog.xambr.com/2009/11/26/ramaze-partials-with-etanni/"&gt;post&lt;/a&gt; that shows how to use that feature.&lt;br /&gt;&lt;br /&gt;Hopefully, this is all pretty clear, but if not, as always, feel free to leave questions in the comments section.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-3960822999424816567?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/3960822999424816567/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/09/ramaze-and-partial-rendering.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/3960822999424816567'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/3960822999424816567'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/09/ramaze-and-partial-rendering.html' title='Ramaze and Partial Rendering'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-2287267300782470032</id><published>2010-09-02T17:08:00.000-07:00</published><updated>2010-09-02T19:11:35.725-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='ramaze'/><category scheme='http://www.blogger.com/atom/ns#' term='heroku'/><category scheme='http://www.blogger.com/atom/ns#' term='sequel'/><title type='text'>Sequel and Heroku</title><content type='html'>Well, this turned out to be a bit harder than I expected, but with quite a bit of help from the Sequel, Ramaze, and Heroku lists, I got it worked out. The source code for this particular exercise is &lt;a href="http://github.com/slabounty/SimpleHerokuSequel"&gt;here&lt;/a&gt;. I'm only going to show a couple of files here as everything else you've already seen. First, here's how to do the migration in a rakefile ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;namespace :db do&lt;br /&gt;    require 'rubygems'&lt;br /&gt;    require 'sequel'&lt;br /&gt;    Sequel.extension :migration&lt;br /&gt;&lt;br /&gt;    task :migrate do&lt;br /&gt;        m = Sequel::Migrator&lt;br /&gt;        db = Sequel.connect(ENV['DATABASE_URL'] || 'sqlite://library.sqlite')&lt;br /&gt;        dir = "dbMigration"&lt;br /&gt;&lt;br /&gt;        target = ENV['TARGET'] ? ENV['TARGET'].to_i : nil&lt;br /&gt;        current = ENV['CURRENT'] ? ENV['CURRENT'].to_i : nil&lt;br /&gt;&lt;br /&gt;        m.run(db, dir, :target =&gt; target, :current =&gt; current)&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We create a sequel migrator and connect to the database. The database connection line contains two parts. The first side is if there's an environment variable named &lt;code&gt;DATABASE_URL&lt;/code&gt; then we'll use that to connect to the database. This is an environment variable set by Heroku. If this isn't set, then we'll go ahead and connect to a sqlite database, &lt;code&gt;library.sqlite&lt;/code&gt;. We use the &lt;code&gt;Sequel.connect command rather than &lt;code&gt;Sequel.sqlite&lt;/code&gt; as we don't know which type of database we're going to be using. On Heroku, it will be PostgreSQL and locally, we use sqlite. Next up, we set the directory where we'll keep our migrations, in this case, dbMigration which is my standard. After that, there's two lines used for telling sequel which version we're going to, &lt;code&gt;target&lt;/code&gt;, and starting from, &lt;code&gt;current&lt;/code&gt;. Finally, we run the migrator with the database, directory, target and current. The final two are part of a hashtable that's used by this migrator. You could also use &lt;code&gt;m.apply&lt;/code&gt; where the first two parameters are the same and then pass the target and current as integers, but the migrator code seems to imply that the &lt;code&gt;run&lt;/code&gt; version is preferred. To run this locally, simply do a &lt;code&gt;rake db:migrate&lt;/code&gt; and it should migrate to the latest version. To move to a different version you can run &lt;code&gt;rake TARGET=0 db:migrate&lt;/code&gt; to remove everything from the database. If you just want to move to the latest version, don't put a target or current in, they'll be nil, and it should just migrate to the latest. Now, to run it on Heroku and migrate the database there simply add heroku in front of the command as in &lt;code&gt;heroku rake db:migrate&lt;/code&gt; after you've pushed all the code up to Heroku with a &lt;code&gt;git push heroku master&lt;/code&gt; as we saw in the &lt;a href="http://steamcode.blogspot.com/2010/08/ramaze-github-and-heroku.html"&gt;last post&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I haven't talked about rake before, so I should probably give a little background for it. It's a ruby version of the Unix make. It has tasks and commands to do them. The homepage for it is &lt;a href="http://rake.rubyforge.org/"&gt;here&lt;/a&gt; and here is a nice &lt;a href="http://jasonseifer.com/2010/04/06/rake-tutorial"&gt;article&lt;/a&gt; on using it.&lt;br /&gt;&lt;br /&gt;OK, now let's take a look at our model file model/models.rb.&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;# The database should have been set up using the database migrations in&lt;br /&gt;# the dbMigration directory. &lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'ramaze'&lt;br /&gt;require 'sequel'&lt;br /&gt;&lt;br /&gt;# Open the library's database. This must be done before we access the models&lt;br /&gt;# that use it.&lt;br /&gt;Sequel.connect(ENV['DATABASE_URL'] || 'sqlite://library.sqlite')&lt;br /&gt;&lt;br /&gt;#&lt;br /&gt;# This is the model for the authors and is backed by the :authors table in the&lt;br /&gt;# database. &lt;br /&gt;#&lt;br /&gt;# Create the Author model. &lt;br /&gt;class Author &lt; Sequel::Model &lt;br /&gt;    many_to_many :books&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#&lt;br /&gt;# This is the model for the book and is backed by the :book table in the&lt;br /&gt;# database. &lt;br /&gt;#&lt;br /&gt;# Create the Book model. &lt;br /&gt;class Book &lt; Sequel::Model &lt;br /&gt;    many_to_many :authors&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This looks exactly like our previous models with a couple of exceptions. Here, we've moved our database connection into here from start.rb. It probably makes more sense here and keeps all of our Sequel code in one place (I got this idea from the Ramaze generated code). The connection itself looks surprisingly like our connection that was used in the rakefile. We end up using either a DATABASE_URL environment variable (supplied by Heroku) or the sqlite library.sqlite. After that, there are a couple of models that are in the database that we can use. The tables for the database and some data are created in the dbMigration/001_LibraryMigration.rb file.&lt;br /&gt;&lt;br /&gt;You can see the end result of all of this &lt;a href="http://stark-ocean-49.heroku.com/"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;All of the code for this is up on &lt;a href="http://github.com/slabounty/SimpleHerokuSequel"&gt;github&lt;/a&gt; and as always, if you have questions, leave them in the comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-2287267300782470032?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/2287267300782470032/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/09/sequel-and-heroku.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/2287267300782470032'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/2287267300782470032'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/09/sequel-and-heroku.html' title='Sequel and Heroku'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-8959108880013168144</id><published>2010-08-13T12:49:00.000-07:00</published><updated>2010-08-13T14:16:08.064-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='ramaze'/><category scheme='http://www.blogger.com/atom/ns#' term='github'/><category scheme='http://www.blogger.com/atom/ns#' term='heroku'/><title type='text'>Ramaze, GitHub, and Heroku</title><content type='html'>I first heard of Heroku from, I believe, a &lt;a href="http://oppugn.us/posts/1271781380.html"&gt;rant by Zed&lt;/a&gt; (if you're offended by profanity, this is probably not for you). It looked pretty interesting and so I decided to give it a try. This was actually a bit more involved than I thought, not hard, but for the first time you have more than a few steps to get through. What I'm going to show is how to a) get Git running, set up GitHub, create the Ramaze application, load it to GitHub, and finally load it to Heroku. Strictly speaking, you don't need GitHub to get the app running on Heroku, but I'm going to start putting some of my posts up there and so I thought I might as well show it too.&lt;br /&gt;&lt;br /&gt;Let's start with getting git up and running. On my Ubuntu system, simply type &lt;code&gt;sudo apt-get install git-core&lt;/code&gt;. After that type &lt;code&gt;git --version&lt;/code&gt; (my shows git version 1.7.2.1) to make sure everything installed correctly. &lt;br /&gt;&lt;br /&gt;Next, let's set up a GitHub account. Go to http://github.com/plans and create yourself a free account (or move up to a paid account if you want). Next, you're going to need to generate a SSH key which will be used by both GitHub and Heroku. You can go to http://help.github.com/linux-key-setup/ if you're running Linux or http://help.github.com/windows-key-setup/ if you're on Windows (probably similar for you Mac users). Follow the directions and you should now have access to your GitHub account. Here's the command on Linux &lt;kbd&gt;ssh-keygen -t rsa -C "yourusername@youremailprovider.com"&lt;/kbd&gt; to create the keys.&lt;br /&gt;&lt;br /&gt;Now you'll want to configure git with a few your user name and email. The commands for this are:&lt;br /&gt;&lt;kbd&gt;&lt;br /&gt;Configure git with user and email&lt;br /&gt;git config --global user.name "yourusername"&lt;br /&gt;git config --global user.email "yourusername@youremailprovider.com"&lt;br /&gt;&lt;/kbd&gt;&lt;br /&gt;&lt;br /&gt;We're going to put our code up on GitHub first, so let's create an application first. Let's just use the default ramaze application and upload that (not exactly what I've done, but close enough). First go to your Dashboard on GitHub and create a new repository and call it "foo". This is where the application will live on GitHub. Now, run &lt;kbd&gt;ramaze create foo&lt;/kbd&gt; to create an application called foo in the current directory. Then &lt;code&gt;cd foo&lt;/code&gt; and we'll get the application ready to upload. We do need to add one file for Heroku and that's a .gems file. This file will contain a list of all the gems used by your application. In this case, the file should have the single line &lt;code&gt;ramaze&lt;/code&gt;. If you're using Sequel say, the file would also contain a line &lt;code&gt;sequel&lt;/code&gt;. In general it should have a line for each gem and the gem name should be what you would do by a &lt;kbd&gt;sudo gem install xxx&lt;/kbd&gt;. Here we're going to run some git commands. I'm just learning git myself, but here's a &lt;a href="http://book.git-scm.com/"&gt;book&lt;/a&gt; that should help you get started. The maintainer of this book, Scott Chacon, also has a dead tree book called &lt;a href="http://www.amazon.com/Pro-Git-Scott-Chacon/dp/1430218339/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1281731231&amp;sr=8-1"&gt;"Pro Git"&lt;/a&gt; that is also quite good. So assuming we're in the foo directory already, type &lt;code&gt;git init&lt;/code&gt;. This will get the application ready for git. Next we need to add the files with a &lt;kbd&gt;git add .&lt;/kbd&gt; to add all the files in this directory and all of it's subdirectories into the repository. Now we need to do a "commit" of the files with a &lt;kbd&gt;git commit -m 'first commit for foo'&lt;/kbd&gt;. Next, we'll tell git where we're going to save this with a &lt;kbd&gt;git remote add origin git@github.com:slabounty/foo.git&lt;/kbd&gt; and finally, we'll push it to GitHub with &lt;kbd&gt;git push origin master&lt;/kbd&gt;. You should now be able to go to your GitHub dashboard, see this repository and look at the files in there. Also, since this is a "public" repository, others will also be able to view and download these files, so don't use this for proprietary code unless you're using a non-free plan.&lt;br /&gt;&lt;br /&gt;OK, let's move on to getting this up and running on Heroku. Start by creating an account on Heroku at http://heroku.com/. Once you have an account, you can &lt;kbd&gt;sudo gem install heroku&lt;/kbd&gt; to get the Heroku gem. Next we'll do a &lt;kbd&gt;heroku keys:add&lt;/kbd&gt; (this uses the same keys we created above to allow us to upload our files to Heroku. The one thing to make sure of is that you've created the .gems file as described above. Start with these two commands &lt;br /&gt;&lt;code&gt;&lt;br /&gt;git remote add origin git@github.com:slabounty/SimpleHeroku.git &lt;br /&gt;git push origin master&lt;br /&gt;&lt;/code&gt; &lt;br /&gt;&lt;br /&gt;Next we'll create an application on Heroku (we don't need to go to the website to do it, we'll just use the gem) with &lt;kbd&gt;heroku create&lt;/kbd&gt; (creates an application on Heroku and let's you know where it's at. In my case it was http://smooth-stone-75.heroku.com) and finally we push it up to Heroku with a &lt;kbd&gt;git push heroku master&lt;/kbd&gt;. &lt;br /&gt;&lt;br /&gt;You can then point your browser where ever the application was created at, for example the web site above and you should see it running there. What is there is not the base Ramaze application that would be created but another simple one that I did. You should be able to see the code on &lt;a href="http://github.com/slabounty/SimpleHeroku"&gt;GitHub&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;There quite a bit of information here and if any of it is unclear, let me know.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-8959108880013168144?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/8959108880013168144/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/08/ramaze-github-and-heroku.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/8959108880013168144'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/8959108880013168144'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/08/ramaze-github-and-heroku.html' title='Ramaze, GitHub, and Heroku'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-4727929467088041950</id><published>2010-07-28T05:24:00.000-07:00</published><updated>2010-07-28T05:50:20.759-07:00</updated><title type='text'>Sequel Trees Redux</title><content type='html'>In a previous &lt;a href="http://steamcode.blogspot.com/2010/07/sequel-trees.html"&gt;post&lt;/a&gt;, I discussed Sequel Trees. I had a question from that post on viewing the tree in "tree order". There are a couple of ways to do this one is recursive, which we'll use here. The other, from Jeremy Evans, is to use the rcte_tree plugin and a database that supports it. The latter is completely beyond me, so we'll go with the former.&lt;br /&gt;&lt;br /&gt;Here, we're going to start out the same way we did last time by building up a database for a company. We've added a few things though. First, we have a title for each of the employees and second, we've added another top level employee (President) and a few additional employees under him. Once we have the structure in place, we get the roots (Presidents) of the model using &lt;code&gt;Employee.roots&lt;/code&gt; and then for each of those employees, we loop calling the &lt;code&gt;put_management_chain&lt;/code&gt; function. &lt;code&gt;put_management_chain&lt;/code&gt; will print the title and name of the employee and then call itself recursively with each of the employees direct reports, &lt;code&gt;children&lt;/code&gt;. One nice thing to note here is the level parameter to the function which is used in the &lt;code&gt;puts&lt;/code&gt; to give us the proper indentation by taking three spaces and multiplying it by the indentation level.&lt;br /&gt;&lt;br /&gt;Here's the code for the full program:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'sequel'&lt;br /&gt;&lt;br /&gt;# Create an in-memory database&lt;br /&gt;DB = Sequel.sqlite &lt;br /&gt;&lt;br /&gt;# Create the employees table with a name and parent_id.&lt;br /&gt;DB.create_table :employees do &lt;br /&gt;    primary_key :id&lt;br /&gt;    foreign_key :parent_id, :employees&lt;br /&gt;    String :name, :text=&gt;true, :unique=&gt;true&lt;br /&gt;    String :title, :text=&gt;true&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Create the Employee model. &lt;br /&gt;class Employee &lt; Sequel::Model&lt;br /&gt;    plugin :tree # Uses :parent_id field for parent&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Puts out the management chain for an employee recursively. The level is used&lt;br /&gt;# to print out some spaces in front of the name to show the relationship.&lt;br /&gt;def put_management_chain(e, level)&lt;br /&gt;    puts "#{"   "*level}#{e.title}: #{e.name}"&lt;br /&gt;    direct_reports = e.children&lt;br /&gt;    direct_reports.each do | d |&lt;br /&gt;        put_management_chain(d, level+1)&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Create a top level employee, Alice.&lt;br /&gt;alice = Employee.create(:name =&gt; "Alice", :title =&gt; "President")&lt;br /&gt;&lt;br /&gt;# Create Alice's direct reports.&lt;br /&gt;bob = Employee.create(:name =&gt; "Bob", :title =&gt; "Vice President", :parent_id =&gt; alice.id)&lt;br /&gt;&lt;br /&gt;# Create Bob's direct reports.&lt;br /&gt;charlene = Employee.create(:name =&gt; "Charlene", :title =&gt; "Manager", :parent_id =&gt; bob.id)&lt;br /&gt;dave = Employee.create(:name =&gt; "Dave",  :title =&gt; "Manager", :parent_id =&gt; bob.id)&lt;br /&gt;&lt;br /&gt;# Create Charlene's and Dave's direct reports.&lt;br /&gt;ellen = Employee.create(:name =&gt; "Ellen",  :title =&gt; "Software Engineer 1", :parent_id =&gt; charlene.id)&lt;br /&gt;frank = Employee.create(:name =&gt; "Frank",  :title =&gt; "Software Engineer 2", :parent_id =&gt; charlene.id)&lt;br /&gt;gerald = Employee.create(:name =&gt; "Gerald",  :title =&gt; "Software Engineer 2", :parent_id =&gt; dave.id)&lt;br /&gt;&lt;br /&gt;# Create another top level employee, Alvin.&lt;br /&gt;alvin = Employee.create(:name =&gt; "Alvin", :title =&gt; "President" )&lt;br /&gt;&lt;br /&gt;# Create Alvin's direct reports.&lt;br /&gt;bill = Employee.create(:name =&gt; "Bill",  :title =&gt; "Vice President", :parent_id =&gt; alvin.id)&lt;br /&gt;&lt;br /&gt;# Create Bill's direct reports.&lt;br /&gt;cedric = Employee.create(:name =&gt; "Cedric",  :title =&gt; "Manager", :parent_id =&gt; bill.id)&lt;br /&gt;dale = Employee.create(:name =&gt; "Dale",  :title =&gt; "Manager", :parent_id =&gt; bill.id)&lt;br /&gt;&lt;br /&gt;# Create Cedric's and Dale's direct reports.&lt;br /&gt;edward = Employee.create(:name =&gt; "Edward",  :title =&gt; "Software Engineer 1", :parent_id =&gt; cedric.id)&lt;br /&gt;felicia = Employee.create(:name =&gt; "Felicia",  :title =&gt; "Software Engineer 2", :parent_id =&gt; dale.id)&lt;br /&gt;&lt;br /&gt;# Find all of the employees that don't have managers.&lt;br /&gt;top_level = Employee.roots&lt;br /&gt;&lt;br /&gt;# Print out the management structure for each of the top level managers.&lt;br /&gt;top_level.each do | r |&lt;br /&gt;    put_management_chain(r, 0)&lt;br /&gt;    puts&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As always, let me know if you have questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-4727929467088041950?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/4727929467088041950/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/07/sequel-trees-redux.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/4727929467088041950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/4727929467088041950'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/07/sequel-trees-redux.html' title='Sequel Trees Redux'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-201400689464363322</id><published>2010-07-14T05:42:00.000-07:00</published><updated>2010-07-14T06:41:12.958-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Happy Numbers</title><content type='html'>Here's one that I saw on-line recently in an &lt;a href="http://fsharpnews.blogspot.com/2010/07/happy-numbers.html"&gt;article&lt;/a&gt; on F#, Microsoft's function language (there was actually a nice flame war going on on the site with respect F# vs. Mathmatica's language M). Anyway, from &lt;a href="http://en.wikipedia.org/wiki/Happy_number"&gt;Wikipedia&lt;/a&gt;, here's the definition of a happy number:&lt;br /&gt;&lt;blockquote&gt;A happy number is defined by the following process. Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers, while those that do not end in 1 are unhappy numbers (or sad numbers[1]).&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;I actually used this recently as a programming interview question and was surprised how well it worked out. It's easy enough to work out in 15-20 minutes (or at least to get most of the main ideas), it contains both math and string work, and you need either a hash or a set as a data structure to contain the visited numbers.&lt;br /&gt;&lt;br /&gt;The code itself is relatively straightforward. If we start down in the main part of the program, you'll see that we create an array to save the happy numbers and then loop to find all of the happy numbers less than or equal to 500 saving them in the array. Finally we print them out.&lt;br /&gt;&lt;br /&gt;The function &lt;code&gt;happy_number?&lt;/code&gt; takes a single parameter n and determines if it is a happy number. First, we create a hash table to save values that we've seen before so that we can detect loops. Then we start a loop that goes until we converge on 1 or until we detect a loop. The heart of the program is the next line which (reading the methods left to right) a) converts n to a string, b) creates an array of the digits as strings using &lt;code&gt;split&lt;/code&gt;, and finally uses &lt;code&gt;inject&lt;/code&gt; to sum the squares of the digits (appropriately converted back to integers). If we detect a loop, the value that we generated is already in the visited hash, then we return false. If not, we add v to visited and set n to v for the next round. If we exit the loop with a 1, we'll return true.&lt;br /&gt;&lt;br /&gt;Here's the code ...&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;# A function that determines whether a number passed in is a happy number or not. From Wikipedia:&lt;br /&gt;#&lt;br /&gt;# A happy number is defined by the following process. Starting with any&lt;br /&gt;# positive integer, replace the number by the sum of the squares of its digits,&lt;br /&gt;# and repeat the process until the number equals 1 (where it will stay), or it&lt;br /&gt;# loops endlessly in a cycle which does not include 1. Those numbers for which&lt;br /&gt;# this process ends in 1 are happy numbers, while those that do not end in 1&lt;br /&gt;# are unhappy numbers (or sad numbers[1]).&lt;br /&gt;#&lt;br /&gt;def happy_number?(n)&lt;br /&gt;&lt;br /&gt;    # visited is a Hash that will keep track of numbers we've already found.&lt;br /&gt;    visited = {}&lt;br /&gt;&lt;br /&gt;    # Loop until we converge on 1 (or exit in the middle of the loop if &lt;br /&gt;    # we find a value that we've already visited.&lt;br /&gt;    while n != 1&lt;br /&gt;&lt;br /&gt;        # Convert n to a string, then split to get an array of characters.  Use&lt;br /&gt;        # inject to calculate the sum of their squares and put it &lt;br /&gt;        # in v.&lt;br /&gt;        v = n.to_s.split(//).inject(0) { |sum, digit| sum += digit.to_i ** 2 }&lt;br /&gt;&lt;br /&gt;        # If we've already seen this value v, then we're in a&lt;br /&gt;        # loop and should return flase.&lt;br /&gt;        return false if visited.has_key? v&lt;br /&gt;            &lt;br /&gt;        # Add v to the visited list&lt;br /&gt;        visited[v] = true&lt;br /&gt;&lt;br /&gt;        # Set n to v for next round.&lt;br /&gt;        n = v&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # n is 1, so it's a original value was a happy number.&lt;br /&gt;    return true&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Place where we'll store the happy numbers&lt;br /&gt;happy_numbers = []&lt;br /&gt;&lt;br /&gt;# Find and save the happy numbers up to 500.&lt;br /&gt;1.upto(500) do |i|&lt;br /&gt;    happy_numbers &lt;&lt; i if happy_number?(i) == true&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Print out the happy numbers that we found.&lt;br /&gt;happy_numbers.each { |n| puts "Happy number #{n}" }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you have questions or comments, be sure to let me know.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-201400689464363322?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/201400689464363322/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/07/happy-numbers.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/201400689464363322'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/201400689464363322'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/07/happy-numbers.html' title='Happy Numbers'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-6259518761156334167</id><published>2010-07-09T13:28:00.000-07:00</published><updated>2010-07-09T15:26:05.562-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='praxis'/><title type='text'>RPN Calculator</title><content type='html'>Here's another one from &lt;a href="http://programmingpraxis.com/2009/02/19/rpn-calculator/"&gt;Programming Praxis&lt;/a&gt;. It's an RPN (reverse Polish calculator) problem that I've chosen to implement in Ruby. The text from Praxis is the header comment of the program. &lt;br /&gt;&lt;br /&gt;The first thing we do is open up the Array class and alias &lt;code&gt;last&lt;/code&gt; with a new method called &lt;code&gt;peek&lt;/code&gt; which returns the the last element of the array. Obviously, we could just use &lt;code&gt;last&lt;/code&gt;, but the "norm" for stacks is &lt;code&gt;peek&lt;/code&gt;. Next we actually create the stack using an Array. We could probably create our own stack with only the appropriate methods, but that's probably overkill for this little project (as I suppose you could argue creating peek is). Next, we'll just loop forever, printing a prompt,reading a line of text, and then processing it. The processing consists of taking a line apart and grabbing either a number, the first regular expression, or an operator, the second. For a number, we simply push it on the stack. For an operator, we pop the top two items off the stack and perform the operation on them. Then we push the result back on the stack. Finally, we strip whatever we just found, either number or operator, off the line and continue. When we finish processing the line, we print the top of stack and then continue on to the next line.&lt;br /&gt;&lt;br /&gt;Here's the actual code&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;# Implement an RPN calculator that takes an expression like 19 2.14 + 4.5 2 4.3&lt;br /&gt;# / - * which is usually expressed as (19 + 2.14) * (4.5 - 2 / 4.3) and responds&lt;br /&gt;# with 85.2974. The program should read expressions from standard input and&lt;br /&gt;# print the top of the stack to standard output when a newline is encountered.&lt;br /&gt;# The program should retain the state of the operand stack between expressions.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# Open up the Array class so we can add a &lt;br /&gt;# method to look at the "top of the stack".&lt;br /&gt;class Array&lt;br /&gt;    alias :peek :last&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Create the stack we'll use for processing.&lt;br /&gt;stack = Array.new&lt;br /&gt;while true&lt;br /&gt;&lt;br /&gt;    # Print the prompt.&lt;br /&gt;    print "&gt;&gt; "&lt;br /&gt;&lt;br /&gt;    # Get the line to process and remove the trailing \n.&lt;br /&gt;    line = gets.chomp&lt;br /&gt;&lt;br /&gt;    while line.size &gt; 0&lt;br /&gt;&lt;br /&gt;        # Check for a number first so that we don't grab a +/- &lt;br /&gt;        # and use it for an operator.&lt;br /&gt;        if line =~ /^\s*([-+]?[0-9]*\.?[0-9]+)\s*/&lt;br /&gt;            # Found an operand so we'll just push it &lt;br /&gt;            # on the stack after changing it to a float.&lt;br /&gt;            stack.push $1.to_f&lt;br /&gt;        elsif line =~ /^\s*([\+\-\*\/])\s*/ then&lt;br /&gt;            # The line has an operator (+/-*).&lt;br /&gt;            operator = $1&lt;br /&gt;&lt;br /&gt;            # Get the operands off the stack.&lt;br /&gt;            operand_2 = stack.pop&lt;br /&gt;            operand_1 = stack.pop&lt;br /&gt;&lt;br /&gt;            # Evaluate the expression and push it on to the stack.&lt;br /&gt;            stack.push  case operator &lt;br /&gt;                when '+'&lt;br /&gt;                    operand_1 + operand_2&lt;br /&gt;                when '-'&lt;br /&gt;                    operand_1 - operand_2&lt;br /&gt;                when '*'&lt;br /&gt;                    operand_1 * operand_2&lt;br /&gt;                when '/'&lt;br /&gt;                    operand_1 / operand_2&lt;br /&gt;                end&lt;br /&gt;        end&lt;br /&gt;&lt;br /&gt;        # Replace whatever we just found with the empty string.&lt;br /&gt;        line.sub!($&amp;, "")&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # We've finished processing the line, so print out the&lt;br /&gt;    # top of the stack.&lt;br /&gt;    puts "Top of stack = #{stack.peek}"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As always, let me know if you have questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-6259518761156334167?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/6259518761156334167/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/07/rpn-calculator.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/6259518761156334167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/6259518761156334167'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/07/rpn-calculator.html' title='RPN Calculator'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-6766315584028868589</id><published>2010-07-05T10:19:00.000-07:00</published><updated>2010-07-05T10:28:19.527-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='praxis'/><title type='text'>World Cup Simulation</title><content type='html'>Here's another one from &lt;a href="http://programmingpraxis.com/2010/06/29/world-cup-prognostication/"&gt;Programming Praxis&lt;/a&gt;. The goal is to simulate the world cup rounds using their calculations for winning expectation and thier elo values (read about their calculations). Here's the simulation:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;class Team&lt;br /&gt;    include Comparable&lt;br /&gt;&lt;br /&gt;    attr_reader :symbol, :country, :initial_elo, :new_elo&lt;br /&gt;    attr_accessor :world_cup_wins&lt;br /&gt;&lt;br /&gt;    # Initialization of the team.&lt;br /&gt;    def initialize(symbol, country, initial_elo)&lt;br /&gt;        @symbol = symbol&lt;br /&gt;        @country = country&lt;br /&gt;        @initial_elo = initial_elo&lt;br /&gt;        @new_elo = initial_elo&lt;br /&gt;        @world_cup_wins = 0&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # Defined for sorting.&lt;br /&gt;    def &lt;=&gt;(team_other)&lt;br /&gt;        @world_cup_wins &lt;=&gt; team_other.world_cup_wins&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # Print out the team and a few statistics.&lt;br /&gt;    def to_s&lt;br /&gt;        "#{@symbol} #{@country} #{@initial_elo} Wins = #{@world_cup_wins}"&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # Calculate the winning expectation between these two teasm.&lt;br /&gt;    def winning_expectation(team_other)&lt;br /&gt;        1.0 / (1.0 + 10.0 ** ((team_other.new_elo - @new_elo) / 400.0))&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # Simulate a game based on the winning expectation between this team and&lt;br /&gt;    # the other team.&lt;br /&gt;    def game(team_other)&lt;br /&gt;        w_e = winning_expectation(team_other)&lt;br /&gt;        if rand &lt;= w_e&lt;br /&gt;            # This team won so calculate appropriately the new elos.&lt;br /&gt;            calc_elo(w_e, 1.0)&lt;br /&gt;            team_other.calc_elo(w_e, 0.0)&lt;br /&gt;&lt;br /&gt;            # Return that this team won.&lt;br /&gt;            return true&lt;br /&gt;        else&lt;br /&gt;            # The other team won so calculate appropriately the new elos.&lt;br /&gt;            calc_elo(w_e, 0.0)&lt;br /&gt;            team_other.calc_elo(w_e, 1.0)&lt;br /&gt;&lt;br /&gt;            # Return that the other team won.&lt;br /&gt;            return false&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # Reset the elo to the initial_elo for the start of a &lt;br /&gt;    # new simulation.&lt;br /&gt;    def reset_elo&lt;br /&gt;        @new_elo = initial_elo&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # Calculate the elo based on the winning expectation and&lt;br /&gt;    # whether this team won or lost.&lt;br /&gt;    def calc_elo(w_e, win_loss)&lt;br /&gt;        @new_elo = @new_elo + 60.0 * 1.0 * (win_loss - w_e)&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Teams with their initial elo scores and ordered by the pairings (e.g. in the&lt;br /&gt;# first round Uruguay will play Korea, and Spain will play Portugal.&lt;br /&gt;initial_rankings = [&lt;br /&gt;&lt;br /&gt;    [ 7, "URU", "Uruguay",        1890],&lt;br /&gt;    [25, "KOR", "Korea",          1746],&lt;br /&gt;    [15, "USA", "United States",  1785],&lt;br /&gt;    [32, "GHA", "Ghana",          1711],&lt;br /&gt;    [ 3, "NED", "Netherlands",    2045],&lt;br /&gt;    [45, "SVK", "Slovakia",       1654],&lt;br /&gt;    [ 1, "BRA", "Brazil",         2082],&lt;br /&gt;    [ 8, "CHI", "Chile",          1883],&lt;br /&gt;    [ 4, "ARG", "Argentina",      1966],&lt;br /&gt;    [10, "MEX", "Mexico",         1873],&lt;br /&gt;    [ 6, "GER", "Germany",        1930],&lt;br /&gt;    [ 5, "ENG", "England",        1945],&lt;br /&gt;    [19, "PAR", "Paraguay",       1771],&lt;br /&gt;    [26, "JPN", "Japan",          1744],&lt;br /&gt;    [ 2, "ESP", "Spain",          2061],&lt;br /&gt;    [ 9, "POR", "Portugal",       1874],&lt;br /&gt;]&lt;br /&gt;&lt;br /&gt;# Create the teams array from the inital rankings above.&lt;br /&gt;teams = Array.new()&lt;br /&gt;initial_rankings.each do |r|&lt;br /&gt;    teams &lt;&lt; Team.new(r[1], r[2], r[3])&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Each simulated World Cup&lt;br /&gt;1.upto(1000000) do | sim |&lt;br /&gt;&lt;br /&gt;    # Start fresh by reinitializing the current_round with&lt;br /&gt;    # the teams and their elo.&lt;br /&gt;    current_round = teams&lt;br /&gt;    current_round.each { |t| t.reset_elo }&lt;br /&gt;&lt;br /&gt;    # Simulate the rounds&lt;br /&gt;    while current_round.size &gt; 1 do &lt;br /&gt;        # Create the array where we'll store the winners for the next round.&lt;br /&gt;        next_round = Array.new&lt;br /&gt;&lt;br /&gt;        # Loop through the round 2 at a time. The winner will get stored in the next_round array.&lt;br /&gt;        i = 0&lt;br /&gt;        while i &lt; current_round.size&lt;br /&gt;            # Add the winner to the next round.&lt;br /&gt;            next_round &lt;&lt; (current_round[i].game(current_round[i+1]) ? current_round[i] : current_round[i+1])&lt;br /&gt;            i += 2&lt;br /&gt;        end&lt;br /&gt;        &lt;br /&gt;        # Save the current round as the next round.&lt;br /&gt;        current_round = next_round&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # Add to the winner's total.&lt;br /&gt;    current_round[0].world_cup_wins += 1&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Sort by the number of wins and then print out the counts.&lt;br /&gt;teams.sort!&lt;br /&gt;teams.each do | t |&lt;br /&gt;    puts "team: #{t} "&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It should be commented well enough for you to figure everything out (assuming you also read the explanation over at Programming Praxis), but if you have any questions or comments, don't hesitate to ask.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-6766315584028868589?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/6766315584028868589/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/07/world-cup-simulation.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/6766315584028868589'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/6766315584028868589'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/07/world-cup-simulation.html' title='World Cup Simulation'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-5633678618906643124</id><published>2010-07-01T15:33:00.000-07:00</published><updated>2010-07-02T11:09:56.152-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='sequel'/><title type='text'>Sequel Trees</title><content type='html'>Edit: Jeremy Evans had a couple of suggestions which I've made in the code below. Use a real foreign key for the parent_id,use a portable text column, and finally don't give a parent_id for the root (Alice) of the tree.&lt;br /&gt;&lt;br /&gt;In &lt;a href="http://sequel.rubyforge.org/"&gt;Sequel&lt;/a&gt; 3.13.0, Jeremy Evans has added a few new plugins. Most interesting to me was the one for &lt;a href="http://sequel.rubyforge.org/rdoc-plugins/classes/Sequel/Plugins/Tree.html"&gt;trees&lt;/a&gt;, so I'm going to outline how to use it here. &lt;br /&gt;&lt;br /&gt;Here's a program that sets up and uses an employee/manager tree structure. We do our normal set up of the database, create the model (including adding the :tree plugin), and create a few employees. Finally, we run through a few of the common tree functions. The code is pretty well commented, so I'll present it and you can ask questions if you have any.&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'sequel'&lt;br /&gt;&lt;br /&gt;# Create an in-memory database&lt;br /&gt;DB = Sequel.sqlite &lt;br /&gt;&lt;br /&gt;# Create the employees table with a name and parent_id.&lt;br /&gt;DB.create_table :employees do &lt;br /&gt;    primary_key :id&lt;br /&gt;    foreign_key :parent_id, :employees&lt;br /&gt;    String :name, :text=&gt;true, :unique=&gt;true&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Create the Employee model. &lt;br /&gt;class Employee &lt; Sequel::Model&lt;br /&gt;    plugin :tree # Uses :parent_id field for parent&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Create the top level employee&lt;br /&gt;alice = Employee.create(:name =&gt; "Alice")&lt;br /&gt;&lt;br /&gt;# Create Alice's direct reports&lt;br /&gt;bob = Employee.create(:name =&gt; "Bob", :parent_id =&gt; alice.id)&lt;br /&gt;charlene = Employee.create(:name =&gt; "Charlene", :parent_id =&gt; alice.id)&lt;br /&gt;dave = Employee.create(:name =&gt; "Dave", :parent_id =&gt; alice.id)&lt;br /&gt;&lt;br /&gt;# Create Charlene's direct reports&lt;br /&gt;ellen = Employee.create(:name =&gt; "Ellen", :parent_id =&gt; charlene.id)&lt;br /&gt;frank = Employee.create(:name =&gt; "Frank", :parent_id =&gt; charlene.id)&lt;br /&gt;&lt;br /&gt;# Find the top level employee for Ellen&lt;br /&gt;president = ellen.root&lt;br /&gt;puts "Ellen's president: #{president.name}"&lt;br /&gt;&lt;br /&gt;# Find Ellen's management chain.&lt;br /&gt;managers = ellen.ancestors&lt;br /&gt;managers.each do | a |&lt;br /&gt;    puts "Ellen's manager: #{a.name}"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Find Charlene's coworkers.&lt;br /&gt;coworkers = charlene.siblings&lt;br /&gt;coworkers.each do | s |&lt;br /&gt;    puts "Charlene's coworker: #{s.name}"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Find Charlene's coworkers and Charlene.&lt;br /&gt;self_coworkers = charlene.self_and_siblings&lt;br /&gt;self_coworkers.each do | s |&lt;br /&gt;    puts "Charlene's coworker (or Charlene): #{s.name}"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Let me know if you have any questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-5633678618906643124?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/5633678618906643124/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/07/sequel-trees.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/5633678618906643124'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/5633678618906643124'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/07/sequel-trees.html' title='Sequel Trees'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-3522822092197651911</id><published>2010-06-26T10:45:00.000-07:00</published><updated>2010-07-05T10:29:13.688-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='praxis'/><title type='text'>The N Queens Problem in Ruby</title><content type='html'>The N Queens Problem was posed recently over at &lt;a href="http://programmingpraxis.com/2010/06/11/n-queens/"&gt;Programming Praxis&lt;/a&gt;. This is a pretty classic problem and typically uses a recursive solution. Here's what I came up with as a ruby solution.&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;# We present today a classic exercise that has been on my to-do list since the&lt;br /&gt;# start of Programming Praxis.&lt;br /&gt;# &lt;br /&gt;# The n-queens problem is to find all possible ways to place n queens on an n ×&lt;br /&gt;# n chess board in such a way that no two queens share a row, column, or&lt;br /&gt;# diagonal. The diagram at right shows one way that can be done on a standard 8&lt;br /&gt;# × 8 chess board.&lt;br /&gt;# &lt;br /&gt;# Your task is to write a program to find all such placements. When you are&lt;br /&gt;# finished, you are welcome to read or run a suggested solution, or to post&lt;br /&gt;# your own solution or discuss the exercise in the comments below.&lt;br /&gt;&lt;br /&gt;class Board&lt;br /&gt;&lt;br /&gt;    # Create a new board, initialize with with all "b" and&lt;br /&gt;    # save the size of it.&lt;br /&gt;    def initialize(n)&lt;br /&gt;        @n = n&lt;br /&gt;        @board = Array.new(n)&lt;br /&gt;        @board.map! { Array.new(n, "b") }&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # Print the current board.&lt;br /&gt;    def print_board&lt;br /&gt;        puts "Board:"&lt;br /&gt;        @board.each_index do |row|&lt;br /&gt;            @board.each_index do |col|&lt;br /&gt;                print "#{@board[row][col]}"&lt;br /&gt;            end&lt;br /&gt;            puts&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # Check if the row is safe by looping through each of the &lt;br /&gt;    # columns in the row.&lt;br /&gt;    def safe_row(suggested_row)&lt;br /&gt;        0.upto(@n-1) do |col|&lt;br /&gt;            return false if @board[suggested_row][col] == "Q"&lt;br /&gt;        end&lt;br /&gt;&lt;br /&gt;        return true&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # Check if the column is safe by looping through each of the &lt;br /&gt;    # rows in the row.&lt;br /&gt;    def safe_col(suggested_col)&lt;br /&gt;        0.upto(@n-1) do |row|&lt;br /&gt;            return false if @board[row][suggested_col] == "Q"&lt;br /&gt;        end&lt;br /&gt;&lt;br /&gt;        return true&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # Loop through in one diagonal direction to determine if the &lt;br /&gt;    # suggested row and column are safe.&lt;br /&gt;    def safe_diag(suggested_row, suggested_col, row_mod, col_mod)&lt;br /&gt;        row,col = suggested_row+row_mod, suggested_col+col_mod&lt;br /&gt;        while true do&lt;br /&gt;&lt;br /&gt;            # Break out of the loop if the row or column is off the board.&lt;br /&gt;            break if (row &gt;= @n) || (col &gt;= @n) || (row &lt; 0) || (col &lt; 0)&lt;br /&gt;&lt;br /&gt;            # If this row or column has a queen, then it's not safe.&lt;br /&gt;            return false if @board[row][col] == "Q"&lt;br /&gt;                &lt;br /&gt;            # Move in the appropriate direction.&lt;br /&gt;            row += row_mod&lt;br /&gt;            col += col_mod&lt;br /&gt;        end&lt;br /&gt;&lt;br /&gt;        # This direction is safe.&lt;br /&gt;        return true&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def safe(suggested_row, suggested_col)&lt;br /&gt;&lt;br /&gt;        # Check the rows and columns for safe.&lt;br /&gt;        return false if !safe_row(suggested_row)&lt;br /&gt;        return false if !safe_col(suggested_col)&lt;br /&gt;&lt;br /&gt;        # Check the diagonals for safe.&lt;br /&gt;        return false if !safe_diag(suggested_row, suggested_col, 1, 1)&lt;br /&gt;        return false if !safe_diag(suggested_row, suggested_col, 1, -1)&lt;br /&gt;        return false if !safe_diag(suggested_row, suggested_col, -1, 1)&lt;br /&gt;        return false if !safe_diag(suggested_row, suggested_col, -1, -1)&lt;br /&gt;&lt;br /&gt;        # Should be OK.&lt;br /&gt;        return true&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # Solve the n-queens problem by making a call to the recursive solve_1&lt;br /&gt;    # method with 0 (the first row of the board) to start.&lt;br /&gt;    def solve&lt;br /&gt;        solve_1(0)&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # The recursive method (by row) that loops through the columns and checks&lt;br /&gt;    # if the row given and the column are "safe". If they are we add a "Q" to&lt;br /&gt;    # the position and if the row is 0, we print it out (everthing is&lt;br /&gt;    # complete). If it's safe adn we aren't at 0 we move to the next row&lt;br /&gt;    # recursively.  Finally, we reset the position to "b" (blank) when we&lt;br /&gt;    # return from the recursive call or from printing the board.  If it's not&lt;br /&gt;    # "safe" then we just move to the next column and try that one.&lt;br /&gt;    def solve_1(row)&lt;br /&gt;        0.upto(@n-1) do |col|&lt;br /&gt;            if safe(row, col)&lt;br /&gt;                @board[row][col] = "Q"&lt;br /&gt;                if row == (@n-1)&lt;br /&gt;                    print_board&lt;br /&gt;                else&lt;br /&gt;                    solve_1(row+1)&lt;br /&gt;                end&lt;br /&gt;                @board[row][col] = "b"&lt;br /&gt;            end&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# Solve the problem for 8 queens. There should be 92&lt;br /&gt;# solutions.&lt;br /&gt;board = Board.new(8).solve&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I've put quite a few comments in there, but if you have questions, don't hesitate to ask.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-3522822092197651911?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/3522822092197651911/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/06/n-queens-problem-in-ruby.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/3522822092197651911'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/3522822092197651911'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/06/n-queens-problem-in-ruby.html' title='The N Queens Problem in Ruby'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-9180198835271271237</id><published>2010-06-23T19:13:00.000-07:00</published><updated>2010-06-24T06:43:30.461-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='shjs'/><category scheme='http://www.blogger.com/atom/ns#' term='webrick'/><title type='text'>Simple Webrick Server and shjs Syntax Highlighting</title><content type='html'>Since I've upgraded my machine, maruku hasn't been able to do syntax highlighting for me. I'm now giving &lt;a href="http://www.yourjavascript.com/"&gt;shjs&lt;/a&gt; a shot. Here's a simple webserver using webrick.&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;# Get webrick&lt;br /&gt;require 'webrick'&lt;br /&gt;include WEBrick&lt;br /&gt;&lt;br /&gt;# Create the server.&lt;br /&gt;server = HTTPServer.new(:Port =&gt; 9090, :DocumentRoot =&gt; Dir::pwd)&lt;br /&gt;&lt;br /&gt;# Shutdown if we get an interrupt.&lt;br /&gt;trap("INT") { server.shutdown }&lt;br /&gt;&lt;br /&gt;# Start the server&lt;br /&gt;server.start&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Not to much going on here. We get webrick included and create the server. The port here is 9090 (obviously you can pick any one that you want). The HTML files will be served from the current directory and this can be modified also. Then we shut down the server when we see a ^C and finally, we start the server.&lt;br /&gt;&lt;br /&gt;I actually lifted this from somewhere and forgot to grab the link to give credit. If it's yours or you know who's it is, let me know so I can acknowledge them.&lt;br /&gt;&lt;br /&gt;Let me know if you have questions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-9180198835271271237?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/9180198835271271237/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/06/simple-webrick-server-and-shjs-syntax_23.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/9180198835271271237'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/9180198835271271237'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/06/simple-webrick-server-and-shjs-syntax_23.html' title='Simple Webrick Server and shjs Syntax Highlighting'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-7324894492558709121</id><published>2010-05-30T10:24:00.000-07:00</published><updated>2010-06-26T10:55:45.438-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>145 Puzzle</title><content type='html'>I've just started reading a blog &lt;a href="http://programmingpraxis.com/"&gt;Praxis&lt;/a&gt; that features programming problems to solve and shows their solutions typically in scheme. You're encouraged to submit your own solutions there to for others to look examine. The ones that come from &lt;a href="http://bonsaicode.wordpress.com/"&gt;Bonsai Code&lt;/a&gt; in Haskell are nothing short of amazing in their brevity.&lt;br /&gt;&lt;br /&gt;Anyway, one I've solved is the 145 puzzle. Here's the description from &lt;a href="http://programmingpraxis.com/2010/04/20/145-puzzle/"&gt;Praxis&lt;/a&gt; ...&lt;br /&gt;&lt;blockquote&gt;Form all the arithmetic expressions that consist of the digits one through nine, in order, with a plus-sign, a times-sign, or a null character interpolated between each pair of digits; for instance, 12+34*56+7*89 is a valid expression that evaluates to 2539. What number is the most frequent result of evaluating all possible arithmetic expressions formed as described above? How many times does it occur? What are the expressions that evaluate to that result?&lt;/blockquote&gt;.&lt;br /&gt;&lt;br /&gt;So here's my solution in Ruby:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sh_ruby"&gt;&lt;br /&gt;#&lt;br /&gt;# Consider this math puzzle:&lt;br /&gt;&lt;br /&gt;# Form all the arithmetic expressions that consist of the digits one through&lt;br /&gt;# nine, in order, with a plus-sign, a times-sign, or a null character&lt;br /&gt;# interpolated between each pair of digits; for instance, 12+34*56+7*89 is a&lt;br /&gt;# valid expression that evaluates to 2539. What number is the most frequent&lt;br /&gt;# result of evaluating all possible arithmetic expressions formed as&lt;br /&gt;# described above? How many times does it occur? What are the expressions&lt;br /&gt;# that evaluate to that result?&lt;br /&gt;# &lt;br /&gt;# Your task is to answer the three questions. When you are finished, you are&lt;br /&gt;# welcome to read or run a suggested solution, or to post your own solution or&lt;br /&gt;# discuss the exercise in the comments below. &lt;br /&gt;&lt;br /&gt;# Multi-combination. Takes the elements to combine, a "level" (how many ways&lt;br /&gt;# will we do the combination), the current multi-combination, and a block that&lt;br /&gt;# we'll yield to.&lt;br /&gt;def mc(elements, level, current=[], &amp;block)&lt;br /&gt;    elements.each do | e |&lt;br /&gt;        if level == 1 then&lt;br /&gt;            yield current &lt;&lt; e&lt;br /&gt;        else&lt;br /&gt;            mc(elements, level-1, current &lt;&lt; e, &amp;block)&lt;br /&gt;        end&lt;br /&gt;        current.pop&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Main program.&lt;br /&gt;digits = ['1', '2', '3', '4', '5', '6', '7', '8', '9']&lt;br /&gt;&lt;br /&gt;# DON'T initialize the hash with "[]" (as I initially did). You'll end up with&lt;br /&gt;# the same array in every hash position.&lt;br /&gt;results = Hash.new()&lt;br /&gt;&lt;br /&gt;# Generate each multi-combination in the 8 spots (between each of the digits.&lt;br /&gt;mc(['*', '+', ''], 8) do | operators | &lt;br /&gt;&lt;br /&gt;    # Initialize the string to evaluate.&lt;br /&gt;    eval_string = ''&lt;br /&gt;&lt;br /&gt;    # Add the digits and operators to the eval_string.&lt;br /&gt;    0.upto(digits.length-2) { |i| eval_string &lt;&lt; digits[i] &lt;&lt; operators[i] }&lt;br /&gt;&lt;br /&gt;    # Add teh final digit.&lt;br /&gt;    eval_string &lt;&lt; digits.last&lt;br /&gt;&lt;br /&gt;    # Evaluate the string and save the result in the hash. Create a new array&lt;br /&gt;    # if one doesn't exist at this position.&lt;br /&gt;    (results[eval(eval_string)] ||= []) &lt;&lt; eval_string&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Get the results that occur the most times.&lt;br /&gt;m = results.max { |a, b| a[1].length &lt;=&gt; b[1].length }&lt;br /&gt;&lt;br /&gt;# Print out the answer.&lt;br /&gt;puts "Most evaluated number = #{m[0]} Number of times evaluated = #{m[1].length} values = #{m[1]}"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Let me know if you have questions and take some time to explore &lt;a href="http://programmingpraxis.com/"&gt;Praxis&lt;/a&gt; and solve some of the problems yourself.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-7324894492558709121?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/7324894492558709121/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/05/145-puzzle.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/7324894492558709121'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/7324894492558709121'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/05/145-puzzle.html' title='145 Puzzle'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-6990720010159692345</id><published>2010-05-27T19:22:00.000-07:00</published><updated>2010-05-27T19:46:15.350-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='vim'/><category scheme='http://www.blogger.com/atom/ns#' term='ramaze'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='sequel'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>Installing Ubuntu, Ruby, Ramaze, Sequel, Vim, and More on an HP dm3-1130us</title><content type='html'>Sorry for not posting recently. My trusty Sony VAIO passed away and I've been getting my new box, an HP dm3-1130us running Linux with all the tools that I normally use. I thought I'd document it in case anyone else needed to do it. To be honest, most of this should work on any system not just mine or even an HP. Here are the steps:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Create boot disks. Use the Recovery Manager.&lt;/li&gt;&lt;li&gt;Use http://unetbootin.sourceforge.net/ to create a bootable USB device.&lt;/li&gt;&lt;li&gt;Plug the USB drive in, reboot, and hit ESC (multiple times).&lt;/li&gt;&lt;li&gt;Select the USB device to boot&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Ubuntu should load. Pick your name, language keyboard, time zone, and password (I think these are all that are asked for)&lt;/li&gt;&lt;li&gt;Install flash - sudo apt-get install flashplugin-nonfree&lt;/li&gt;&lt;li&gt;Add the following add ons to Firefox (you may have different favorites)- Colorful Tabs, Faviconize, Vimperator&lt;/li&gt;&lt;li&gt;Install Ruby 1.9 - sudo apt-get install ruby1.9.1-full (will load  executable ruby1.9.1)&lt;/li&gt;&lt;li&gt;Create a symbolic link for ruby - sudo ln -s  /usr/bin/ruby1.9.1 /usr/bin/ruby&lt;br /&gt;Install 7zip - sudo apt-get install  p7zip&lt;/li&gt;&lt;li&gt;Install gvim - sudo apt-get install vim-gnome; Create an  application launcher&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Name-gvim Location-/usr/bin/gvim Change the icon to  /usr/share/pixmaps/vim.svg&lt;/li&gt;&lt;li&gt;Install Ruby gems - sudo apt-get install rubygems1.9.1&lt;/li&gt;&lt;li&gt;Install mailit  mail package for ruby - sudo gem install mailit&lt;br /&gt;Install gemcutter  (A replacement for SourceForge  and gethub as gem repositories) - sudo gem install gemcutter&lt;/li&gt;&lt;li&gt;Install  sequel - sudo gem install sequel&lt;/li&gt;&lt;li&gt;Install sqlite3 - sudo apt-get  install sqlite3 libsqlite3-dev&lt;/li&gt;&lt;li&gt;Install sqlite3-ruby gem - sudo gem  install sqlite3-ruby&lt;/li&gt;&lt;li&gt;Install ramaze - sudo gem install ramaze&lt;/li&gt;&lt;li&gt;Put  sequel into /usr/bin - sudo ln -s /var/lib/gems/1.9.1/bin/sequel  /usr/bin&lt;/li&gt;&lt;li&gt;Put ramaze in /usr/bin - sudo ln -s  /var/lib/gems/1.9.1/bin/ramaze /usr/bin&lt;/li&gt;&lt;li&gt;Add the sqlite manager to Firefox -  https://addons.mozilla.org/en-US/firefox/addon/5817/&lt;/li&gt;&lt;li&gt;Download  snipmate.vim - http://www.vim.org/scripts/script.php?script_id=2540&lt;/li&gt;&lt;li&gt;Unzip  snipmate.zip from ~/Downloads - unzip snipMate.zip -d ~/.vim&lt;/li&gt;&lt;li&gt;Install irb *and*  removed unused packages - sudo apt-get install irb1.9; sudo apt-get  autoremove&lt;/li&gt;&lt;li&gt;Be able to use matchit (match ruby do/end etc.) in vim  (may want to look at vim-addons for Debian/Ubuntu) - set  rtp+=/usr/share/vim/addons/ (in the .vimrc file)&lt;/li&gt;&lt;/ul&gt;Vimperator is a Firefox add-on that if you use vim, you absolutely need. It makes Firefox behave like vim ("j" scrolls down, "k" scrolls up, etc.). For vim itself, you need to look at snipmate. It provides snippets (similar to TextMate I believe) and it will make your Ruby programming life much easier. The final step, for matchit, is a bit of a hack and you probably want to investigate the vim-addons tool which from my quick glance, looked like a gem type thing for vim add ons.&lt;br /&gt;&lt;br /&gt;I'm keeping a list of everything I do system wise on this machine. I discovered that for the most part I had a ton of stuff that I wasn't using and sometimes had no idea what it was.&lt;br /&gt;&lt;br /&gt;So, let me know if you have any questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-6990720010159692345?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/6990720010159692345/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/05/installing-ubuntu-ruby-ramaze-sequel.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/6990720010159692345'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/6990720010159692345'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/05/installing-ubuntu-ruby-ramaze-sequel.html' title='Installing Ubuntu, Ruby, Ramaze, Sequel, Vim, and More on an HP dm3-1130us'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-1502642622167634951</id><published>2010-04-21T05:56:00.000-07:00</published><updated>2010-04-21T06:08:03.441-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Passing Classes as Parameters</title><content type='html'>I've been playing around with genetic algorithms again and I'll post my work a bit later. But, I did realize something while I was doing it that I thought was interesting and completely makes sense, but I hadn't seen discussed anywhere before (that I remember anyway). You can actually pass Classes as parameters to methods, including initializers. Why's this interesting? It allows you to create factories and then pass those factories to other classes. Here's a very simple example, using my genetic algorithm terminology of Organisms.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='ruby' lang='ruby'&gt;&lt;span class='comment'&gt;# Create a basic organism.&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;Organism&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;speak&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;I&amp;#39;m a basic organism&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Derive an organism that modifies the speak method.&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;OrganismOther&lt;/span&gt; &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt; &lt;span class='constant'&gt;Organism&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;speak&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;I&amp;#39;m another organism&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Create a &amp;quot;factory&amp;quot; that take a Class as a parameter and can&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# generate organisms of that class.&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;OrganismFactory&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;initialize&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;organism_class&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@organism_class&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;organism_class&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;generate_organism&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@organism_class&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='constant'&gt;__FILE__&lt;/span&gt; &lt;span class='punct'&gt;==&lt;/span&gt; &lt;span class='global'&gt;$PROGRAM_NAME&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Create a basic and other factory for the two types of organisms.&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;organism_factory_basic&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;OrganismFactory&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='constant'&gt;Organism&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;organism_factory_other&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;OrganismFactory&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='constant'&gt;OrganismOther&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Generate an organism of each type.&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;organism&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;organism_factory_basic&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;generate_organism&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;organism_other&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;organism_factory_other&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;generate_organism&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Let them speak.&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;organism&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;speak&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;organism_other&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;speak&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You can see that we create a basic Organism and then subclass it to get a slightly different organism. There's nothing too awfully interesting there. Next is the OrganismFactory where we show off our new technique.  The &lt;code&gt;initialize()&lt;/code&gt; method takes a Class as a parameter and saves it away in the &lt;code&gt;@organism_class&lt;/code&gt; variable. We also have a method &lt;code&gt;generate_organism()&lt;/code&gt; that will return an object of the type that was passed in. Finally, we have the main program that creates a couple of factories, one of each type, and then uses them to create objects of each type. Finally, we make sure they work by having them "speak".&lt;br /&gt;&lt;br /&gt;Let me know if you have questions or comments on this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-1502642622167634951?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/1502642622167634951/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/04/passing-classes-as-parameters.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/1502642622167634951'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/1502642622167634951'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/04/passing-classes-as-parameters.html' title='Passing Classes as Parameters'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-6502786821019472003</id><published>2010-03-22T15:47:00.000-07:00</published><updated>2010-03-22T15:51:44.132-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='dynamic programming'/><title type='text'>Metaprogramming Ruby - Review</title><content type='html'>I wrote a review of Metaprogramming Ruby by Paolo Perrotta and much to my surprise, Slashdot published it. You can find it &lt;a href="http://books.slashdot.org/story/10/03/22/146235/Metaprogramming-Ruby"&gt;here&lt;/a&gt;. Feel free to post comments and thoughts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-6502786821019472003?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/6502786821019472003/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/03/metaprogramming-ruby-review.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/6502786821019472003'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/6502786821019472003'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/03/metaprogramming-ruby-review.html' title='Metaprogramming Ruby - Review'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-6977122528972082633</id><published>2010-02-17T05:54:00.000-08:00</published><updated>2010-02-17T06:12:39.085-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='dynamic programming'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><title type='text'>Ruby and Simple Dynamic Programming V</title><content type='html'>I've been reading Paolo Perrotta's new book "&lt;a href="http://www.amazon.com/Metaprogramming-Ruby-Paolo-Perrotta/dp/1934356476/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1266414967&amp;sr=1-1"&gt;Metaprogramming Ruby&lt;/a&gt;" recently and enjoying it thoroughly. In the first chapter, he talks about &lt;a href="http://en.wikipedia.org/wiki/Monkey_patch"&gt;Monkey Patching&lt;/a&gt;, the ability to add methods to classes at runtime. This combined with a need recently for an iterator through an array that returns both the index and the value led me to come up with the following code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='ruby' lang='ruby'&gt;&lt;span class='comment'&gt;# Open the Array class and add a new method &amp;quot;each_with_index&amp;quot;.&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# This will loop through the array using the each_index method&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# and yeild the index and the value of the array at that index.&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;Array&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;each_with_index&lt;/span&gt;&lt;br /&gt;        &lt;span class='constant'&gt;self&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;each_index&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt; &lt;span class='punct'&gt;|&lt;/span&gt; &lt;span class='ident'&gt;i&lt;/span&gt; &lt;span class='punct'&gt;|&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;yield&lt;/span&gt; &lt;span class='ident'&gt;i&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='constant'&gt;self&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='ident'&gt;i&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='constant'&gt;__FILE__&lt;/span&gt; &lt;span class='punct'&gt;==&lt;/span&gt; &lt;span class='global'&gt;$PROGRAM_NAME&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Create a simple array&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;x&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;[&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;hello&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;,&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;world&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;,&lt;/span&gt; &lt;span class='number'&gt;42&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='number'&gt;3.14159&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='punct'&gt;[&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;test&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;,&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;an&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;,&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;array&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;]&lt;/span&gt; &lt;span class='punct'&gt;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Go through the array and print each index and value in the&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# array.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;x&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;each_with_index&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt; &lt;span class='punct'&gt;|&lt;/span&gt; &lt;span class='ident'&gt;i&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='ident'&gt;v&lt;/span&gt; &lt;span class='punct'&gt;|&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;index = &lt;span class='expr'&gt;#{i}&lt;/span&gt; value = &lt;span class='expr'&gt;#{v}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The code is pretty simple. We open the Arrary class, define the new method, and then close the class. There's a bit of test code after that to show that everything works as expected.&lt;br /&gt;&lt;br /&gt;Even though I'm only through the first chapter, I can recommend Perrotta's book. It's an easy read (so far anyway) and clearly shows the concepts that it discusses. The form it takes is conversational and the narrative is that you're a programmer, new to Ruby, who is paired with a senior developer Bill. This format may not be for everyone, especially if you're looking for more "formality", but I think it works well here and it's not overdone.&lt;br /&gt;&lt;br /&gt;Let me know if you have questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-6977122528972082633?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/6977122528972082633/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/02/ruby-and-simple-dynamic-programming-v.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/6977122528972082633'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/6977122528972082633'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/02/ruby-and-simple-dynamic-programming-v.html' title='Ruby and Simple Dynamic Programming V'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-2310761913746468409</id><published>2010-02-10T05:28:00.000-08:00</published><updated>2010-02-10T06:12:35.808-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Beginning a Program</title><content type='html'>A young friend (YF) of mine was having a problem with a programming assignment from a large local university (LLU) and gave me a call the other day for some help. We spent a couple of hours together going through the piece that he was having issues with and finally got everything pretty much working. This episode though showed me that we don't necessarily teach the right things in college concerning how approach a program. I thought I'd take a few posts and show how I might tackle a problem like this. Not everyone will find this way of doing things appropriate and I wouldn't use it in certain cases, but it may help some of you in some cases.&lt;br /&gt;&lt;br /&gt;Here's the problem as given:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Assignment Details&lt;br /&gt;Homework 1 - Non-GUI Tower Defender&lt;br /&gt;Players start with a fixed amount of money, in less they are a returning player. In that case, they are to start with the money they ended up with, or they can start over, if they wish.&lt;br /&gt;&lt;br /&gt;Towers:There are to be 4 types of towers. Each has a different capability - you get to decide. Each has a different price - that you decide. A player starts the game by deciding which towers they want and where they are to be put. Given that the path for Creeps is only from left to right, towers can be above, or below, the path. The player gets to decide that, and the "x-direction" for the tower location.&lt;br /&gt;&lt;br /&gt;Since this first assignment is not graphical - only command line - the Creep path is straight from left to right. You are to use keyboard characters as your graphics to display what is happening - tower location, and Creep location.&lt;br /&gt;&lt;br /&gt;Creeps:Creeps may move one, or more, squares, from left to right each "turn". You get to decide how big squares are. Too big, and Creeps will easily get to the base - which is on the right side of the window. Creeps start from the left side of the display window. You are to have three (3) types of Creeps. Their behavior is up to you, but just moving faster, or slower, does not qualify as a different Creep type. Each Creep is worth a different amount of money - depending on how hard they are to kill.&lt;br /&gt;&lt;br /&gt;Statistics: You are to track the number of Creeps killed (for each Creep type), the total number of times this player has played, the total amount of money they have spent, and the total amount of money they have earned. You may choose to have additional statistics.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;There are a few things here that are worth noting. First the requirements are pretty loose. You have some options for doing things how you like (this may be good or bad depending on your temperament. Second there are a couple of things that don't make sense. We have the "x-direction" for the tower location. I'm pretty sure that what's meant is the "x-position", but if I were doing this for a grade at LLU, I'd check with the prof. I checked with YF and it sounds like since the towers don't move, the x-position is what is meant.&lt;br /&gt;&lt;br /&gt;As a first cut, I'd spend my time working on the "logistics" of the program. What do I mean by that? Well, we'll have a main program that loops getting input from a player. We're going to have to create a player, give her some money, be able to save her totals when she quits, and on initialization, we're going to have to check if she's played before and if so if she'd like to resume or start a new game.&lt;br /&gt;&lt;br /&gt;With that out of the way, here's what I came up with (this is in Ruby, YF for LLU had to write this in Java).&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='ruby' lang='ruby'&gt;&lt;span class='comment'&gt;# Assignment Details Homework 1 - Non-GUI Tower Defender Players start with a&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# fixed amount of money, in less they are a returning player. In that case,&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# they are to start with the money they ended up with, or they can start over,&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# if they wish.&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Towers: There are to be 4 types of towers. Each has a different capability -&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# you get to decide. Each has a different price - that you decide. A player&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# starts the game by deciding which towers they want and where they are to be&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# put. Given that the path for Creeps is only from left to right, towers can be&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# above, or below, the path. The player gets to decide that, and the&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# &amp;quot;x-direction&amp;quot; for the tower location.&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Since this first assignment is not graphical - only command line - the Creep&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# path is straight from left to right. You are to use keyboard characters as&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# your graphics to display what is happening - tower location, and Creep&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# location.&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Creeps: Creeps may move one, or more, squares, from left to right each &amp;quot;turn&amp;quot;.&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# You get to decide how big squares are. Too big, and Creeps will easily get to&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# the base - which is on the right side of the window. Creeps start from the&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# left side of the display window. You are to have three (3) types of Creeps.&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Their behavior is up to you, but just moving faster, or slower, does not&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# qualify as a different Creep type. Each Creep is worth a different amount of&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# money - depending on how hard they are to kill.&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Statistics: You are to track the number of Creeps killed (for each Creep&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# type), the total number of times this player has played, the total amount of&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# money they have spent, and the total amount of money they have earned. You&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# may choose to have additional statistics.&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;#&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;Tower&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;Creep&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;Game&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;Player&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Initialize a player.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;initialize&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@name&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;name&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@dollars&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='number'&gt;100&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@file_name&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;&lt;span class='expr'&gt;#{@name}&lt;/span&gt;.txt&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;br /&gt;        &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='constant'&gt;File&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;exist?&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='attribute'&gt;@file_name&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;print&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Welcome back &lt;span class='expr'&gt;#{@name}&lt;/span&gt;. Would you like to resume(r) or start a new game(n)?&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;command&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;gets&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;chomp&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;case&lt;/span&gt; &lt;span class='ident'&gt;command&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;when&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;r&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Resuming from &lt;span class='expr'&gt;#{@file_name}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;                &lt;span class='constant'&gt;File&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;open&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='attribute'&gt;@file_name&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;r&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;)&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt; &lt;span class='punct'&gt;|&lt;/span&gt;&lt;span class='ident'&gt;player_file&lt;/span&gt;&lt;span class='punct'&gt;|&lt;/span&gt;&lt;br /&gt;                    &lt;span class='ident'&gt;line&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;player_file&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;gets&lt;/span&gt;&lt;br /&gt;                    &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;line&lt;/span&gt; &lt;span class='punct'&gt;!=&lt;/span&gt; &lt;span class='constant'&gt;nil&lt;/span&gt;&lt;br /&gt;                        &lt;span class='ident'&gt;name_f&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='attribute'&gt;@dollars&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;line&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;split&lt;/span&gt;&lt;span class='punct'&gt;(&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;,&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;)&lt;/span&gt;&lt;br /&gt;                        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Resume: &lt;span class='expr'&gt;#{name_f}&lt;/span&gt;: Dollars&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='comment'&gt;#{dollars_f}&amp;quot;&lt;/span&gt;&lt;br /&gt;                    &lt;span class='keyword'&gt;else&lt;/span&gt;&lt;br /&gt;                        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Could not read line&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;                    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;                &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;when&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;n&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Starting new game&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Save the players and stats to a file.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;save&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;player_file&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;File&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='attribute'&gt;@file_name&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;w+&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;)&lt;/span&gt;&lt;br /&gt;           &lt;span class='ident'&gt;player_file&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;&lt;span class='expr'&gt;#{@name}&lt;/span&gt;, &lt;span class='expr'&gt;#{@dollars}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;player_file&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;close&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Convenience funtion to get the player and their current&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# stats.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;to_s&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;name: &lt;span class='expr'&gt;#{@name}&lt;/span&gt;, dollars: &lt;span class='expr'&gt;#{@dollars}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='constant'&gt;__FILE__&lt;/span&gt; &lt;span class='punct'&gt;==&lt;/span&gt; &lt;span class='global'&gt;$PROGRAM_NAME&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Get the player name&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;print&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Name: &lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;name&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;gets&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;chomp&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Create a new player&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;player&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;Player&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;&lt;span class='expr'&gt;#{player}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Do forever (or until a &amp;#39;q&amp;#39; command anyway)&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;while&lt;/span&gt; &lt;span class='constant'&gt;true&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class='comment'&gt;# Get the command&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;print&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Command: &lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;command&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;gets&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;chomp&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class='comment'&gt;# Check the command and execute it.&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;case&lt;/span&gt; &lt;span class='ident'&gt;command&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;when&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;q&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# Quit so go ahead and save the player then break out&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# of the loop.&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;player&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;save&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;break&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You can see that I put the requirements at the top so they're pretty much always available for checking (you obviously can't do this with really big requirements, but when you can, it's not a bad idea). There are place holders for the classes that I think we'll have, but those may change. The one that's filled out, the Player class, has just three methods. initialize(), sets the player up and checks if the do/don't already have a saved game, save() saves the players current data, and to_s() let's us print out their data in a readable format. As we go along, these may (really will) change and get refactored, but for now, they'll suffice. The main program asks the user for their name and creates a player. We then start the main loop that just gets a command (here only the quit command) and processes it. Quit simply saves the players data and breaks out of the loop which then exits.&lt;br /&gt;&lt;br /&gt;This would probably take less than 1/2 an hour for someone who knows the language they're working in fairly well. What is does though is provide us with places to hang major pieces of the game going forward.&lt;br /&gt;&lt;br /&gt;Let me know if you have questions or comments and look for the next edition where we'll add in a bit more functionality to the program.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-2310761913746468409?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/2310761913746468409/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/02/beginning-program.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/2310761913746468409'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/2310761913746468409'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/02/beginning-program.html' title='Beginning a Program'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-8752946061927274388</id><published>2010-01-20T05:44:00.000-08:00</published><updated>2010-01-20T06:09:05.650-08:00</updated><title type='text'>Ruby and Simple Dynamic Programming IV</title><content type='html'>After my last &lt;a href="http://steamcode.blogspot.com/2010/01/ruby-and-simple-dynamic-programming-iii.html"&gt;post&lt;/a&gt;, Gregory Brown, the author of &lt;a href="http://www.amazon.com/Ruby-Best-Practices-Gregory-Brown/dp/0596523009/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1263995503&amp;amp;sr=8-1"&gt;Ruby Best Practices&lt;/a&gt; wrote in to note that not only was &lt;code&gt;eval&lt;/code&gt; evil, it was not ever really necessary. He suggested that the &lt;code&gt;attr_r&lt;/code&gt;, &lt;code&gt;attr_w&lt;/code&gt;, and &lt;code&gt;attr_rw&lt;/code&gt; could be better implemented by using &lt;code&gt;define_method&lt;/code&gt;, &lt;code&gt;instance_variable_get&lt;/code&gt;, and &lt;code&gt;instance_variable_set&lt;/code&gt;. So, as I like to do after someone smart shows me a better way of doing things, I reimplemented our last piece of code using these methods. It's really pretty straightforward so there's not much to really talk about, so here it is:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='ruby' lang='ruby'&gt;&lt;span class='comment'&gt;# Open the class Class and add three new access methods, access_r, access_w, access_rw.&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# These are really just reimplementations for attr_reader, attr_writer, attr_accessor.&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# This version will use define_method, instance_variable_get, &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# and instance_variable_set to do this (based on a recommendation from Gregory Brown.&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;Class&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Provide read access only. Take a list of symbols and create a &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# method that will all the user to access each symbol.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;access_r&lt;/span&gt;&lt;span class='punct'&gt;(*&lt;/span&gt;&lt;span class='ident'&gt;symbols&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;symbols&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;each&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt; &lt;span class='punct'&gt;|&lt;/span&gt;&lt;span class='ident'&gt;symbol&lt;/span&gt;&lt;span class='punct'&gt;|&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;define_method&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;symbol&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;  &lt;br /&gt;                &lt;span class='ident'&gt;instance_variable_get&lt;/span&gt;&lt;span class='punct'&gt;(&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;@&lt;span class='expr'&gt;#{symbol}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;)&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;end&lt;/span&gt;        &lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Provide write access only. Take a list of symbols and create a &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# method that will all the user to write each symbol.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;access_w&lt;/span&gt;&lt;span class='punct'&gt;(*&lt;/span&gt;&lt;span class='ident'&gt;symbols&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;symbols&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;each&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt; &lt;span class='punct'&gt;|&lt;/span&gt;&lt;span class='ident'&gt;symbol&lt;/span&gt;&lt;span class='punct'&gt;|&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;define_method&lt;/span&gt;&lt;span class='punct'&gt;(&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;&lt;span class='expr'&gt;#{symbol}&lt;/span&gt;=&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;)&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt; &lt;span class='punct'&gt;|&lt;/span&gt;&lt;span class='ident'&gt;val&lt;/span&gt;&lt;span class='punct'&gt;|&lt;/span&gt; &lt;br /&gt;                &lt;span class='ident'&gt;instance_variable_set&lt;/span&gt;&lt;span class='punct'&gt;(&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;@&lt;span class='expr'&gt;#{symbol}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;,&lt;/span&gt; &lt;span class='ident'&gt;val&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Provide read/write access. Take a list of symbols and create two&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# methods that will all the user to read and write each symbol.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;access_rw&lt;/span&gt;&lt;span class='punct'&gt;(*&lt;/span&gt;&lt;span class='ident'&gt;symbols&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;symbols&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;each&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt; &lt;span class='punct'&gt;|&lt;/span&gt;&lt;span class='ident'&gt;symbol&lt;/span&gt;&lt;span class='punct'&gt;|&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;define_method&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;symbol&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;  &lt;br /&gt;                &lt;span class='ident'&gt;instance_variable_get&lt;/span&gt;&lt;span class='punct'&gt;(&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;@&lt;span class='expr'&gt;#{symbol}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;)&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;end&lt;/span&gt;        &lt;br /&gt;&lt;br /&gt;            &lt;span class='ident'&gt;define_method&lt;/span&gt;&lt;span class='punct'&gt;(&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;&lt;span class='expr'&gt;#{symbol}&lt;/span&gt;=&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;)&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt; &lt;span class='punct'&gt;|&lt;/span&gt;&lt;span class='ident'&gt;val&lt;/span&gt;&lt;span class='punct'&gt;|&lt;/span&gt; &lt;br /&gt;                &lt;span class='ident'&gt;instance_variable_set&lt;/span&gt;&lt;span class='punct'&gt;(&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;@&lt;span class='expr'&gt;#{symbol}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;,&lt;/span&gt; &lt;span class='ident'&gt;val&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='constant'&gt;__FILE__&lt;/span&gt; &lt;span class='punct'&gt;==&lt;/span&gt; &lt;span class='global'&gt;$PROGRAM_NAME&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Using the new attribute accessor methods.&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;Foo&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;access_r&lt;/span&gt; &lt;span class='symbol'&gt;:bar&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;access_w&lt;/span&gt; &lt;span class='symbol'&gt;:qux&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;access_rw&lt;/span&gt; &lt;span class='symbol'&gt;:baz&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='symbol'&gt;:quux&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Since bar is read only from the outside, we&amp;#39;ll just initialize&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# it here.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;initialize&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;bar&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@bar&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;bar&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Since qux is write only, we&amp;#39;ll create a method that lets us view&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# it.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;show_qux&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;qux = &lt;span class='expr'&gt;#{@qux}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Create a new foo and initialize bar (read only) with goodbye.&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Show that we can then access it.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;Foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt; &lt;span class='punct'&gt;(&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;goodbye&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;)&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;foo.bar = &lt;span class='expr'&gt;#{foo.bar}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Set and then access the two variables we set to &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# read/write.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;baz&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;hello&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;foo.baz = &lt;span class='expr'&gt;#{foo.baz}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;quux&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;world&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;foo.quux = &lt;span class='expr'&gt;#{foo.quux}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Set the write only field and then display it using the show_qux&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# method.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;qux&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;test&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;show_qux&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Try to access the write only field for reading. This should&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# fail with an undefined method.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='ident'&gt;foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;qux&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Like I said, it's all pretty straightforward. Also, here's a &lt;a href="http://www.raulparolari.com/Ruby2/attr_accessor"&gt;link&lt;/a&gt; to someone who's done something very similar using the same technique (there's some other good posts in there, so take some time and read a bit of it).&lt;br /&gt;&lt;br /&gt;As always, let me know if you have questions or comments and thanks to Gregory Brown for starting me down this path.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-8752946061927274388?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/8752946061927274388/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/01/ruby-and-simple-dynamic-programming-iv.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/8752946061927274388'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/8752946061927274388'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/01/ruby-and-simple-dynamic-programming-iv.html' title='Ruby and Simple Dynamic Programming IV'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-9176390269103069922</id><published>2010-01-01T11:26:00.000-08:00</published><updated>2010-01-01T12:08:34.819-08:00</updated><title type='text'>Ruby and Simple Dynamic Programming III</title><content type='html'>In my last couple of posts, &lt;a href="http://steamcode.blogspot.com/2009/12/ruby-and-simple-dynamic-programming.html"&gt;here&lt;/a&gt; and &lt;a href="http://steamcode.blogspot.com/2009/12/ruby-and-simple-dynamic-programming-ii.html"&gt;here&lt;/a&gt;, I began talking about dynamic programming using Ruby. In this post, I'm going to continue on the same lines and this time we're going to discuss using the &lt;code&gt;eval&lt;/code&gt; series of methods, specifically &lt;code&gt;class_eval&lt;/code&gt;. Before getting started however, here's a word of warning. Gregory Brown in &lt;a href="http://www.amazon.com/Ruby-Best-Practices-Gregory-Brown/dp/0596523009/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1262374564&amp;sr=1-1"&gt;Ruby Best Practices&lt;/a&gt; describes &lt;code&gt;eval&lt;/code&gt; (and related methods) as "evil". The truth is that you need to be pretty careful about using these methods as they offer ample opportunity for a user to do some pretty bad things to your system. With that said ...&lt;br /&gt;&lt;br /&gt;As you know, Ruby offers three convenience methods for read, write, and read/write access to variables and these are attr_reader, attr_writer, and attr_accessor respectively. Let's take a look at how we could implement these if they hadn't already been thoughtfully provided. &lt;br /&gt;&lt;br /&gt;Here's the code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='ruby' lang='ruby'&gt;&lt;span class='comment'&gt;# Open the class Class and add three new access methods, access_r, access_w, access_rw.&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# These are really just reimplementations for attr_reader, attr_writer, attr_accessor.&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;Class&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Provide read access only. Take a list of symbols and create a &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# method that will all the user to access each symbol.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;access_r&lt;/span&gt;&lt;span class='punct'&gt;(*&lt;/span&gt;&lt;span class='ident'&gt;symbols&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;symbols&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;each&lt;/span&gt; &lt;span class='punct'&gt;{&lt;/span&gt; &lt;span class='punct'&gt;|&lt;/span&gt; &lt;span class='ident'&gt;symbol&lt;/span&gt; &lt;span class='punct'&gt;|&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;class_eval&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;def &lt;span class='expr'&gt;#{symbol}&lt;/span&gt;() @&lt;span class='expr'&gt;#{symbol}&lt;/span&gt;; end&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;br /&gt;        &lt;span class='punct'&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Provide write access only. Take a list of symbols and create a &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# method that will all the user to write each symbol.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;access_w&lt;/span&gt;&lt;span class='punct'&gt;(*&lt;/span&gt;&lt;span class='ident'&gt;symbols&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;symbols&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;each&lt;/span&gt; &lt;span class='punct'&gt;{&lt;/span&gt; &lt;span class='punct'&gt;|&lt;/span&gt; &lt;span class='ident'&gt;symbol&lt;/span&gt; &lt;span class='punct'&gt;|&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;class_eval&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;def &lt;span class='expr'&gt;#{symbol}&lt;/span&gt;=(val) @&lt;span class='expr'&gt;#{symbol}&lt;/span&gt; = val; end&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Provide read/write access. Take a list of symbols and create two&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# methods that will all the user to read and write each symbol.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;access_rw&lt;/span&gt;&lt;span class='punct'&gt;(*&lt;/span&gt;&lt;span class='ident'&gt;symbols&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;symbols&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;each&lt;/span&gt; &lt;span class='punct'&gt;{&lt;/span&gt; &lt;span class='punct'&gt;|&lt;/span&gt; &lt;span class='ident'&gt;symbol&lt;/span&gt; &lt;span class='punct'&gt;|&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;class_eval&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;def &lt;span class='expr'&gt;#{symbol}&lt;/span&gt;() @&lt;span class='expr'&gt;#{symbol}&lt;/span&gt;; end&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;class_eval&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;def &lt;span class='expr'&gt;#{symbol}&lt;/span&gt;=(val) @&lt;span class='expr'&gt;#{symbol}&lt;/span&gt; = val; end&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='constant'&gt;__FILE__&lt;/span&gt; &lt;span class='punct'&gt;==&lt;/span&gt; &lt;span class='global'&gt;$PROGRAM_NAME&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Using the new attribute accessor methods.&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;Foo&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;access_r&lt;/span&gt; &lt;span class='symbol'&gt;:bar&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;access_w&lt;/span&gt; &lt;span class='symbol'&gt;:qux&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;access_rw&lt;/span&gt; &lt;span class='symbol'&gt;:baz&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='symbol'&gt;:quux&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Since bar is read only from the outside, we&amp;#39;ll just initialize&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# it here.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;initialize&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;bar&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@bar&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;bar&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Since qux is write only, we&amp;#39;ll create a method that lets us view&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# it.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;show_qux&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;qux = &lt;span class='expr'&gt;#{@qux}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Create a new foo and initialize bar (read only) with goodbye.&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Show that we can then access it.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;Foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt; &lt;span class='punct'&gt;(&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;goodbye&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;)&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;foo.bar = &lt;span class='expr'&gt;#{foo.bar}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Set and then access the two variables we set to &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# read/write.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;baz&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;hello&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;foo.baz = &lt;span class='expr'&gt;#{foo.baz}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;quux&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;world&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;foo.quux = &lt;span class='expr'&gt;#{foo.quux}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Set the write only field and then display it using the show_qux&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# method.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;qux&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;test&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;show_qux&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Try to access the write only field for reading. This should&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# fail with an undefined method.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='ident'&gt;foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;qux&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;We start out opening Class as this is where we're going to add our new methods, &lt;code&gt;access_r&lt;/code&gt;, &lt;code&gt;access_w&lt;/code&gt;, and &lt;code&gt;access_rw&lt;/code&gt;. We're going to take a list of symbols, represented here with "*symbols" and covert each of the symbols into a new method. For &lt;code&gt;access_r&lt;/code&gt;, we'll loop through the symbols and then generate a method with the name "symbol" that returns symbol. For example if we have a symbol &lt;code&gt;:x&lt;/code&gt;, we'll get a method that looks like &lt;code&gt;def x() @x; end&lt;/code&gt;. The &lt;code&gt;access_rw&lt;/code&gt; will give us, for the same symbol &lt;code&gt;:x&lt;/code&gt;, &lt;code&gt;def x=(val) @x=val; end&lt;/code&gt;. Finally, the &lt;code&gt;access_rw&lt;/code&gt; will give us both methods (there's probably a clean way to refactor this so we don't have duplicated code, but this is left as an exercise for the reader). &lt;br /&gt;&lt;br /&gt;Finally, we create a class Foo, that uses all three access methods and then some code that exercises each one. The final call is a read access to a write only field and should fail with an undefined method.&lt;br /&gt;&lt;br /&gt;As always, let me know if you have any questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-9176390269103069922?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/9176390269103069922/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2010/01/ruby-and-simple-dynamic-programming-iii.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/9176390269103069922'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/9176390269103069922'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2010/01/ruby-and-simple-dynamic-programming-iii.html' title='Ruby and Simple Dynamic Programming III'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-6395912293743815470</id><published>2009-12-26T17:27:00.001-08:00</published><updated>2009-12-27T17:32:11.518-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='dynamic programming'/><title type='text'>Ruby and Simple Dynamic Programming II</title><content type='html'>In my last &lt;a href="http://steamcode.blogspot.com/2009/12/ruby-and-simple-dynamic-programming.html"&gt;post&lt;/a&gt;, we went over using method_missing in Ruby to do some simple dynamic programming. In this post we'll take a look at using the Singleton Class (not the Singleton pattern) to do a bit more dynamic programming. Most of this is a rehash of a couple of great posts by Ola Bini &lt;a href="http://ola-bini.blogspot.com/2006/09/ruby-singleton-class.html"&gt;here&lt;/a&gt; and Peter Jones &lt;a href="http://www.contextualdevelopment.com/articles/2008/ruby-singleton"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So, what is the Singleton Class? A Singleton Class is where methods for an individual object are stored. What's this mean? Let's just look at some code.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='ruby' lang='ruby'&gt;&lt;span class='comment'&gt;# Create a class, Foo, that has a single method bar. We&amp;#39;ll also&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# add a method_missing so that we can see what&amp;#39;s called that &lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;Foo&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;bar&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Called bar&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Put this in so we can see what gets called in foo2 below that&amp;#39;s not available.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;method_missing&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='punct'&gt;*&lt;/span&gt;&lt;span class='ident'&gt;args&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='punct'&gt;&amp;amp;&lt;/span&gt;&lt;span class='ident'&gt;block&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;You tried to call &lt;span class='expr'&gt;#{name}&lt;/span&gt; with &lt;span class='expr'&gt;#{args.inspect}&lt;/span&gt;. There is no method with that name.&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Create a new Foo&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;Foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Call the method that does exist.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;bar&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Add a new method to foo. This method, baz, will be added to &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# foo&amp;#39;s singleton class.&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;foo.baz&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Called baz&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Call the method we just added.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;baz&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Another way to add a new method to foo. This method, baz, will be added to &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# foo&amp;#39;s singleton class.&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='punct'&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='ident'&gt;foo&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;qux&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Called qux&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Call the method we just added.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;qux&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Show that we don&amp;#39;t have either baz or qux for any other Foo objects.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo2&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;Foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo2&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;bar&lt;/span&gt; &lt;span class='comment'&gt;# Should be there&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo2&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;baz&lt;/span&gt; &lt;span class='comment'&gt;# Should not be there&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo2&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;qux&lt;/span&gt; &lt;span class='comment'&gt;# Should not be there&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Add two class methods to Foo.&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;Foo&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='punct'&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='constant'&gt;self&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;quux&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Called quux&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;self.quuux&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Called quuux&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo3&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;Foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo3&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;quux&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;foo3&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;quuux&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='constant'&gt;Foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;quux&lt;/span&gt;&lt;br /&gt;&lt;span class='constant'&gt;Foo&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;quuux&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;First we define a class Foo (here we're going to use metasyntactic variables, a phrase I just learned &lt;a href="http://en.wikipedia.org/wiki/Metasyntactic_variable"&gt;here&lt;/a&gt;). Anyway, class Foo has two methods, bar and method_missing (see &lt;a href="http://steamcode.blogspot.com/2009/12/ruby-and-simple-dynamic-programming.html"&gt;last post&lt;/a&gt;). bar just prints out the fact that it was called and method_missing shows any methods called that aren't available. Nothing too awfully interesting here, we've seen things like this a million times. Next, we'll just create a new Foo called foo and then call the bar method on it. After that, we're going to do something a bit new, we're going to add a new method, baz, to foo (note that we're adding it to the object foo and not the class Foo. We'll call foo.baz to show that it works. Following, we're going to add a method qux using a different syntax, but it will do exactly the same thing as the last addition. Then we're going to call qux on foo to show that it works. Where were these methods added? Well, you can see from the next few statements, that they weren't added to all Foos. The fact is they were added to foo's Singleton Class. The Singleton Class sits between the object foo and its class Foo (see Jones' &lt;a href="http://www.contextualdevelopment.com/articles/2008/ruby-singleton"&gt;post&lt;/a&gt; to see this represented graphically). &lt;br /&gt;&lt;br /&gt;Since a class has a class Class (OK, that may have made very little sense), it makes sense that the class Foo itself might have a Singleton Class and if you guessed that, then you guessed correctly. In the next section, we add a couple of methods using two different techniques to Foo (notice that we just reopen it), as class methods. In the same way as happened above, these methods are added to the Foo Singleton Class. We create a new foo3 variable and show that we can't call these new methods using an instance of foo, then we call them using Foo. &lt;br /&gt;&lt;br /&gt;OK, so all of this is very interesting and ... so what? What can we do with this. Well, one use for the Singleton Class is for mocking (once again shown in Jones' post).&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='ruby' lang='ruby'&gt;&lt;span class='comment'&gt;# Create a class, User, that has a single method get_buy_power. In&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# real life a user would have many, many more methods than this.&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;User&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;get_buy_power&lt;/span&gt;&lt;br /&gt;        &lt;span class='comment'&gt;# Normally, this would be a complex call to &lt;/span&gt;&lt;br /&gt;        &lt;span class='comment'&gt;# the database, but here we&amp;#39;ll just return&lt;/span&gt;&lt;br /&gt;        &lt;span class='comment'&gt;# a random number * 10000.0. This should give&lt;/span&gt;&lt;br /&gt;        &lt;span class='comment'&gt;# us a number between 0 and 10000.&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;rand&lt;/span&gt; &lt;span class='punct'&gt;*&lt;/span&gt; &lt;span class='number'&gt;10000.0&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# A &amp;quot;normal&amp;quot; user. &lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;user_normal&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;user_normal buy power = &lt;span class='expr'&gt;#{user_normal.get_buy_power}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Create a new User&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;user_small_bp&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Change the user_small_bp&amp;#39;s get_buy_power method to return a small value. This will be&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# added to the user_small_bp&amp;#39;s singleton class.&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='punct'&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='ident'&gt;user_small_bp&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;get_buy_power&lt;/span&gt;&lt;br /&gt;        &lt;span class='number'&gt;20.0&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Print out the buy power for the user_small_bp&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;user_small_bp buy power = &lt;span class='expr'&gt;#{user_small_bp.get_buy_power}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Create a new User&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;user_large_bp&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Change the user&amp;#39;s get_buy_power method to return a large value. This will be&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# added to the user&amp;#39;s singleton class.&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='punct'&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='ident'&gt;user_large_bp&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;get_buy_power&lt;/span&gt;&lt;br /&gt;        &lt;span class='number'&gt;200000.0&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Print out the buy power for the user_large_bp&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;user_large_bp buy power = &lt;span class='expr'&gt;#{user_large_bp.get_buy_power}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# We can now use user_small_bp and user_large_bp to run tests on buying stocks &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# without enough buy power or with quite a bit of buy power.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Create a simple OrderManager that will place orders and send orders. The place_order&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# method will check a user&amp;#39;s buy power before sending an order through. If the buy power isn&amp;#39;t&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# large enough, it will simply print a message, otherwise it will send the order and it&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# will also print a message.&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;OrderManager&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;place_order&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='ident'&gt;shares&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='ident'&gt;stock&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='ident'&gt;price&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;get_buy_power&lt;/span&gt; &lt;span class='punct'&gt;&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;price&lt;/span&gt;&lt;span class='punct'&gt;*&lt;/span&gt;&lt;span class='ident'&gt;shares&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;send_order&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;stock&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='ident'&gt;price&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='ident'&gt;shares&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;else&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Not engough buy power for &lt;span class='expr'&gt;#{shares}&lt;/span&gt; of &lt;span class='expr'&gt;#{stock}&lt;/span&gt; at &lt;span class='expr'&gt;#{price}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='ident'&gt;private&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;send_order&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;stock&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='ident'&gt;price&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='ident'&gt;shares&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Order sent for &lt;span class='expr'&gt;#{shares}&lt;/span&gt; of &lt;span class='expr'&gt;#{stock}&lt;/span&gt; at &lt;span class='expr'&gt;#{price}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Create a simple order manager.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;order_manager&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;OrderManager&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Place an order for 200 shares of apple at $210.0 with user_small_bp. This should fail.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;order_manager&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;place_order&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;user_small_bp&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='number'&gt;200&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;AAPL&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;,&lt;/span&gt; &lt;span class='number'&gt;210.0&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Place an order for 200 shares of apple at $210.0 with user_large_bp. This should succeed.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;order_manager&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;place_order&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;user_large_bp&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='number'&gt;200&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;AAPL&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;,&lt;/span&gt; &lt;span class='number'&gt;210.0&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Take a look at the code above. In the world that I live in (stock trading software), users have a certain amount of buy power that they can use to purchase stocks. Normally, this value would come out of the database and would be incremented (selling a stock) and decremented I(buying a stock) with each trade (OK, this sentence is incredibly simplistic, but will do for now). We're going to use Singleton Class to change our get_buy_power method (rather than adding as we did earlier). In one case, we'll give the user very little buy power and in the other, quite a bit more. After that, we'll create simple order manager that will allow us to place an order for a user that will check their buy power before sending it. &lt;br /&gt;&lt;br /&gt;So there you have it, the Singleton Class and its usage. As always, let me know if you have any questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-6395912293743815470?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/6395912293743815470/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2009/12/ruby-and-simple-dynamic-programming-ii.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/6395912293743815470'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/6395912293743815470'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2009/12/ruby-and-simple-dynamic-programming-ii.html' title='Ruby and Simple Dynamic Programming II'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-512868012623167281</id><published>2009-12-16T09:35:00.000-08:00</published><updated>2009-12-16T10:19:53.910-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='dynamic programming'/><title type='text'>Ruby and Simple Dynamic Programming</title><content type='html'>I've been reading"Ruby Best Practices" by Gregory T. Brown and it's well worth checking out for anyone interested in Ruby. I'm in the middle of Chapter 3, "Mastering the Dynamic Toolkit" and thought I'd share a some simple bits of code that actually use dynamic programming.&lt;br /&gt;&lt;br /&gt;We actually make use of the fact that with Ruby you can add a &lt;code&gt;method_missing&lt;/code&gt; method to any class that allows you to capture calls to any method that are ... well missing. Here's a simple example that shows how it works.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='ruby' lang='ruby'&gt;&lt;span class='comment'&gt;# Create a class with the method_missing method. If a method &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# is called on this class and it&amp;#39;s not found, then this method&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# will be called. We&amp;#39;ll then print whatever was passed in along&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# with the fact that it&amp;#39;s not there.&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;MM&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;x&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Called x&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;y&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Called y&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;method_missing&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='punct'&gt;*&lt;/span&gt;&lt;span class='ident'&gt;args&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='punct'&gt;&amp;amp;&lt;/span&gt;&lt;span class='ident'&gt;block&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;You tried to call &lt;span class='expr'&gt;#{name}&lt;/span&gt; with &lt;span class='expr'&gt;#{args.inspect}&lt;/span&gt;. There is no method with that name.&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='constant'&gt;__FILE__&lt;/span&gt; &lt;span class='punct'&gt;==&lt;/span&gt; &lt;span class='global'&gt;$PROGRAM_NAME&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Create a new MM&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;mm&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;MM&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Call the two mehtods that do exist.&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;mm&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;x&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;mm&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;y&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Call z (which doesn&amp;#39;t exist) both with and without &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# paramaters.&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;mm&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;z&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;mm&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;z&lt;/span&gt; &lt;span class='number'&gt;1&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='number'&gt;2&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='number'&gt;3&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This code creates a simple class called MM with three methods, &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, and &lt;code&gt;method_missing&lt;/code&gt;. The first two only print out the fact that they were called and the third will print out any other method that gets called, say &lt;code&gt;z 1,2, 3&lt;/code&gt; and will print out the name and parameters that get passed in to it. The main code just creates a new &lt;code&gt;MM&lt;/code&gt; and calls a few methods (existing and not) on it.&lt;br /&gt;&lt;br /&gt;Admittedly, this isn't too awfully interesting, but in our next example, we'll actually use &lt;code&gt;method_missing&lt;/code&gt; to save ourselves some work. Here's the second bit of code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='ruby' lang='ruby'&gt;&lt;span class='comment'&gt;# Create a class MM1. The x and y methods require calling&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# setup before and teardown after. This means that everytime&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# we have to add a new method (say z()), we end up having to&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# duplicate this code. &lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;MM1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;setup&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Setup&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;teardown&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Tear down&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;x&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;setup&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Called x&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;teardown&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;y&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;setup&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Called y&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;teardown&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Create a class with the method_missing method. Here we&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# still require x and y to have setup and teardown called, but&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# we wrap it in method_missing as setup_x_teardown or setup_y_teardown.&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# This allows us to also add z without having to worry about remembering&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# the setup/teardown.&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;MM2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;setup&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Setup&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;teardown&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Tear down&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# The method_missing() does all of the work here. We check if the &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# name is setup_something_teardown and if it is, we call setup,&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# call something with the parameters passed in, and then call teardown.&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# If the method isn&amp;#39;t of this form, we just pass it along.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;method_missing&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='punct'&gt;*&lt;/span&gt;&lt;span class='ident'&gt;args&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='punct'&gt;&amp;amp;&lt;/span&gt;&lt;span class='ident'&gt;block&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;case&lt;/span&gt; &lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;when&lt;/span&gt; &lt;span class='punct'&gt;/&lt;/span&gt;&lt;span class='regex'&gt;^setup_(.*)_teardown&lt;/span&gt;&lt;span class='punct'&gt;/&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;setup&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;send&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='global'&gt;$1&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='punct'&gt;*&lt;/span&gt;&lt;span class='ident'&gt;args&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='punct'&gt;&amp;amp;&lt;/span&gt; &lt;span class='ident'&gt;block&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt; &lt;br /&gt;            &lt;span class='ident'&gt;teardown&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;else&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;super&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;x&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Called x&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;y&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;puts&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Called y&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='constant'&gt;__FILE__&lt;/span&gt; &lt;span class='punct'&gt;==&lt;/span&gt; &lt;span class='global'&gt;$PROGRAM_NAME&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Create a new MM1&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;mm1&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;MM1&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Call the two mehtods that do exist.&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;mm1&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;x&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;mm1&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;y&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Create a new MM2&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;mm2&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;MM2&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;mm2&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;setup_x_teardown&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;mm2&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;setup_y_teardown&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There's two classes here that both "do" the same thing. The first class &lt;code&gt;MM1&lt;/code&gt; has two methods, &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; that require a &lt;code&gt;setup&lt;/code&gt; before they are called and a &lt;code&gt;teardown&lt;/code&gt; after they are called.&lt;br /&gt;&lt;br /&gt;The second class, &lt;code&gt;MM2&lt;/code&gt;, has the same requirements, but we're going to handle them a bit differently. We have the same &lt;code&gt;setup&lt;/code&gt; and &lt;code&gt;teardown&lt;/code&gt;, but we don't have &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; call them directly. Instead we use  &lt;code&gt;method_missing&lt;/code&gt; to handle the &lt;code&gt;setup&lt;/code&gt; and &lt;code&gt;teardown&lt;/code&gt;. What we're going to do is use &lt;code&gt;method_missing&lt;/code&gt; and then check the name parameter. If it matches something that looks like &lt;code&gt;setup_X_teardown&lt;/code&gt;, then we'll call &lt;code&gt;setup&lt;/code&gt;, call the method using &lt;code&gt;send&lt;/code&gt;, and finally, call &lt;code&gt;teardown&lt;/code&gt;. If we don't match the pattern, then we just pass the call up the chain. The main code here creates both an &lt;code&gt;MM1&lt;/code&gt; and an &lt;code&gt;MM2&lt;/code&gt; and shows a bit of how to use them.&lt;br /&gt;&lt;br /&gt;Here, in this simple example, you probably wouldn't bother with this. In the book Brown gives a much better use case, but this should give you some ideas at least.&lt;br /&gt;&lt;br /&gt;Let me know if you have questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-512868012623167281?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/512868012623167281/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2009/12/ruby-and-simple-dynamic-programming.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/512868012623167281'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/512868012623167281'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2009/12/ruby-and-simple-dynamic-programming.html' title='Ruby and Simple Dynamic Programming'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-8081427070953629910</id><published>2009-11-28T16:09:00.000-08:00</published><updated>2009-11-30T19:59:26.455-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='ramaze'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='search'/><title type='text'>Ramaze - Forgot Password II</title><content type='html'>Edit 2009-11-30&lt;br /&gt;&lt;br /&gt;This in from Jeremy Evans&lt;br /&gt;------------------------------&lt;br /&gt;Looks better, but I recommend a few more changes:&lt;br /&gt;&lt;br /&gt;1) You need to salt your password hashes.  Unsalted hashes are better&lt;br /&gt;than storing the password in plaintext, but most common hash&lt;br /&gt;algorithms probably already have large rainbow tables that will allow&lt;br /&gt;an easy lookup of most passwords given an unsalted hash.&lt;br /&gt;&lt;br /&gt;2) I would recommend at least including random data when generating&lt;br /&gt;the random key for password resets.  Your use of the username and&lt;br /&gt;Time.now makes it guessable if you know roughly when the user&lt;br /&gt;requested/will request a password change.  encrypt_password is a&lt;br /&gt;poorly named method, since you are hashing, not encrypting (encrypting&lt;br /&gt;implies the possibility of decrypting, while hashing is one way).&lt;br /&gt;&lt;br /&gt;3) I generally put a time limit on password resets.  That way if&lt;br /&gt;someone requests one, but then remembers their password and doesn't&lt;br /&gt;change it, they are not vulnerable to someone else changing it next&lt;br /&gt;year.&lt;br /&gt;------------------------------------------------&lt;br /&gt;&lt;br /&gt;So, add the salt for the password, modify the generate_rand_key() to add a random component (possibly just add a #{rand(1000000)} to the end of the string to add in a 6 digit random component, rename encrypt_password to say hash_password, and finally add a time limit. Here, you'll need to add a date to the user table, add a date when you generate_rand_key(), and check this in change_password() when you also test the existence of a user with the key.&lt;br /&gt;&lt;br /&gt;Thanks for the improvements Jeremy.&lt;br /&gt;&lt;br /&gt;------------------------------------------------&lt;br /&gt;&lt;br /&gt;After my &lt;a href="http://steamcode.blogspot.com/2009/11/forgot-password.html"&gt;last post&lt;/a&gt;, I received, as I noted, some rather stern comments on a) saving passwords in plaintext in the database and b) sending them in plaintext via email. So, I decided to fix the example up to make it a bit better. We'll be saving the password as a hash in the database and also when the user forgets their password, we'll send a link to let them change it. One other suggestion was to add a salt for the password hash which is easy enough to do, but I've left it as an exercise for the reader. I should note that some of the ideas in this post were stolen (and I mean that in the good sense) from &lt;a href="http://www.justkez.com/user-authentication-with-ramaze"&gt;JustKez&lt;/a&gt;. This post is definitely worth reading over as are others on the site.&lt;br /&gt;&lt;br /&gt;OK, let's get started. We'll start out with the database migration.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='ruby' lang='ruby'&gt;&lt;span class='comment'&gt;# dbMigration/001_ForgotPassword.rb&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# This is the &amp;quot;new&amp;quot; way to do migrations by using the Class.new form. &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# It means that a new class name is not required and so there is no chance&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# of creating a second class in the migration files that is the same as the &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# first causing problems.&lt;/span&gt;&lt;br /&gt;&lt;span class='constant'&gt;Class&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='constant'&gt;Sequel&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Migration&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;up&lt;/span&gt;&lt;br /&gt;        &lt;span class='comment'&gt;# Create the users table.&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;create_table&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:users&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;primary_key&lt;/span&gt; &lt;span class='symbol'&gt;:id&lt;/span&gt;&lt;br /&gt;            &lt;span class='constant'&gt;String&lt;/span&gt; &lt;span class='symbol'&gt;:user_name&lt;/span&gt;&lt;br /&gt;            &lt;span class='constant'&gt;String&lt;/span&gt; &lt;span class='symbol'&gt;:password&lt;/span&gt;&lt;br /&gt;            &lt;span class='constant'&gt;String&lt;/span&gt; &lt;span class='symbol'&gt;:email&lt;/span&gt;&lt;br /&gt;            &lt;span class='constant'&gt;String&lt;/span&gt; &lt;span class='symbol'&gt;:rand_key&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;down&lt;/span&gt;&lt;br /&gt;        &lt;span class='comment'&gt;# Remove the two tables.&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;drop_table&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:users&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This is a bit simpler than in the previous example. We're only going to have a users table with the user_name, password (which will be encrypted), an email address, and a random key (used for sending the user their password).  The down method will just drop the users table. To generate the password, simply type &lt;kbd&gt;sequel -M dbMigration/ sqlite://forgot.db&lt;/kbd&gt;. This will create the database we'll use for the project.&lt;br /&gt;&lt;br /&gt;The model for this is pretty simple too.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='ruby' lang='ruby'&gt;&lt;span class='comment'&gt;# models/models.rb&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Create the User model. Each user can have a single challenge question.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;require&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;digest/sha1&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;User&lt;/span&gt; &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt; &lt;span class='constant'&gt;Sequel&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Model&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Return an encrypted password based on the one passed in.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;self.encrypt_password&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='constant'&gt;Digest&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;SHA1&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;hexdigest&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Generate a random key based on the username and the current time in&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# rand_key and save the model back to the database. We&amp;#39;ll use this to email&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# the user so that they can changer their password.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;generate_rand_key&lt;/span&gt;&lt;br /&gt;        &lt;span class='constant'&gt;self&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;rand_key&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;Digest&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;SHA1&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;hexdigest&lt;/span&gt;&lt;span class='punct'&gt;(&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;&lt;span class='expr'&gt;#{@username}&lt;/span&gt; -- &lt;span class='expr'&gt;#{Time.now}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;save&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The only model we have is for the User. We have a couple of methods. The first is a Class level method for encrypting the password. We create a hash of the password using SHA1 and return the value (it will be used for creation of the user and changing the password). The second method is for generating a random key which will be passed as part of a link to the user in case they forget or lose their password.&lt;br /&gt;&lt;br /&gt;Here's our start code&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='ruby' lang='ruby'&gt;&lt;span class='comment'&gt;# start.rb&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# This is the main program for the example. It loads the Sequel database,&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# loads the controllers and models, and then starts up Ramaze. &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# The database should have been set up using the database migrations in&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# the dbMigration directory. &lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;require&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;rubygems&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;require&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;ramaze&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;require&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;sequel&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Required for mailing.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;require&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;net/smtp&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;require&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;mailit&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Create the mailer.&lt;/span&gt;&lt;br /&gt;&lt;span class='constant'&gt;MAILER&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;Mailit&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Mailer&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:server&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;MailServer.MyCompany.COM&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;,&lt;/span&gt; &lt;span class='symbol'&gt;:port&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='number'&gt;25&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='symbol'&gt;:username&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;ApplicationName&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;,&lt;/span&gt; &lt;br /&gt;                            &lt;span class='symbol'&gt;:password&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;ApplicationPassword&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Open the forgot password database. This must be done before we access the&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# models that use it.&lt;/span&gt;&lt;br /&gt;&lt;span class='constant'&gt;DB&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;Sequel&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;sqlite&lt;/span&gt;&lt;span class='punct'&gt;(&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;forgot.db&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;)&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Load the controllers and models.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;require&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;models/models&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;require&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;controllers/main_controller&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Start Ramaze.&lt;/span&gt;&lt;br /&gt;&lt;span class='constant'&gt;Ramaze&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;start&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This is pretty much the same as most of our start files. We add in the code for mailit, open the database, and then require our models and controllers. Finally, we start ramaze.&lt;br /&gt;&lt;br /&gt;Next up our only controller.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='ruby' lang='ruby'&gt;&lt;span class='comment'&gt;# controllers/main_controller.rb&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# The mainController has a single method index. First map to / for &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# the view. Next, set the layout to page so that we use the layout/page.xhtml for our &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# layout. &lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;MainController&lt;/span&gt; &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt; &lt;span class='constant'&gt;Ramaze&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Controller&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# The Main controller will be accessed using &amp;quot;main&amp;quot; as in:&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# http://localhost:7000/main.&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;map&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;/&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Use page.xhtml in the layout directory for layout except &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# for when we&amp;#39;re doing AJAX.&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;layout&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:page&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt; &lt;span class='punct'&gt;{&lt;/span&gt; &lt;span class='punct'&gt;!&lt;/span&gt;&lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;xhr?&lt;/span&gt; &lt;span class='punct'&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Set up a helper to check if we&amp;#39;re logged in and only allow access&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# to the :logged_in page if we are. This is probably the hard way to &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# do this for only the single page but will make much more sense if &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# we add more pages as we&amp;#39;d do in a real application.&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;helper&lt;/span&gt; &lt;span class='symbol'&gt;:aspect&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;before&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:account_settings&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='symbol'&gt;:main&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt; &lt;span class='punct'&gt;{&lt;/span&gt; &lt;br /&gt;        &lt;span class='keyword'&gt;unless&lt;/span&gt; &lt;span class='ident'&gt;logged_in?&lt;/span&gt; &lt;br /&gt;            &lt;span class='comment'&gt;# Set the flash message which will only be available in the next&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# screen. In this case that will be the logged_in screen.&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;flash&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:message&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;You must log in before accessing the requested page.&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:index&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# You can access it now with http://localhost:7000/&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;index&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@title&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;SteamCode - User&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Placeholder for real content.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;main&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;&amp;lt;h2&amp;gt;Main&amp;lt;/h2&amp;gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Placeholder for real content.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;about&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;&amp;lt;h2&amp;gt;About&amp;lt;/h2&amp;gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Placeholder for real content.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;help&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;&amp;lt;h2&amp;gt;User Help&amp;lt;/h2&amp;gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Register a new user with SteamCode. We will get here from the&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# views/register.xhtml page where the user will put in their (requested)&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# login, password, and email address.  First find if the user already&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# exists, if it does, then we&amp;#39;ll set a message to tell the user so and&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# redirect them back to the register screen. If not, we&amp;#39;ll go ahead and add&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# them to the database with the appropriate login, password, and email&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# address. We&amp;#39;ll then send them to the login screen to let them log in to&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# SteamCode.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;register&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@title&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Register with SteamCode&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class='comment'&gt;# Make sure we&amp;#39;re getting here from a post request.&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;post?&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# Check the login and password.&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# if we find the Account based on the login and password. If we find it&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# we&amp;#39;ll save the login ID in the session variable and we can use that&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# to show if the Account is currently logged in or not. If we can&amp;#39;t&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# find the Account, we&amp;#39;ll set the flash message, set the session to nil&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# and just stay on this page.&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;unless&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;find&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt;&lt;span class='punct'&gt;])&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# This account does not exist. Grab the user_name, the password,&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# and the email and create a new Account with them.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;user_name&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;password&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:password&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;email&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:email&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Create the account with the user_name, password, and email given.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;user&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;create&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;user_name&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='symbol'&gt;:password&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;encrypt_password&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;),&lt;/span&gt; &lt;span class='symbol'&gt;:email&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;email&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;                &lt;span class='constant'&gt;Ramaze&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Log&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;debug&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;New User Added: user_name = &lt;span class='expr'&gt;#{user.user_name}&lt;/span&gt; password = &lt;span class='expr'&gt;#{user.password}&lt;/span&gt; email = &lt;span class='expr'&gt;#{user.email}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Redirect to the login page.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:login&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;else&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# This user already exists. Set the flash message for them to&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# try again.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;flash&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:message&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Login &lt;span class='expr'&gt;#{request[:user_name]}&lt;/span&gt; already used. Please select another.&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;                &lt;br /&gt;                &lt;span class='comment'&gt;# Stay on the register page.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:register&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Login to Steamcode. If the request is a post, then we&amp;#39;ll try to find the&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# user. If we succeed then we&amp;#39;ll set some session variables and redirect to&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# the main page (which the user can only access if they&amp;#39;re logged in). If they&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# can&amp;#39;t be logged in, we&amp;#39;ll set a flash message, reset the session, and redirect&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# back to the login page.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;login&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@title&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Login to SteamCode&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;post?&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;user&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;find&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt;&lt;span class='punct'&gt;],&lt;/span&gt; &lt;span class='symbol'&gt;:password&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;encrypt_password&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:password&lt;/span&gt;&lt;span class='punct'&gt;]))&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Use the name= portion of the input form to grab the data&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# from the request variable and save it in the session&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# hash table.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_id&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;id&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;user_name&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Redirect to the main screen.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:main&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;else&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# The login could not be authorized. Set the flash message&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# and stay on this page (index/login). Set the session loginID &lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# to nil also. This will effectively log the user out. This would &lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# be reasonable if they are logged in and then try to log in with&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# a new login/password.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;flash&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:message&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Incorrect user name or password, please try again!!!&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_id&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;nil&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;nil&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Stay on the login page.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:login&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;       &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Let the user change account settings. For now this is&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# just the email and password.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;account_settings&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@title&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Account Settings for SteamCode&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;user&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_id&lt;/span&gt;&lt;span class='punct'&gt;]]&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;post?&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;user&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_id&lt;/span&gt;&lt;span class='punct'&gt;]]&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;email&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:email&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;password&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;encrypt_password&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:password&lt;/span&gt;&lt;span class='punct'&gt;])&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;save&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;flash&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:message&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;New email and/or password saved.&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:main&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@current_email&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;email&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Logout of the system. Set the flash message and then&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# set the session values to nil. Finally, redirect back to the &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# index page.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;logout&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@title&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Logout from SteamCode&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;flash&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:message&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;&lt;span class='expr'&gt;#{session[:user_name]}&lt;/span&gt; Logged out&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_id&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;nil&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;nil&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:index&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# The user has requested that we email their password back to them. Generate&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# a random key and email it to them to allow them to change their password.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;forgot_password&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;post?&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# Final submit.&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;user&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;find&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt;&lt;span class='punct'&gt;])&lt;/span&gt;&lt;br /&gt;                &lt;br /&gt;                &lt;span class='comment'&gt;# Generate a key and associate it with the user_name.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;generate_rand_key&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Create the mail message and fill it in with the appropriate&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# information (to/from/subject/text). Then send it off.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;mail&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;Mailit&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Mail&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;mail&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;to&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;email&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;mail&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;from&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Steamcode@MyCompany.com&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;mail&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;subject&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Steamcode Password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;mail&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;text&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;To change your password: http://localhost:7000/change_password/&lt;span class='expr'&gt;#{user.rand_key}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Send the mail message via the MAILER (created in start.rb).&lt;/span&gt;&lt;br /&gt;                &lt;span class='constant'&gt;MAILER&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;send&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;mail&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Just go back to the login page.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:login&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;else&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;flash&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:message&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Could not find user: &lt;span class='expr'&gt;#{request[:user_name]}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Could not find user with this user_name.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:forgot_password&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# The key will be the key that we created above when the user asked&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# for the password change. It will be passed as a parameter when the user&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# clicks on the link that was emailed to them.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;change_password&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;key&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='comment'&gt;# Check to make sure that there&amp;#39;s a user with this key.&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;user&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;find&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:rand_key&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;key&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;user&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;post?&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# We got here from a post and there&amp;#39;s a user with the key. Go ahead&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# and a) change the password, b) reset the random key, and c) save&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# the new user information. Then set the flash message and put them &lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# on the login screen.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;password&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;encrypt_password&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:password&lt;/span&gt;&lt;span class='punct'&gt;])&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;rand_key&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;nil&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;save&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;flash&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:message&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Your new password saved.&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:login&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;else&lt;/span&gt; &lt;br /&gt;            &lt;span class='comment'&gt;# There wasn&amp;#39;t a user with this random key. Just flash a message&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# and then redirect to the login screen.&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;flash&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:message&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;This does not appear to be a valid request.&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:login&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='ident'&gt;private&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# If the user is logged in, the session will&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# contain a non nil user id.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;logged_in?&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_id&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;!=&lt;/span&gt; &lt;span class='constant'&gt;nil&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This is very similar to many of our other controllers from our past posts. We map to '/', Add the layout (which won't be used for AJAX calls (not used here anyway)), and then the aspect which will prevent the user from going to certain pages unless they're logged in to the system. The next four methods, index, main, about, and help are really just place holders. Index is where the user will end up initially and main is where they will end up after logging in. Then we have the register page. This will check if it's a post and if it is, try to find the user. If it can't find the user (note the use of "unless" here. To a certain extend, I'm trying to decide if it helps or hinder readability. Let me know what you think) it will create a new one with the parameters from the request hash. If the user already exists, we'll just flash a message back and redirect them back to the register page. Next we have the login method. We check to make sure this is from a post, then check to see if we can find the user based on their user name and password (using the model's encrypt_password method). If we find them, we go ahead and log them in (set the session variables) and redirect them to the main page. If not, we flash a message, reset the session variables, and redirect them back to the login page. The account_settings page let's the user reset their email and password. The logout page resets the session variables and then redirects back to the index page. Looking at it now, I'd recommend refactoring the session resets here and in login to their own private method (once again we'll leave that as an exercise). The forgot_password method is the reason for all of this. We check that it's a post and contains a valid user. If so, we generate a random key for the user (using the model method) and then create an email with the link containing this key. If we can't find the user, we'll flash a message and redirect back to the same page. Finally (for the pages anyway), we have the change_password page. This checks to see if we have user with this rand_key (from the link generated above) and if we do, we check if this is a post and change their password appropriately, reset the random key (so it's used only once), flash a message and redirect them back to the login page. If there wasn't a user with that random key, we simply flash a message and redirect them back to the login page. Finally, we have the private method that's used to check if a user is logged in to the system.&lt;br /&gt;&lt;br /&gt;Here's our layout page.xhtml&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='xml' lang='xml'&gt;&lt;span class='comment'&gt;&amp;lt;!-- view/page.xhtml --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;!&lt;/span&gt;&lt;span class='tag'&gt;DOCTYPE&lt;/span&gt; &lt;span class='attribute'&gt;html&lt;/span&gt; &lt;span class='attribute'&gt;PUBLIC&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;html&lt;/span&gt; &lt;span class='attribute'&gt;xmlns&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;http://www.w3.org/1999/xhtml&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;head&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt; &lt;br /&gt;        &lt;span class='comment'&gt;&amp;lt;!-- Use the page.css in the public directory and set title based on&lt;br /&gt;        what&amp;#39;s set in the associated method.&lt;br /&gt;        --&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;link&lt;/span&gt; &lt;span class='attribute'&gt;rel&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;stylesheet&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;text/css&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;href&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;/page.css&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;title&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;#@title&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;title&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;head&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;body&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;whole_page&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;header&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;h1&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;SteamCode&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;h1&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;nav&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;&amp;lt;!-- Main/User controller --&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;&amp;lt;!-- Move this next section over to the right side of the screen. It&lt;br /&gt;                will contain the Login/Register if we&amp;#39;re not logged in and the Logout&lt;br /&gt;                if we are.  --&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;span&lt;/span&gt; &lt;span class='attribute'&gt;style&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;float: right&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class='comment'&gt;&amp;lt;!-- We&amp;#39;re going to use the private method logged_in? here to test if &lt;br /&gt;                    we want to show the Login/Register links or the Logout link --&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class='punct'&gt;&amp;lt;?&lt;/span&gt;&lt;span class='tag'&gt;r&lt;/span&gt; &lt;span class='attribute'&gt;if&lt;/span&gt; !&lt;span class='attribute'&gt;logged_in?&lt;/span&gt; &lt;span class='punct'&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;                        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt; &lt;span class='attribute'&gt;href&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;#{r(:login)}&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Login&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt; &lt;span class='attribute'&gt;href&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;#{r(:register)}&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Register&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class='punct'&gt;&amp;lt;?&lt;/span&gt;&lt;span class='tag'&gt;r&lt;/span&gt; &lt;span class='attribute'&gt;else&lt;/span&gt; &lt;span class='punct'&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;                        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt; &lt;span class='attribute'&gt;href&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;#{r(:account_settings)}&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Account&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt; &lt;span class='attribute'&gt;href&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;#{r(:logout)}&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Logout&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class='punct'&gt;&amp;lt;?&lt;/span&gt;&lt;span class='tag'&gt;r&lt;/span&gt; &lt;span class='attribute'&gt;end&lt;/span&gt; &lt;span class='punct'&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;span&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;&amp;lt;!-- These next three will be on the left side and always there --&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt; &lt;span class='attribute'&gt;href&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;#{r(:index)}&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Home&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt; |&lt;br /&gt;                &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt; &lt;span class='attribute'&gt;href&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;#{r(:about)}&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;About Us&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt; |&lt;br /&gt;                &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt; &lt;span class='attribute'&gt;href&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;#{r(:help)}&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Help&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;content&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;&amp;lt;!-- Display the actual content. This will come from the method or the&lt;br /&gt;                associated view/*.xhtml file&lt;br /&gt;                --&amp;gt;&lt;/span&gt;&lt;br /&gt;                #@content&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- Set the footer in the center of the screen. --&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;footer&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;style&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;text-align: center;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;h5&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt; Powered by Ramaze &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;h5&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;body&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;html&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It's stripped down a bit from the last post and has all of the administration stuff removed. Since you've seen this in past posts, I won't go through it. It's mostly just code for the navigation with some content and a header and footer tossed in for good measure.&lt;br /&gt;&lt;br /&gt;Let's take a look at the views for the project. They're really simple this time. No JavaScript and no AJAX. Here's the index.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='xml' lang='xml'&gt;#{flashbox}&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;h2&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;Welcome&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;h2&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here's the login page&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='xml' lang='xml'&gt;#{flashbox}&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt; &lt;span class='attribute'&gt;href&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;#{r(:forgot_password)}&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Forgot your password?&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;form&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;login&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;method&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;post&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;fieldset&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;legend&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt; Login &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;legend&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- for= goes with id=, the name= is placed in the request variable. --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- Input for the user_name. --&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt; &lt;span class='attribute'&gt;for&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;user_name&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;User Name:&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;user_name&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;user_name&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;text&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- Input for the user_name. --&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt; &lt;span class='attribute'&gt;for&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Password:&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- Submit the login request.  --&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;submit&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;value&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Login&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;fieldset&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;form&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There's just input boxes for the user name and password and a button for submitting.&lt;br /&gt;&lt;br /&gt;Here's the registration page.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='xml' lang='xml'&gt;&lt;span class='comment'&gt;&amp;lt;!-- view/register.xhtml --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;form&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;register&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;method&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;post&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='comment'&gt;&amp;lt;!-- for= goes with id=, the name= is placed in the request variable. --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class='comment'&gt;&amp;lt;!-- Input for the user_name. --&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt; &lt;span class='attribute'&gt;for&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;user_name&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Login:&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;user_name&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;user_name&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;text&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class='comment'&gt;&amp;lt;!-- Input for the password. --&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt; &lt;span class='attribute'&gt;for&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Password:&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class='comment'&gt;&amp;lt;!-- Input for the email. --&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt; &lt;span class='attribute'&gt;for&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;email&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Email:&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;email&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;email&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;text&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class='comment'&gt;&amp;lt;!-- Submit the new User --&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;submit&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;value&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Register&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;form&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;As above boxes for user name, password, and email plus the submit button.&lt;br /&gt;&lt;br /&gt;Here's the page for changing the account settings.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='xml' lang='xml'&gt;&lt;span class='comment'&gt;&amp;lt;!-- Let&amp;#39;s the user change their email and/or password --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;form&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;change_password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;method&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;post&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;fieldset&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;legend&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt; Change Settings &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;legend&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- Input for the email address. --&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt; &lt;span class='attribute'&gt;for&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;email&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Email:&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;email&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;email&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;text&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;value&lt;/span&gt;&lt;span class='punct'&gt;=#{@&lt;/span&gt;&lt;span class='attribute'&gt;current_email}&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- Input for the password. --&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt; &lt;span class='attribute'&gt;for&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Password:&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;/&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- Submit the new email and/or password --&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;submit&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;value&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Submit&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;fieldset&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;form&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This contains boxes for password and email (the user can't change their user_name) and the submit button.&lt;br /&gt;&lt;br /&gt;Next is the forgot_password.xhtml.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='xml' lang='xml'&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;h2&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;Forgot Password&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;h2&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;#{flashbox}&lt;br /&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;form&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;forgot_screen&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;method&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;post&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;fieldset&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;legend&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt; Forgot Password &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;legend&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;forgot_password&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- for= goes with id=, the name= is placed in the request variable. --&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- Input for the user_name. --&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt; &lt;span class='attribute'&gt;for&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;user_name&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;User Name:&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;user_name&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;user_name&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;text&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;value&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;User Name&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class='comment'&gt;&amp;lt;!-- Once they&amp;#39;ve put in the challenge answer, they will select --&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='comment'&gt;&amp;lt;!-- this and the system will send their password via email. --&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;submit&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;value&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Send Password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;fieldset&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;form&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This has a box for the user_name and the submit button. When the user puts in their user_name and submits, an email is generated (see above) that provides a link to change their password. This page is the change_password.xhtml.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='xml' lang='xml'&gt;&lt;span class='comment'&gt;&amp;lt;!-- view/register.xhtml --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;form&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;change_password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;method&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;post&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='comment'&gt;&amp;lt;!-- for= goes with id=, the name= is placed in the request variable. --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class='comment'&gt;&amp;lt;!-- Input for the password. --&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt; &lt;span class='attribute'&gt;for&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Password:&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class='comment'&gt;&amp;lt;!-- Submit the new User --&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;submit&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;value&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Change Password.&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;form&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Once again, dead simple with the password box and a submit (you'd probably want a confirmation password that would be checked using JavaScript, but we'll just assume that the user won't make any mistakes.&lt;br /&gt;&lt;br /&gt;That's pretty much everything except for the CSS which is in public/page.css&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#whole_page {&lt;br /&gt;  width: 50em;&lt;br /&gt;  margin: auto;&lt;br /&gt;  padding: 0;&lt;br /&gt;  text-align: left;&lt;br /&gt;  border-width:  0 1px 1px 1px;&lt;br /&gt;  border-color:  black;&lt;br /&gt;  border-style:  solid;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#content {&lt;br /&gt;  height: 100%;&lt;br /&gt;  background:  white;&lt;br /&gt;  padding: 1em 1em 1em 1em;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* Header CSS */&lt;br /&gt;#header {&lt;br /&gt;    background:#9DA9EE;&lt;br /&gt;    color: white;&lt;br /&gt;    margin-bottom: 0;&lt;br /&gt;    padding: 0.25em;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#nav {&lt;br /&gt;    background:#9DA9EE;&lt;br /&gt;    color: black;&lt;br /&gt;    padding: 0.5em;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* Footer CSS */&lt;br /&gt;#footer {&lt;br /&gt;    background:#9DA9EE;&lt;br /&gt;    color: black;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;So, I hope this works out for everyone a bit better than the last version and gets at least a bit closer to what you might use in a "real" project. Let me know if you have questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5746251571102358624-8081427070953629910?l=steamcode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://steamcode.blogspot.com/feeds/8081427070953629910/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://steamcode.blogspot.com/2009/11/ramaze-forgot-password-ii.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/8081427070953629910'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5746251571102358624/posts/default/8081427070953629910'/><link rel='alternate' type='text/html' href='http://steamcode.blogspot.com/2009/11/ramaze-forgot-password-ii.html' title='Ramaze - Forgot Password II'/><author><name>slabounty</name><uri>http://www.blogger.com/profile/06122119234374455724</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5746251571102358624.post-2712134897085556776</id><published>2009-11-12T15:16:00.000-08:00</published><updated>2009-11-20T06:18:24.057-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='ramaze'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='sequel'/><title type='text'>Ramaze - Forgot Password (Edited 2009-11-20)</title><content type='html'>Edit: I received some rather stern comments on this post on the Sequel mail list and probably rather deservedly. The primary complaints were that you really shouldn't even be doing this sort of thing as it a) involves saving the user's password as plaintext in the database and b) sending the user's password in plaintext over the internet via email. The solution is to save the user's password as a hash in the database and then provide a link to them for changing the password if requested. I basically agree with the criticism, so use this only for non-critical applications (i.e. don't use if for a banking app.) or better yet, just use some of the techniqes (email, AJAX) without using the whole idea. Thanks to all who commented to set me straight.&lt;br /&gt;&lt;br /&gt;-----------------------------------------------------&lt;br /&gt;&lt;br /&gt;For a recent project, I was looking at how to notify the user if they forgot their password. I'd initially thought the interesting piece would be the email part, but really, not so much. Let's start there though. The first thing you'll need to add that we haven't before is install Michael Fellinger's (Manveru) Mailit. So ...&lt;br /&gt;&lt;kbd&gt;sudo gem install mailit&lt;/kbd&gt;&lt;br /&gt;&lt;br /&gt;With that taken care of, let's take a look at our database migrations. There's two of them since I added the admins table later. Here's the first one&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='ruby' lang='ruby'&gt;&lt;span class='comment'&gt;# dbMigration/001_ForgotPassword.rb&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# This is the &amp;quot;new&amp;quot; way to do migrations by using the Class.new form. &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# It means that a new class name is not required and so there is no chance&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# of creating a second class in the migration files that is the same as the &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# first causing problems.&lt;/span&gt;&lt;br /&gt;&lt;span class='constant'&gt;Class&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='constant'&gt;Sequel&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Migration&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;up&lt;/span&gt;&lt;br /&gt;        &lt;span class='comment'&gt;# Create the users table.&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;create_table&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:users&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;primary_key&lt;/span&gt; &lt;span class='symbol'&gt;:id&lt;/span&gt;&lt;br /&gt;            &lt;span class='constant'&gt;String&lt;/span&gt; &lt;span class='symbol'&gt;:user_name&lt;/span&gt;&lt;br /&gt;            &lt;span class='constant'&gt;String&lt;/span&gt; &lt;span class='symbol'&gt;:password&lt;/span&gt;&lt;br /&gt;            &lt;span class='constant'&gt;String&lt;/span&gt; &lt;span class='symbol'&gt;:email&lt;/span&gt;&lt;br /&gt;            &lt;span class='constant'&gt;String&lt;/span&gt; &lt;span class='symbol'&gt;:challenge_answer&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;foreign_key&lt;/span&gt; &lt;span class='symbol'&gt;:challenge_question_id&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='symbol'&gt;:challenge_questions&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class='comment'&gt;# Create the challenge questions table.&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;create_table&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:challenge_questions&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;primary_key&lt;/span&gt; &lt;span class='symbol'&gt;:id&lt;/span&gt;&lt;br /&gt;            &lt;span class='constant'&gt;String&lt;/span&gt; &lt;span class='symbol'&gt;:question&lt;/span&gt; &lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;down&lt;/span&gt;&lt;br /&gt;        &lt;span class='comment'&gt;# Remove the two tables.&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;drop_table&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:users&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='symbol'&gt;:challenge_questions&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here we create a user table that has a user_name, password, email, and a challenge_response.  It also has a foreign key to the challenge_questions table for the challenge question. The challenge_question table contains a list of potential questions that the user can select. This will be handled as a drop down when they register for the site.&lt;br /&gt;&lt;br /&gt;The second migration script contains the admins table. For this application, about the only thing an admin can do is add more challenge questions. We'll also add in an admin since we don't have another way of doing it in this application. Here we'll give the admin the name "admin" (clever) and a password "helloworld" (better anyway), and an email address that's never used.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='ruby' lang='ruby'&gt;&lt;span class='comment'&gt;# dbMigration/002_ForgotPasswordMigration.rb&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# This is the &amp;quot;new&amp;quot; way to do migrations by using the Class.new form. &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# It means that a new class name is not required and so there is no chance&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# of creating a second class in the migration files that is the same as the &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# first causing problems.&lt;/span&gt;&lt;br /&gt;&lt;span class='constant'&gt;Class&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='constant'&gt;Sequel&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Migration&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;up&lt;/span&gt;&lt;br /&gt;        &lt;span class='comment'&gt;# Add in the admins table for administrators.&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;create_table&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:admins&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;primary_key&lt;/span&gt; &lt;span class='symbol'&gt;:id&lt;/span&gt;&lt;br /&gt;            &lt;span class='constant'&gt;String&lt;/span&gt; &lt;span class='symbol'&gt;:admin_name&lt;/span&gt;&lt;br /&gt;            &lt;span class='constant'&gt;String&lt;/span&gt; &lt;span class='symbol'&gt;:password&lt;/span&gt;&lt;br /&gt;            &lt;span class='constant'&gt;String&lt;/span&gt; &lt;span class='symbol'&gt;:email&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;        &lt;br /&gt;        &lt;span class='comment'&gt;# Add in an administrator.&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;from&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:admins&lt;/span&gt;&lt;span class='punct'&gt;).&lt;/span&gt;&lt;span class='ident'&gt;insert&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:admin_name&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;admin&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;,&lt;/span&gt; &lt;span class='symbol'&gt;:password&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;helloworld&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;,&lt;/span&gt; &lt;span class='symbol'&gt;:email&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;admin@company.com&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;down&lt;/span&gt;&lt;br /&gt;        &lt;span class='comment'&gt;# Remove the administrators table.&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;drop_table&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:admins&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;We run our migrations with the following:&lt;br /&gt;&lt;br /&gt;&lt;kbd&gt;sequel -m dbMigration/ sqlite://forgot.db&lt;/kbd&gt;&lt;br /&gt;&lt;br /&gt;The models we use for this project are pretty simple. The User model just states that it's many_to_one with the challenge questions (many users can have the same challenge question). The Admin model is about as simple as it gets (empty). The ChallengeQuestion model has the one_to_many with users (one challenge question can be associated with many users). It also has the self.questions method which will return all of the challenge questions in the database and their associated ids. This will be used by the registration page to allow the user to select one challenge question from a drop down.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='ruby' lang='ruby'&gt;&lt;span class='comment'&gt;# Create the User model. Each user can have a single challenge question.&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;User&lt;/span&gt; &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt; &lt;span class='constant'&gt;Sequel&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Model&lt;/span&gt; &lt;br /&gt;    &lt;span class='ident'&gt;many_to_one&lt;/span&gt; &lt;span class='symbol'&gt;:challenge_question&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Create the Challenge_Question model. Multiple users can have a single&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# challenge question.&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;ChallengeQuestion&lt;/span&gt; &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt; &lt;span class='constant'&gt;Sequel&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Model&lt;/span&gt; &lt;br /&gt;    &lt;span class='ident'&gt;one_to_many&lt;/span&gt; &lt;span class='symbol'&gt;:users&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Will return an array of all of the questions.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;self.questions&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;select&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:id&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='symbol'&gt;:question&lt;/span&gt;&lt;span class='punct'&gt;).&lt;/span&gt;&lt;span class='ident'&gt;all&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Create the Administrator model. &lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;Admin&lt;/span&gt; &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt; &lt;span class='constant'&gt;Sequel&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Model&lt;/span&gt; &lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So now we're ready to move on to the start.rb file.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='ruby' lang='ruby'&gt;&lt;span class='comment'&gt;# start.rb&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# This is the main program for the example. It loads the Sequel database,&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# loads the controllers and models, and then starts up Ramaze. &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# The database should have been set up using the database migrations in&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# the dbMigration directory. &lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;require&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;rubygems&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;require&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;ramaze&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;require&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;sequel&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Required for mailing.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;require&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;net/smtp&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;require&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;mailit&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Create the mailer.&lt;/span&gt;&lt;br /&gt;&lt;span class='constant'&gt;MAILER&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;Mailit&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Mailer&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:server&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;MailServer.MyCompany.COM&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;,&lt;/span&gt; &lt;span class='symbol'&gt;:port&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='number'&gt;25&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='symbol'&gt;:username&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;ApplicationName&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;,&lt;/span&gt; &lt;span class='symbol'&gt;:password&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;ApplicationPassword&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Open the forgot password database. This must be done before we access the&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# models that use it.&lt;/span&gt;&lt;br /&gt;&lt;span class='constant'&gt;DB&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;Sequel&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;sqlite&lt;/span&gt;&lt;span class='punct'&gt;(&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;forgot.db&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;)&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Load the controllers and models.&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;require&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;models/models&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;require&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;controllers/main_controller&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span class='ident'&gt;require&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;controllers/admin_controller&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='comment'&gt;# Start Ramaze.&lt;/span&gt;&lt;br /&gt;&lt;span class='constant'&gt;Ramaze&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;start&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The difference here from most of our other start.rb files is the addition of the code for the mailer. First we require 'net/smtp' and 'mailit'. The we create the MAILER. We'll pass the server name, the port (will almost certainly be 25), the username, and the password. This will create a mailer that we can then "send" messages to. Next we open the database, forgot.db, and then get the models and the controllers.&lt;br /&gt;&lt;br /&gt;Let's take a look at the admin controller first.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='ruby' lang='ruby'&gt;&lt;span class='comment'&gt;# controllers/admin_controller.rb&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# The AdminController has a single method index. First map to /admin for &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# the view. Next, set the layout to page so that we use the layout/page.xhtml for our &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# layout. Then we use a helper for the :xhtml which will allow us to use &amp;quot;js&amp;quot; in the &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# layout (we use this to generate a javascript link). &lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;AdminController&lt;/span&gt; &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt; &lt;span class='constant'&gt;Ramaze&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Controller&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# The Admin controller will be accessed using &amp;quot;admin&amp;quot; as in:&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# http://localhost:7000/admin.&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;map&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;/admin&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Use page.xhtml in the layout directory for layout&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;layout&lt;/span&gt; &lt;span class='symbol'&gt;:page&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Let&amp;#39;s us put in our &amp;quot;js&amp;quot; lines.&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;helper&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:xhtml&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Set up a helper to check if we&amp;#39;re logged in and only allow access&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# to the :logged_in page if we are. This is probably the hard way to &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# do this for only the single page but will make much more sense if &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# we add more pages as we&amp;#39;d do in a real application.&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;helper&lt;/span&gt; &lt;span class='symbol'&gt;:aspect&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;before&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:main&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='symbol'&gt;:add_challenge&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt; &lt;span class='punct'&gt;{&lt;/span&gt; &lt;br /&gt;        &lt;span class='keyword'&gt;unless&lt;/span&gt; &lt;span class='ident'&gt;logged_in?&lt;/span&gt; &lt;br /&gt;            &lt;span class='comment'&gt;# Set the flash message which will only be available in the next&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# screen. In this case that will be the logged_in screen.&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;flash&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:message&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;You must log in before accessing the requested page.&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:index&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# You can access it now with http://localhost:7000/admin&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;index&lt;/span&gt;&lt;br /&gt;        &lt;span class='constant'&gt;Ramaze&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Log&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;debug&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Enter Admin Index&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@title&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;SteamCode - Administration Home&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;main&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Add a new challenge question for the user to select.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;add_challenge&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;post?&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;challenge_question&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:challenge_question&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt;&lt;br /&gt;            &lt;span class='constant'&gt;ChallengeQuestion&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;create&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:question&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;challenge_question&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Login as an administrator. Figure out if this is a correct login/password&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# pair and log the admin in and redirect ot main if it is. If not, flash&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# a message and redirect back to the login page.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;login&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@title&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Library - Administration - Login&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;       &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;post?&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;admin&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;Admin&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;find&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:admin_name&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:admin_name&lt;/span&gt;&lt;span class='punct'&gt;],&lt;/span&gt; &lt;span class='symbol'&gt;:password&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:password&lt;/span&gt;&lt;span class='punct'&gt;])&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Use the name= portion of the input form to grab the data&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# from the request variable and save it in the session&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# hash table.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:admin_id&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;admin&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;id&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Redirect to the list_all screen.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:main&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;else&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# The login could not be authorized. Set the flash message&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# and stay on this page (index/login). Set the session loginID &lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# to nil also. This will effectively log the user out. This would &lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# be reasonable if they are logged in and then try to log in with&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# a new login/password.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;flash&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:message&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Incorrect user name or password, please try again!!!&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:admin_id&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;nil&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Stay on the login page.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:login&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;       &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Log the administrator out.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;logout&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:admin_id&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;nil&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;flash&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:message&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Admin Logged out&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='constant'&gt;MainController&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;r&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:index&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='ident'&gt;private&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# If the admin is logged in, the session will&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# contain a non nil admin id.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;logged_in?&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:admin_id&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;!=&lt;/span&gt; &lt;span class='constant'&gt;nil&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It starts out with most of the same code as all of our controllers. There's the map command, the layout (here we'll use layout/page.xhtml), the helper for our javascript, the helper for aspect (this will allow us to do before/after commands for selected methods in this controller), the before command which will have us check for being logged in before allowing access to the main page and the add_challenge page. The first method is the index method which is the page that the admin will go to before logging in. This is followed by main which is where the admin will be redirected after login. Next we have the add_challenge method. Here we just grab the question from the request hash (filled in by the add_challenge page input) and create a new ChallengeQuestion from it (also adding it to the database). Next is the login method, which should be pretty familiar from past posts. If we find the admin (and here the only one we have was created by the database migration), we'll set the session admin_id variable and redirect to the main page. If we fail to login the admin, we'll put up a flash message and redirect back to the login page. Next is the logout which just resets the session admin_id, sets a message, and redirects back to the login page. Finally, we have the private method logged_in? which will check if an admin is logged in.&lt;br /&gt;&lt;br /&gt;Let's take a look at the admin views. First we have the view/admin/index.xhtml.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='xml' lang='xml'&gt;#{flashbox}&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;p&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt; Welcome to the Library. This is the Administrator&amp;#39;s section. Please login and administrate.  &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;p&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Nothing too much here, just a note for the user to login.&lt;br /&gt;&lt;br /&gt;Next we have the main view.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='xml' lang='xml'&gt;&lt;span class='comment'&gt;&amp;lt;!-- The only thing here is a link to add a challenge question. --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;h2&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;Enter Admin&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;h2&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt; &lt;span class='attribute'&gt;href&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;#{r(:add_challenge)}&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Add Challenge Question&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This is the page that the admin will see when they log in to the system. Here, there's just a link to the add challenge question page.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='xml' lang='xml'&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;form&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;login&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;method&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;post&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;fieldset&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;legend&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt; Add Challenge &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;legend&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- for= goes with id=, the name= is placed in the request variable. --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- Input for the challenge_question. --&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt; &lt;span class='attribute'&gt;for&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;challenge_question&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;User Name:&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;challenge_question&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;challenge_question&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;text&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- Submit the new challenge question (this should result in it being saved in the database) --&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;submit&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;value&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Add&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;fieldset&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;form&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here we just have the input box for the challenge question and the submit button. This will, as noted above, add a new challenge question to the database.&lt;br /&gt;&lt;br /&gt;Here's the login page.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='xml' lang='xml'&gt;#{flashbox}&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;form&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;login&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;method&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;post&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;fieldset&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;legend&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt; Login &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;legend&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- for= goes with id=, the name= is placed in the request variable. --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- Input for the admin_name. --&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt; &lt;span class='attribute'&gt;for&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;admin_name&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Admin:&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;admin_name&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;admin_name&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;text&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- Input for the password. --&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt; &lt;span class='attribute'&gt;for&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Password:&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- Submit the admin name and password. If accepted, &lt;br /&gt;                 the admin should get logged in. --&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;submit&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;value&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Login&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;fieldset&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;form&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It has input boxes for the admin's admin_name and password as well as the submit button. Once again, nothing very interesting. And the end of the admin pages.&lt;br /&gt;&lt;br /&gt;Let's turn to the user side now. First we have the user controller, controllers/main_controller.rb.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='ruby' lang='ruby'&gt;&lt;span class='comment'&gt;# controllers/main_controller.rb&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# The mainController has a single method index. First map to /admin for &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# the view. Next, set the layout to page so that we use the layout/page.xhtml for our &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# layout. Then we use a helper for the :xhtml which will allow us to use &amp;quot;js&amp;quot; in the &lt;/span&gt;&lt;br /&gt;&lt;span class='comment'&gt;# layout (we use this to generate a javascript link). &lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;class &lt;/span&gt;&lt;span class='class'&gt;MainController&lt;/span&gt; &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt; &lt;span class='constant'&gt;Ramaze&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Controller&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# The Main controller will be accessed using &amp;quot;main&amp;quot; as in:&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# http://localhost:7000/main.&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;map&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;/&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Use page.xhtml in the layout directory for layout except &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# for when we&amp;#39;re doing AJAX.&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;layout&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:page&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt; &lt;span class='punct'&gt;{&lt;/span&gt; &lt;span class='punct'&gt;!&lt;/span&gt;&lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;xhr?&lt;/span&gt; &lt;span class='punct'&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Let&amp;#39;s us put in our &amp;quot;js&amp;quot; lines.&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;helper&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:xhtml&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Set up a helper to check if we&amp;#39;re logged in and only allow access&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# to the :logged_in page if we are. This is probably the hard way to &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# do this for only the single page but will make much more sense if &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# we add more pages as we&amp;#39;d do in a real application.&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;helper&lt;/span&gt; &lt;span class='symbol'&gt;:aspect&lt;/span&gt;&lt;br /&gt;    &lt;span class='ident'&gt;before&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:account_settings&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='symbol'&gt;:main&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt; &lt;span class='punct'&gt;{&lt;/span&gt; &lt;br /&gt;        &lt;span class='keyword'&gt;unless&lt;/span&gt; &lt;span class='ident'&gt;logged_in?&lt;/span&gt; &lt;br /&gt;            &lt;span class='comment'&gt;# Set the flash message which will only be available in the next&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# screen. In this case that will be the logged_in screen.&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;flash&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:message&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;You must log in before accessing the requested page.&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:index&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# You can access it now with http://localhost:7000/&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;index&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@title&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;SteamCode - User&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Placeholder for real content.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;main&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;&amp;lt;h2&amp;gt;Main&amp;lt;/h2&amp;gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Placeholder for real content.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;about&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;&amp;lt;h2&amp;gt;About&amp;lt;/h2&amp;gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Placeholder for real content.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;help&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;&amp;lt;h2&amp;gt;User Help&amp;lt;/h2&amp;gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Register a new user with SteamCode. We will get here from the&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# views/register.xhtml page where the user will put in their (requested)&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# login, password, and email address.  First find if the user already&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# exists, if it does, then we&amp;#39;ll set a message to tell the user so and&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# redirect them back to the register screen. If not, we&amp;#39;ll go ahead and add&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# them to the database with the appropriate login, password, and email&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# address. We&amp;#39;ll then send them to the login screen to let them log in to&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# SteamCode.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;register&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@title&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Register with SteamCode&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@questions&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;ChallengeQuestion&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;questions&lt;/span&gt;&lt;br /&gt;        &lt;span class='comment'&gt;# Make sure we&amp;#39;re getting here from a post request.&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;post?&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# Check the login and password.&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# if we find the Account based on the login and password. If we find it&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# we&amp;#39;ll save the login ID in the session variable and we can use that&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# to show if the Account is currently logged in or not. If we can&amp;#39;t&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# find the Account, we&amp;#39;ll set the flash message, set the session to nil&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# and just stay on this page.&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;find&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt;&lt;span class='punct'&gt;])&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# This user already exists. Set the flash message for them to&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# try again.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;flash&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:message&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Login &lt;span class='expr'&gt;#{request[:user_name]}&lt;/span&gt; already used. Please select another.&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;                &lt;br /&gt;                &lt;span class='comment'&gt;# Stay on the register page.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:register&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;else&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# This account does not exist. Grab the user_name, the password,&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# and the email and create a new Account with them.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;user_name&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;password&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:password&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;email&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:email&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Log the new user (a real application wouldn&amp;#39;t probably print&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# the password out though).&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Ramaze::Log.debug &amp;quot;New User Added: user_name = #{user_name} password = #{password} email = #{email}&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Create the account with the user_name, password, and email given.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;user&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;create&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;user_name&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='symbol'&gt;:password&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='symbol'&gt;:email&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;email&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt;&lt;br /&gt;                           &lt;span class='symbol'&gt;:challenge_answer&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:challenge_answer&lt;/span&gt;&lt;span class='punct'&gt;],&lt;/span&gt; &lt;br /&gt;                           &lt;span class='symbol'&gt;:challenge_question&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='constant'&gt;ChallengeQuestion&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:challenge_question&lt;/span&gt;&lt;span class='punct'&gt;]])&lt;/span&gt;&lt;br /&gt;                &lt;span class='constant'&gt;Ramaze&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Log&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;debug&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;New User Added: user_name = &lt;span class='expr'&gt;#{user.user_name}&lt;/span&gt; password = &lt;span class='expr'&gt;#{user.password}&lt;/span&gt; email = &lt;span class='expr'&gt;#{user.email}&lt;/span&gt; question = &lt;span class='expr'&gt;#{user.challenge_question.question}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Redirect to the login page.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:login&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Login to Steamcode. If the request is a post, then we&amp;#39;ll try to find the&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# user. If we succeed then we&amp;#39;ll set some session variables and redirect to&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# the main page (which the user can only access if they&amp;#39;re logged in). If they&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# can&amp;#39;t be logged in, we&amp;#39;ll set a flash message, reset the session, and redirect&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# back to the login page.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;login&lt;/span&gt;&lt;br /&gt;       &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;post?&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;user&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;find&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt;&lt;span class='punct'&gt;],&lt;/span&gt; &lt;span class='symbol'&gt;:password&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:password&lt;/span&gt;&lt;span class='punct'&gt;])&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Use the name= portion of the input form to grab the data&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# from the request variable and save it in the session&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# hash table.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_id&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;id&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;user_name&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Redirect to the main screen.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:main&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;else&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# The login could not be authorized. Set the flash message&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# and stay on this page (index/login). Set the session loginID &lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# to nil also. This will effectively log the user out. This would &lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# be reasonable if they are logged in and then try to log in with&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# a new login/password.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;flash&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:message&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Incorrect user name or password, please try again!!!&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_id&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;nil&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;nil&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Stay on the login page.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:login&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;       &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Let the user change account settings. For now this is&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# just the email and password.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;account_settings&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;user&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_id&lt;/span&gt;&lt;span class='punct'&gt;]]&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;post?&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;user&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_id&lt;/span&gt;&lt;span class='punct'&gt;]]&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;email&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:email&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;password&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:password&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;save&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;flash&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:message&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;New email and/or password saved.&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:main&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@current_password&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;password&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@current_email&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;email&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Logout of the system. Set the flash message and then&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# set the session values to nil. Finally, redirect back to the &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# index page.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;logout&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;flash&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:message&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;&lt;span class='expr'&gt;#{session[:user_name]}&lt;/span&gt; Logged out&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_id&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;nil&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;nil&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:index&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# The user has requested that we email their password back to them. When they submit &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# their challenge response and we verify it, we&amp;#39;ll set up an email response using &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# Mailit and send it to them.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;forgot_password&lt;/span&gt;&lt;br /&gt;        &lt;span class='constant'&gt;Ramaze&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Log&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;debug&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Enter Forgot Password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class='attribute'&gt;@page_javascript&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;span class='string'&gt;forgot_password&lt;/span&gt;&lt;span class='punct'&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;post?&lt;/span&gt;&lt;br /&gt;            &lt;span class='constant'&gt;Ramaze&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Log&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;debug&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Challenge Question Submitted: Email: &lt;span class='expr'&gt;#{request[:user_name]}&lt;/span&gt; Answer: &lt;span class='expr'&gt;#{request[:challenge_answer]}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# Final submit.&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;user&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;find&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt;&lt;span class='punct'&gt;],&lt;/span&gt; &lt;span class='symbol'&gt;:challenge_answer&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:challenge_answer&lt;/span&gt;&lt;span class='punct'&gt;])&lt;/span&gt;&lt;br /&gt;                &lt;span class='constant'&gt;Ramaze&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Log&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;debug&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Found user: &lt;span class='expr'&gt;#{user.user_name}&lt;/span&gt; &lt;span class='expr'&gt;#{user.email}&lt;/span&gt; &lt;span class='expr'&gt;#{user.password}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;br /&gt;                &lt;span class='comment'&gt;# Create the mail message and fill it in with the appropriate&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# information (to/from/subject/text). Then send it off.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;mail&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;Mailit&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Mail&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;new&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;mail&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;to&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;email&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;mail&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;from&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Steamcode@MyCompany.com&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;mail&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;subject&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Steamcode Password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;mail&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;text&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Your password is: &lt;span class='expr'&gt;#{user.password}&lt;/span&gt;.&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Send the mail message via the MAILER (created in start.rb).&lt;/span&gt;&lt;br /&gt;                &lt;span class='constant'&gt;MAILER&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;send&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='ident'&gt;mail&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Just go back to the login page.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:login&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;else&lt;/span&gt;&lt;br /&gt;                &lt;span class='constant'&gt;Ramaze&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Log&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;debug&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Could not find user: &lt;span class='expr'&gt;#{request[:user_name]}&lt;/span&gt; or incorrect challenge response.&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;flash&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:message&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Could not find user: &lt;span class='expr'&gt;#{request[:user_name]}&lt;/span&gt; or incorrect challenge response.&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Could not find user with this user_name/challenge answer just redirect to forgot password&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;redirect&lt;/span&gt; &lt;span class='ident'&gt;rs&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:forgot_password&lt;/span&gt;&lt;span class='punct'&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# This is called from an Ajax request. We take in the email address that the &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# user submitted and then pass back the challenge question for that user. If &lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# we can&amp;#39;t find the user, we won&amp;#39;t respond with anything and we&amp;#39;ll let the&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# javascript (public/js/forgot_password.js) deal with it. In this case, they&amp;#39;ll&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# just pop up an alert to let the user know.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;generate_forgot_question&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;xhr?&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# Get the user_name and if it exists, return the challenge question. If not, generate the&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;# could not find user_name messesage.&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='ident'&gt;user&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='constant'&gt;User&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;find&lt;/span&gt;&lt;span class='punct'&gt;(&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt; &lt;span class='punct'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ident'&gt;request&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_name&lt;/span&gt;&lt;span class='punct'&gt;])&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;challenge_question&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='ident'&gt;user&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;challenge_question&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;question&lt;/span&gt;&lt;br /&gt;                &lt;span class='constant'&gt;Ramaze&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Log&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;debug&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Challenge Question Requested: challenge_question = &lt;span class='expr'&gt;#{challenge_question}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# It looks like we a) MUST use the respond command and b)MUST use the 200 return value. This was&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# determined by just trying different things.&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;json&lt;/span&gt; &lt;span class='punct'&gt;=&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;{ challenge_question: &lt;span class='escape'&gt;\&amp;quot;&lt;/span&gt;&lt;span class='expr'&gt;#{challenge_question}&lt;/span&gt;&lt;span class='escape'&gt;\&amp;quot;&lt;/span&gt;}&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;                &lt;span class='ident'&gt;respond&lt;/span&gt; &lt;span class='ident'&gt;json&lt;/span&gt;&lt;span class='punct'&gt;,&lt;/span&gt; &lt;span class='number'&gt;200&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;else&lt;/span&gt;&lt;br /&gt;                &lt;span class='comment'&gt;# Go ahead and log a message.&lt;/span&gt;&lt;br /&gt;                &lt;span class='constant'&gt;Ramaze&lt;/span&gt;&lt;span class='punct'&gt;::&lt;/span&gt;&lt;span class='constant'&gt;Log&lt;/span&gt;&lt;span class='punct'&gt;.&lt;/span&gt;&lt;span class='ident'&gt;debug&lt;/span&gt; &lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Could not find user with user_name: &lt;span class='expr'&gt;#{request[:user_name]}&lt;/span&gt;&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;        &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='ident'&gt;private&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# If the user is logged in, the session will&lt;/span&gt;&lt;br /&gt;    &lt;span class='comment'&gt;# contain a non nil user id.&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;def &lt;/span&gt;&lt;span class='method'&gt;logged_in?&lt;/span&gt;&lt;br /&gt;        &lt;span class='ident'&gt;session&lt;/span&gt;&lt;span class='punct'&gt;[&lt;/span&gt;&lt;span class='symbol'&gt;:user_id&lt;/span&gt;&lt;span class='punct'&gt;]&lt;/span&gt; &lt;span class='punct'&gt;!=&lt;/span&gt; &lt;span class='constant'&gt;nil&lt;/span&gt;&lt;br /&gt;    &lt;span class='keyword'&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='keyword'&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The main controller starts the exact same way that the admin controller does. It has the map, layout, helper, and aspect lines and for all of the exact same reasons. Next is the index method which is the default page before someone logs in and this is followed by the main page which is where a user ends up after they log in. Next are two placeholder methods about and help that can be used for obvious purposes. Next is the registration method. We check if this is called from a post and if it is, we check to see if we already have a user with the user_name that was submitted. If we already have that name registered, we'll flash the user a message and send them back to the registration page. If we don't, we'll create a new user with the user_name, password, email, and challenge question/answer. Then we'll redirect them to the main page. Next, the login page will see if they can find the user with the given user_name and password and if so, we save their information in the session and redirect them to the main page. If not, we'll flash a message and redirect back to the login page so that they can try again. The account_settings allows the user to change their email and/or password. The logout method, like the corresponding admin logout, sets the session id and redirects the user back to the index page. The forgot_password method is the main reason for the post and it's actually pretty simple. We check the user_name and the challenge_answer that they provided and if they match we use the MAILER constant to send the email containing their password and redirect them to the login page. If we can't find the user or if the challenge answer doesn't match, we'll flash a message and send them back to the forgot_password page. The generate_forgot_question will come from an AJAX request. If we find the user_name, we'll send their challenge question back to them using JSON. If not, we'll just stay on the same page and they can try again. Finally, we have the logged_in? method, for checking if the user is logged in (obviously). We use this to protect certain pages from users who aren't logged in.&lt;br /&gt;&lt;br /&gt;Now, let's take a look at the views. First is the index page and it's a simple Welcome message.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='xml' lang='xml'&gt;#{flashbox}&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;h2&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;Welcome&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;h2&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Next, the registration page contains input boxes for the user_name, password, email, and challenge response. There's also a drop down for the challenge question and the submit button.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='xml' lang='xml'&gt;&lt;span class='comment'&gt;&amp;lt;!-- view/register.xhtml --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;form&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;register&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;method&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;post&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='comment'&gt;&amp;lt;!-- for= goes with id=, the name= is placed in the request variable. --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class='comment'&gt;&amp;lt;!-- Input for the user_name. --&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt; &lt;span class='attribute'&gt;for&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;user_name&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Login:&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;user_name&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;user_name&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;text&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class='comment'&gt;&amp;lt;!-- Input for the password. --&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt; &lt;span class='attribute'&gt;for&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Password:&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class='comment'&gt;&amp;lt;!-- Input for the email. --&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt; &lt;span class='attribute'&gt;for&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;email&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Email:&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;email&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;email&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;text&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class='comment'&gt;&amp;lt;!-- Input for the challenge question. The register() method will get the list&lt;br /&gt;             of challenge questions from the database table ChallengeQuestion and will&lt;br /&gt;             pass the list of questions and ids.&lt;br /&gt;        --&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt; &lt;span class='attribute'&gt;for&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;challenge_question&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;class&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Challenge Question:&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;select&lt;/span&gt; &lt;span class='attribute'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;challenge_question&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;?&lt;/span&gt;&lt;span class='tag'&gt;r&lt;/span&gt; @&lt;span class='attribute'&gt;questions.each&lt;/span&gt; &lt;span class='attribute'&gt;do&lt;/span&gt; | &lt;span class='attribute'&gt;question&lt;/span&gt; | &lt;span class='punct'&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;option&lt;/span&gt; &lt;span class='attribute'&gt;value&lt;/span&gt;&lt;span class='punct'&gt;=#{&lt;/span&gt;&lt;span class='attribute'&gt;question.id}&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;#{question.question} &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;option&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;?&lt;/span&gt;&lt;span class='tag'&gt;r&lt;/span&gt; &lt;span class='attribute'&gt;end&lt;/span&gt; &lt;span class='punct'&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;select&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class='comment'&gt;&amp;lt;!-- Input for the challenge_answer. We&amp;#39;ll save this and if they need to retrieve &lt;br /&gt;             their password, we&amp;#39;ll ask the question from above and see if they know the&lt;br /&gt;             answer they will submit here.&lt;br /&gt;        --&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt; &lt;span class='attribute'&gt;for&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;challenge_answer&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Challenge Response:&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;challenge_answer&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;challenge_answer&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;text&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class='comment'&gt;&amp;lt;!-- Submit the new User --&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;submit&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;value&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Register&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;form&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The login page only has the input boxes for the user_name and password along with the submit button.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class='xml' lang='xml'&gt;#{flashbox}&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt; &lt;span class='attribute'&gt;href&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;#{r(:forgot_password)}&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Forgot your password?&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;a&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;form&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;login&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;method&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;post&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;fieldset&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;legend&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt; Login &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;legend&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- for= goes with id=, the name= is placed in the request variable. --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- Input for the user_name. --&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt; &lt;span class='attribute'&gt;for&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;user_name&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;User Name:&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;user_name&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;user_name&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;text&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- Input for the user_name. --&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt; &lt;span class='attribute'&gt;for&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&amp;gt;&lt;/span&gt;Password:&lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;label&lt;/span&gt;&lt;span class='punct'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;id&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;name&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;password&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;br&lt;/span&gt;&lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class='comment'&gt;&amp;lt;!-- Submit the login request.  --&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class='punct'&gt;&amp;lt;&lt;/span&gt;&lt;span class='tag'&gt;input&lt;/span&gt; &lt;span class='attribute'&gt;type&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;submit&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='attribute'&gt;value&lt;/span&gt;&lt;span class='punct'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='string'&gt;Login&lt;/span&gt;&lt;span class='punct'&gt;&amp;quot;&lt;/span&gt; &lt;span class='punct'&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class='punct'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='tag'&gt;div&lt;/span&gt;&lt;span class='punct
