Ruby


Its been a crazy December through January and I haven’t written much!

I’m glad the GWT posts helped some of you from the comments. I spent some time on figuring them out from the limited docs on google’s GWT site, mostly I think it helps to have complete examples since they dont make it real clear what file each snippit of code goes in. I’m glad the pain I went through to figure them out help some of you :) A few of you had problems but i haven’t gotten around to seeing what is wrong. I was using the trunk version of GWT, so if you are using 2.0 then you might have some differences.

I’ve been diving my head back into rails after spending a spell in perl/mason and GWT in some projects for work. I think other languages are neat but I really love ruby. So I’ve been re-watching some of my episodes of PeepCode.com and RailsCasts.com those guys are awesome. I love this stuff. Why else would I be spending my Saturday night with Ruby vs watching a movie or playing a game!

I’ve also been playing with android a bit, its pretty fun to see my app on a phone! Working on a TODO List app, which seems almost like “hello world” but it has a twist… more later when i have something to show.

Been working learning jQuery. I had seen it before, but saw class names mixed with programming and having a ugghhhh feeling. But.. I decided to give it a shot and dang! I would have given my right arm to have this 5 years ago when i was experimenting with ajax (though it wasn’t called that…) with setting the src of a script tag with a php url to load and save data. Anyways, its cool and neat. I think the name is horrible since you aren’t really quering anything… IMHO :) Maybe if I can think of a better one I can suggest it, but seems like it is here to stay since there are stay since there are 4 books already about it!

To help with reviewing ruby I have been working through Ruby Koans. Hats off to EdgeCase. I have already written them and thanked them! This goes along with my post How To Get Better At Programming where I wrote about how i was working at getting better at programming. It all comes down to practice! … I think when I finish the rubykoans exercises, i will revert and start going through them again. Almost like doing pushups every day (I push up to get more coffee at least 3x a day!).

Git … I did my first pull request on github, very cool how that works.

Have some ideas for some more substantial posts… coming soon :)

I’ve have been pondering in the past 6 months - How do I get better at programing? What is the best way? do I need more books? At my current company, we whole heartedly engage in peer reviews, nothing gets checked in the repository without at least one person going over it. In that process, i’ve learned more about coding then I could from 10 books. I used to be a book fiend. I had about 10 books on every subject. Did I learn? yeah, some! But I think I’ve learned more from doing and practice. Practice, practice, practice! When the Chicago Ruby User Group offered this book in exchange for a review, I jumped at the chance.

“Refactoring in Ruby” written by William C. Wake and Kevin Rutherford.
Published by Addison-Wesley

“Refactoring in Ruby” is more like a “workbook” then a “how to write awesome code” book. If you download the code from github http://github.com/kevinrutherford/rrwb-code you have tests already written for the exercises.

The book is arranged in three parts, The Art of Refactoring, Code Smells, and Programs to Refactor.

There are explanations of “code smells” which are one characteristic of code that could be improved. Some of them are long parameter lists, unnecessarily complex, global variable, feature envy sections, etc. One thing I find interesting is the “How did it get this way?” section. It gives some insight into the thought process and reasoning behind the smell. I think this is good, as programmers our ego may be rather miffed to hear “This code stinks” but with some reasoning, it makes the pain less and I think firms up in our minds when this happens again, to do it this other way. I always want to know why when someone says I could do such and such thing better.

In addition to the code smell examples there are three programs to refactor in the end of the book. In a conversational tone, it walks through and gives some hints on what needs refactoring. Its almost as if you had a pair programming buddy working with you and identifying in small chunks what can be improved. This is definitely something I want to work through more carefully.

What I find odd, is that not all the code smells have code examples. The inspiration for the book I think is the Martin Fowler book “Refactoring Improving the design of Existing Code” which has examples for every code smell. Maybe Ruby smells less than Java? Or those fixes are really trivial? I don’t know. Overall, this is a great book and is certainly worth the price and investment and you will be a better programmer because of it!

There are explanations of “code smells” which are one characteristic of code that could be improved. Some of them are long parameter lists, unnecessarily complex, global variable, feature envy sections, etc. One thing I find interesting is the “How did it get this way?” section. It gives some insight into the thought process and reasoning behind the smell. I think this is good, as programmers our ego may be rather miffed to hear “This code stinks” but with some reasoning, it makes the pain less and I think firms up in our minds when this happens again, to do it this other way. I always want to know why when someone says I could do such and such thing better.

In addition to the code smell examples there are three programs to refactor in the end of the book. In a conversational tone, it walks through and gives some hints on what needs refactoring. Its almost as if you had a pair programming buddy working with you and identifying in small chunks what can be improved. This is definitely something I want to work through more carefully.

What I find odd, is that not all the code smells have code examples. The inspiration for the book I think is the Martin Fowler book “Refactoring Improving the design of Existing Code” which has examples for every code smell. Maybe Ruby smells less than Java? Or those fixes are really trivial? I don’t know. Overall, this is a great book and is certainly worth the price and investment and you will be a better programmer because of it!

Trying something new .. HAML... I saw it a couple years ago, I was like "ehh.. umm.. nah" ... But working on the DevChix site, it seems like it will be our choice instead of erb for templates so I thought I'd give it a try.

So here's some straight up html + erb

RUBY:
  1. <h1>Listing users</h1>
  2.  
  3. <table>
  4.   <tr>
  5.     <th>Username</th>
  6.     <th>Email</th>
  7.   </tr>
  8.  
  9. <% @users.each do |user| %>
  10.   <tr>
  11.     <td><%=h user.username %></td>
  12.    <td><%=h user.email %></td>
  13.     <td><%= link_to 'Show', user %></td>
  14.     <td><%= link_to 'Edit', edit_user_path(user) %></td>
  15.     <td><%= link_to 'Destroy', user, :confirm => 'Are you sure?', :method => :delete %></td>
  16.   </tr>
  17. <% end %>
  18. </table>
  19.  
  20. <%= link_to 'New user', new_user_path %>

And same with haml:

RUBY:
  1. %h1 Listing users
  2.  
  3. %table
  4.   %tr
  5.     %th Username
  6.     %th Email
  7.  
  8. - @users.each do |user|
  9.   %tr
  10.     %td
  11.       = user.username
  12.     %td
  13.       = user.email
  14.     %td
  15.       = link_to 'Show', user
  16.     %td
  17.       = link_to 'Edit', edit_user_path(user)
  18.     %td
  19.       = link_to 'Destroy', user, :confirm => 'Are you sure?', :method => :delete
  20.  
  21. = link_to 'New user', new_user_path

I am not totally sold, but.. it is an interesting kind of markup!

Let me know if you see a better way to write it or if you prefer another markup language!

Call me crazy, but this is why I classify myself as a language geek. When I learn something fascinating, i wonder hmm how can I do that with X language? My last post I did an example of the Builder pattern as described in Effective Java by Joshua Bloch. The main motivation for me to use Builder is to have flexible parameter lists, without worrying about order of parameters (there are a few other reasons outlined in the book, but this is what I find cool).

Its too easy.

My class:

RUBY:
  1. class Address
  2.   attr_accessor :street, :street2, :city, :state, :zip, :address_type
  3.  
  4.   def initialize(&block)
  5.    
  6.     #set default values
  7.     self.city = "Chicago"
  8.     self.state = "IL"
  9.    
  10.     #set value from block
  11.     instance_eval &block if block_given?
  12.  
  13.   end
  14.  
  15. end

And the usage of it:

RUBY:
  1. def testDefaultValues
  2.     myaddress = Address.new
  3.     assert_equal("Chicago", myaddress.city)
  4.     assert_equal("IL", myaddress.state)
  5.   end
  6.  
  7.   def testStreetStateZip
  8.     myaddress = Address.new do
  9.       self.street = "this is the street"
  10.       self.zip = "11111"
  11.     end
  12.     assert_equal("Chicago", myaddress.city)
  13.     assert_equal("IL", myaddress.state)
  14.     assert_equal("this is the street", myaddress.street)
  15.     assert_equal("11111", myaddress.zip)
  16.   end

Wow, huh? Compare to

JAVA:
  1. public void testBuilderDefaults() {
  2. Address expected = new Address.Builder("Chicago", "IL").build();
  3. assertEquals("State is IL", "IL", expected.getState());
  4. assertEquals("City is Chicago", "Chicago", expected.getCity());
  5. }

then the optional params are chained to that:

JAVA:
  1. public void testBuilderStreetStateZip() {
  2.    Address expected = new Address.Builder("Chicago", "IL").street("this is an address").zip("11111").build();
  3.   assertEquals("this is an address", expected.getStreet());
  4.   assertEquals("11111", expected.getZip());
  5.   assertEquals("IL", expected.getState());
  6.   assertEquals("Chicago", expected.getCity());
  7. }

Full source for Ruby (though I was able to paste it all here!)
Address class in ruby | Address test in ruby

And for Java, if you want to compare ...
Address class in Java | Address test in java

Yes... sometimes its hard not to gloat. :-D

yeah yeah yeah, its not really "fair" to compare strongly typed languages... but as I said, my motivation is to have easy parameter lists without having to remember specific ordering of params for constructor or use multiple set methods.

Even though I don't do ruby at work, I do it for fun on weekends. I paid for my own self to go to the WindyCityRails conference and tutorial on Cucumber, RSpec Testing. It was well worth the money!! Not many things can get me to go up to Chicago early in the morning and on a weekend!

I went to a 3 hour tutorial class "Behaviour Driven Rails with RSpec and Cucumber" ... in my limited time I can spent with I've had a hard time getting my head around cucumber. I did rspec alot a few years ago, so thats a piece of cake. David Chelimsky and Corey Haines. 4 days before the conference, they sent an email to attendees of the tutorial with a list of resources to read and libraries to install. I worked all week on watching railscasts.com videos on cucumber, factories, testing. I always like to try things out myself first, then I am familiar with it when I go "to class" :) Dave and Corey did the class pair programming style..which was totally fascinating. There was one laptop, two wireless mice and one wireless keyboard. Dave typed on the laptop keyboard and Corey typed on the external keyboard. One would talk and explain things while the other typed. They took turns. It was really awesome. After watching them program, then they told us to split up in pairs and do the same thing for another scenario. I was sitting between two people so I kinda bounced between them. The one on my left didn't have the same version of rails, so he typed on my keyboard and we took turns. It was awesome, I had not really done pair programming quite like that before. They bounced between cucumber tests and rspec tests. I wish I could have recorded video and played it back in slow motion!

The regular talks:

Better Ruby through Functional Programming
Dean Wampler, Object Mentor, Inc.

I started to learn haskell once.. bought the O'Reilly book (which is excellent with little exercises)... but thats as far as I got with functional programming. This talk was interesting with code samples of ruby. We were challenged to learn a functional programming language. He mentioned others like scala, erlang ... hmm what to choose!

Super-easy PDF Generation with Prawn and Prawnto
John McCaffrey, Pathfinder Development

I have not had to make PDFs with ruby yet...but now I know there are some great libraries. Cool part of this is John was making a PDF of a ruby app, pulling in twitters happening at the conference and using Googles graphs APIs to make pretty graphs! I saw alot of people saying "I didn't know that Google had graph APIs!!!" :)

“Comics” Is Hard: On Domains and Databases
Ben Scofield, Viget Labs

When the talk started Ben asked for a show of hands of who reads comics? I meekly raised my hand. My husband is a comic book fan and I read them on occasion. I sat at his table for lunch and he asked me about it. I was surprised he saw my hand, iwas sitting near the back! This talk didn't have much code, but talked about the number of attributes that comic books have (title, issue, theme, publisher, etc) and how hard it was to model in a relational database. He talked about couch db, mongo ... i haven't tried any of those, but I might now that I know it can be the best choice for some data sets.

Rails 3 Update
Yehuda Katz, Engine Yard

Yehuda talked about whats coming up in Rails3. But by this time I was kinda brain dead and was trying to make plans for dinner!

Devchix!!!
A few of the local chix came to the after party and hung out. There was a few at the conference I had not met yet and a few I invited to join! It was awesome. It was so fun. I caught up some of my ruby buddies I hadn't seen in awhile and made some new friends. I was sad to see it end...

This book is still in beta, but so far... I love it!

Chapter 1 is a very brief overview of RSpec and Cucumber and in Chapter 2 you are shown some examples. This is Real Code That Works! You can type it in and run. That is awesome, I was so excited last night that I almost couldn't stop and go to sleep (Doc tells me to get more sleep. BAH!). I've done RSpec on a fairly large project before, a few years ago. I had seen some presentation at the Chirb meetings about some kind of testing involving Stories and Scenarios. It was interesting then... I just wasn't sure how you can translate that into code. Now I see, it looks like this method has matured to the point where it is viable. Cucumber is only version 0.3.11 at this time but hey! Its cool, its tight, its gonna take off!

Chapter 3 - Starting off with a game example! WAY TO GO! Nothing more uninteresting than Yet Another Bank Account or Blog example. This is totally awesome. Its a very conversational at first, as you are learning how to apply the "Story" concept to the need. Once the planning is out of the way.... its time to code!

Chapter 4 - Cucumber, Writing steps to the stories

Chapter 5 - RSpec, writing rspec tests

Its great to see code that you can type in an run and its kinda fun, it a game! what isn't fun about that! Great book so far Dave Chelimsky, Dave Astels, Zach Dennis, Aslak Hellesoy, Bryan Helmkamp and Dan North. Right on! Looking forward to the rest :)

Published by Apress
By Kevin Marshall, Chad Pytel, Jon Yurek
Book Info
Sample Chapter: Ch. 01 - Introducing Active Record
Table of Contents

Years ago when I was in PHP Land (now I travel quite a bit more! haha), I strugged for months with how to write a good ORM . It was tough, because I wanted to abstract the "boring logic" of retrieving records from a database without writing SQL but still remain flexible enough. I never really came up with a good model. I used the DAO from "extreme php" library which I think was a knock off from java. It was ok, but I still didn't feel like I had "arrived".

When I discovered Ruby on Rails, I found ActiveRecord. Ahh HA! Finally, this is what I was looking for. At first I thought it was part of Rails, but its not. Its a standalone library and you can use it with straight up ruby scripts.

I got a review copy of "Pro Active Record" some time ago and read it some when I got it, then some later, and now I am going to officially write up a review!

If you do anything with Active Record, get this book. The things that are briefly mentioned in most Rails books are described in detail in this book.

Chapter 1 - Introducing Active Record

Most of the time, the first chapters of a book are boring to me. I don't need another "History of the Internet" or how "HTML was developed" ... blah blah. But this one, the story is only 1 page. And it actually has some introductory scripts on using Active Record, so you can see right away how it works. It also explains the benefits of MVC and why ORMs are good. Some people still don't get it!

Chapter 2 - Active Record and SQL

This chapter helps you translate the "sql in your head" to how to write it with Active Record. I've used Active Record so much that now I have forgotten most of my SQL, which is kind of embarrassing. :) I now find writing sql tedious and boring! I would have actually called this chapter "Demystifying Active Record" since it explains why all the dynamic finders work. You'll also find transactions and locking explained here.

Chapter 3 - Setting up Your Database

Migrations! The Awesome Thing that can turn into a nightmare for large rails projects with multiple developers.... definitely have to decide on some best practices with your team on this one. The chapter has only one thing to say about this -- assume any checked in migration has already been run by your team and the migration should not be edited and checked back in! You'll have to make another migration file with your changes.

[tip]
Nola's Note: When you make a migration, test it both UP and DOWN!! Here's what I do --
write a migratiion
rake db:migrate (go up to the version with new code)
rake db:migrate VERSION=n-1, (go to version before the latest)
rake db:migrate (back to lastest)
rake db:migrate VERSION=0 (back to blank db)
rake db:migrate (back to latest)
[/tip]

Just to be sure its all good -- even on a new database!

Chapter 4 - Core Features of Active Record

Now is the fun stuff - Callbacks. This is magic. This makes Active Record so flexible, and is one thing I could never figure out how to do with my PHP ORMs. I use call backs to set defaults for fields. If its just a straight default, then I set it in the database but if I need to make a decision, (if this field then this field..) then I can use it in a callback.

Associations - at first this is very confusing! I don't know how many times I got "has_many" and "belongs_to" mixed around in the beginning.

Validations - Awesome. I had to do some ruby code without a database and I really really really missed the validations. It took me like 5x longer than it should! Understanding all of these validation methods will make your life so much more enjoyable. I really really hate doing boring, repetitive stuff...it seems so wasteful to me.

Chapter 5 - Bonus Features

Everybody likes a bonus and this isn't even the last chapter of the book.

Java people will like the Active Record Observers -- seems a little AOP to me (aspect orienteted programming) and something I probably have neglected to use to their fullest extent.

Acting up -- Learn how to "save time" with the "acts_as" magic: List, Tree, Nested Sets. If your data needs these structures, you got it made. I can imaging how much longer it would take to write this stuff in perl or php.

Composed of - I haven't used this, but this looks like a good way to make sensible objects out of database tables. There is quite a bit of explanation and examples of this, it will come in handy.

There are a few other in depth explanations of things, such as method_missing which is how alot of the magic happens. Rock on.

Chapter 6 - Active Record Testing and Debugging

Ahh yes, Testing. My favorite subject. My friends who know how much I love testing say I am sick. I must have an inner need to PROVE I am right or something, haha.

The chapter goes into depth about using test_unit with Active Record, sadly no RSpec. But, it does go into all the error messages that Active Record throws so you can write good try/catch blocks and make very exact error messages (probably best logged for the admin rather then displayed to the user!)

Chapter 7 - Working with Legacy Schema

Here's how you work with that old database that just won't die... or that management won't let you totally redo. Active Record follows some of the principles of Rails "convention over configuration" ... relying on table and column naming conventions to figure out how to build your object....but still giving you a way out if you want your tables singular and your primary id field called "myawesomeid" instead of "id"

I've used some of these things on an older database and it was possible! Not too bad if thats what you have to work with.

[soapbox]
Some people find this annoying "oh gosh! my library can't make decisions for me! OMG! That sucks" .. to that I say, "Umm ok. But if you follow these conventions then I can come into your project and know exactly what is going on" ... like with web standards, we all harp on how IE and FF do things differently, yet people want to bellyache about Active Record preferring to have plural names and id field called "id". Right.

Follow the dang convention and find something worth complaining about to complain about. :)
[/soapbox]


Chapter 8 - Active Record and The Real World

This chapter goes into depth about the library and encourages you to go read the Active Record code. Always a good idea to know what it is you are using :) I've actually learned ruby better by reading source code. The chapter walks you through basic structure of the files. Very cool.

[soapbox]
I used to work at a place that didn't like any "outside code" because they were afraid "OMG ... it will send our passwords to Russia!" ... ok, well I am not an idiot. I read over any code that I use that I didn't write. I look at the tests to see if I am using it right. I even RUN the tests so I can be sure its working as advertised.
[/soapbox]

Alternatives to Active Record - with EXAMPLES! If something about Active Record doesn't set too well with you, take a look at the alternatives. Sometimes I look at the alternatives and decide that the first wasn't so bad after all. You'll find examples of DBI, Og, ActiveRelation.

Finally a section on Q and A finishes up this book. The Appendix has a complete reference of ActiveRecord methods to make this book a well rounded reference, tips, documentation and very handy to have at your desk!

I know that mentioning Rails and PHP in the same sentence is taboo and can incite many flame wars. But hear me out -- Some say one of the "downfalls" of PHP is that its so easy to write applications and just about anybody can write a PHP if they put their mind to it and learn the syntax. As a result, PHP Applications have a long history of badly written, insecure code and has really been shunned by many advanced developers (aside from many poorly named methods, I think PHP is alright!).

In recent months I've been recruiting for a Rails Developer at my company, in Chicago. I did a phone interview and the guy couldn't name me any rails sites he reads, or name the 7 rest actions, or even tell me what version(s) he uses. Now, I'm not claiming to be an expert, but I would think that even an average Rails developer would know that.

I've also seen code where the developer doesn't quite get MVC. You don't need to be validating values in your controller and adding error messages to @model.errors.add for example. You don't need to be setting up display labels in your model. You don't need to be counting things in a helper method. I was thinking, why is it so hard? Is it because in mostlanguages we have had free reign to interpret MVC however we pleased? I know I spent many years in PHP trying to develop a DAO. I made an object that returned a row of data, with methods to access the fields. But what about a collection? what is that? I experimented with an array of objects but I felt that was too wasteful. Iexperimented with a DaoSet that was made to hold a collection -- complete with iterators! I even struggled with MVC and knowing what went where...when I saw Rails it was like someone who met their true love -- this is it!

After experiencing Rails, I realized hey I can do some of this in PHP! I wrote a simple MVC framework in PHP. I called it StupidlyEasyMVC Framework. I was able to use it at work (at the time, I was still at a PHP job. Some say I talk about that time in my life as if it were a prison sentence haha). SO I was able to apply things I learned from Rails, into an existing structure at work. Just like the guy from CDBaby -- I couldn't drop my existing PHP site and just start converting to Rails, but by starting to gradually switch from what I had to an MVC structure, it made my code cleaner and easier to work with.

So as I look for advanced rails developers, I find they are far and few between. Either they are hotshot consultants or working on their own startup. What makes a rails programmer "get it" and really work with the framework instead of against it - still trying to write as they always have?

Here are some things you can do if you feel you are still writing PHP or .NET code in rails..

Get a project. You can read and dabble all you want, but if you don't have a project, you won't be forced to learn. Along with that, you need a timeline to force you to keep at it!

Watch all the Peepcodes! especially the REST and rspec episodes. I've search hard and long enough for answers, to find comprehensive training in ONE spot, in such an easy to learn format is awesome. I constantly talk about peepcode and I won't work with anyone who hasn't watch them.

Peepcode Code Review - their first book, full of helpful hints and gotchas that will really help you move beyond a beginning developer

Ruby Inside Blog - www.rubyinside.com

Jay Fields - http://blog.jayfields.com/

Obie Fernandez - obiefernandez.com

Books:
Agile Web Development with Rails - If you are doing Rails and don't have this book, get it! It is the bible of rails! I don't care if you have the first edition already, this will save you time!
The Ruby Way by Hal Fulton - because if you don't know ruby, you will never be a good rails developer.
The Rails Way by Obie Fernandez - its good because I tech edited it before publication! It is a comprehensive instructional and reference book -- all in one. I cannot wait to get my hands on a paper copy of this to keep at home and one for work. (just got one this week...I'm ecstatic)

Well this has been mostly a rant but hopefully a help resource to move into more advanced development of rails. If you have other insights into this problem or suggestions for how to improve, please leave a comment!

I did PHP for 6 years.... sometimes its hard not to do PHP in ruby...

Today i was testing a url to see if it contains a certain string:

RUBY:
  1. response = Net::HTTP.get_response(URI.parse("http://myawesomesite")
  2. if response.body.match("my awesome text") == nil  then
  3.       return false
  4. end

and remember to do:

RUBY:
  1. response = Net::HTTP.get_response(URI.parse("http://myawesomesite")
  2. return "false" if response.body.match("my awesome text").nil?

Another thing I was working on was I had to do a multiple if statement

I will simplify it for this example:

RUBY:
  1. color = red
  2.   if (color == "red") or (color =="green") or (color == "yellow") then
  3.     print "its valid)
  4. end

In PHP I might have actually made the values into an array, and then did in_array ... but in reading the code, you see below, if in the valid values, print something. I don't want to see array!

This is more elegant:

RUBY:
  1. color = red
  2. valid_values = ["red","green","yellow"]
  3. puts "its valid" if valid_values.include? color

This seems to only work for values you'd do == on, not ===

See... programming in ruby just makes me grin :)

I've been kinda on a rails spree lately, I guess I've had some free time and also redoing a rails 1.1.6 project (and was noob then and no clue of what I was doing) and updating it to use REST.

I got Geoffrey Grosenbach PeepCode's REST Tutorial, which is very awesome and well worth the 9 bucks. Its over an hour long! I also got the RJS Tutorial which is also awesome. I can't wait till payday to get the $40 pack so I can get some more! There's just something about SEEING something work that makes it stick sometimes.

Also I spent some time on Railscasts which features a ton of short demos on rails topics. Very cool. In particular i liked Testing Without Fixtures which is cool because sometimes fixtures are a PITA!

When watching one of the PeepCode screencasts I saw him using "autotest" .. a cool toy which I must have too! I searched for it and found this posting on his blog. Now I'm autotesting all the time :) It basically monitors your rails site and runs the test everytime you change your code.

I've been using e-TextEditor and slowly learning the shortcuts. I love the font that was on PeepCode's screen cast and found a link on the PeepCode FAQ where I can download it. For Free! And it mentioned the name of the theme used in Textmate -- which happened to be the one I had found in e-Text-Editor and was using. No wonder I liked it! I also used this font in my Putty settings and changed the awful default colors (esp that dark blue! hard to see!). e-TextEditor is in Beta but its in great shape and i was so happy to see a "close all tabs" feature put into the latest build. I'll be ecstatic when they make a linux version.

Next Page »