Archive for August, 02005

Extending Ruby’s Array Class with Mean Calculating Methods

Wednesday, August 31st, 02005

While hacking on some Ruby today, I came to a point where I wanted to take the geometric mean of the contents of some arrays. It would have been super cool if the Array class already had a method to do this, but it turns out that it's so easy to extend the Array class and the implementation is so easy, that I kind of appreciated it not being there, so I could go through the following exercise :

class Array
  def arithmetic_mean
    inject(0){ |sum, n| sum + n } / length.to_f
  end
  def geometric_mean
    inject(1){ |product, n| product * n } ** (1.0/length)
  end
end
	
> [1,2,3,4].arithmetic_mean
=> 2.5
> [1,2,3,4].geometric_mean
=> 2.21336383940064
> [1,2,3,18_446_744_073_709_551_616].geometric_mean
=> 102569.383039683

Videos and Music

Wednesday, August 31st, 02005

A handful of people will find the following videos interesting:

videos #1-3: Disc Golf in Ames, IA. Am I (or Spenser) competitive by nature?
video 1, video 2, video 3.

video #4: Bali Satay House. I am the capsaicin commander:
video 4.

O'Rourke took these videos with his digital camera.

In other O'Rourke news, he tipped me off to Pandora, which you should definitely check out (if it can handle the publicity):

Can you help me discover more music that I'll like?

Those questions often evolved into great conversations. Each friend told us their favorite artists and songs, explored the music we suggested, gave us feedback, and we in turn made new suggestions. Everybody started joking that we were now their personal DJs.

We created Pandora so that we can have that same kind of conversation with you.

This is close to what I wanted for a long time, but you should check it out now anyways, because it's near enough to be cool right now. What I want is a mobile AI that rides with me my in my car that constantly learns from my exclamations of "lame" or "elite". The result would be the ultimate playlist or a family of many different ultimate playlists, without the cost of years of Beef-style research. There's lots of music out there that I'm sure I'd love to listen to. Problem is: I just don't have the time to find it.

In the not too distant future:

Sack: "Computer, give me bluegrass, but none of that candy-ass crap - I want old school, crying' on the Lord, nasal vocals, and up tempo."
Computer: "Yes Mr. Sack. I think I know exactly what you mean. You should be very pleased with what I've selected, but let me know if you have any further input".

Best Metal Band in the History of the Universe?

Wednesday, August 31st, 02005

Iron Maiden - without question.

Learning Computer Arch via ADUni

Sunday, August 28th, 02005

As an supplement to my 538 reading and lectures, I'm developing a stronger background in computer architecture by going through ADUni's How Computer's Work course. ADUni is a fantastic resource. Once you start participating in these courses with their full video lectures, lecture notes, homeworks, tests, and other material, you start to wonder why all schools don't post similar material for every class - You begin to see how obviously beneficial this kind extra effort is for the student, and you start to ask questions about the classes you're taking conventionally:

  • Why can't I review the video of last week's lecture?
  • Why can't I compare last week's lecture to last year's lecture on the same subject?
  • Why can't I compare last week's lecture at my school to that which was given at MIT, UIUC, or Stanford?
  • Why aren't lecture notes available online for the lecture I just attended?
  • Why can't I take a peek at the lecture notes for tomorrow's lecture beforehand, so I can prepare some questions?
  • Why is the community I depend to learn a course's material limited to a single professor and a handful of students physically present in a classroom?
  • Why must I settle for a professor who's less than the very best?
  • Why aren't class evaluations publicly-accessible, so I can know what I'm getting into, before I sign up for a class?
  • ...

After you've asked these questions, you start to wonder about a University's purpose. If a main goal is providing the best education possible to the greatest number of people, why do I need to ask these questions? Why isn't this stuff already done, if it's so very clearly possible?

It seems to me that the academy, like many crusty institutions, could stand the motivation that transparency and competition would create.

Don't get me wrong. I'm not saying this stuff must be free in every case. Freely-available material, especially in the case of publically-funded institutions, would be best, but I'd be more than willing to dig into my own pockets, if someone offered that which I seek: ADUni-like material (but better and constantly evolving) for everything I'm interested it.

It’s what’s for dinner

Saturday, August 27th, 02005

Beef, broccoli, chile rellanos, and aggressive supplementation: It's what for dinner.


dinner

Name That Tune

Saturday, August 27th, 02005

[http://bohnsack.com/audio-posts/stng.mp3]

Spenser Loves Coffee

Friday, August 26th, 02005

Spenser's written something about coffee that you can read over here. He should get a blog.

Standing in line for coffee during RAGBRAI
Standing in line for coffee during RAGBRAI

Rails App Hosting

Thursday, August 25th, 02005

This screencast showing off the new RailsAppHosting service is a must view. When they go live, you should be able to get an account and start developing (and maybe even deploying) your Rails app, with everything in subversion revision control, in a very short time via a turn-key web interface.

Another Rails-related discovery: the Hieraki wiki app seems worth looking into.

School Started Yesterday

Wednesday, August 24th, 02005

School started yesterday with ECE 538 - Advanced Computer Architectures. The course goals are listed as:

  1. To understand the fundamental mechanisms involved in computer architectures and how they contribute to the overall functionality of the computer system.
  2. To develop abilities in modeling the effectiveness of these mechanisms to determine if the technique should be used in a particular application.

Topics are to include:

  • Instruction Set Development
  • Fundamentals of Pipelining
  • Dynamic Pipeline Activities
  • Memory Systems - Caching
  • Memory Systems - Virtual Memory
  • MIMD - Shared Memory
  • MIMD - Message Passing (with a material on interconnects that make this possible)
  • SIMD - Vector Processing
  • Other - VLIW, Super-scalar, etc.

I don't have loads of formal training in this area beyond basic logic design, so some of the material in this class might be challenging, but I'm up to the task and am excited to learn. There's supposed to be an emphasis on a quantitative approach, which should prove pretty powerful. A large paper is due at the end of the semester where we are to "Select a concept, machine, technique, or mechanism; then, state whether it is good or not, defending your position with judicious use of appropriate metrics." Doing this work, especially the "with judicious use of appropriate metrics" part, will be instructive.

Sannier Blogs About Transforming a Major University’s IT Infrastructure

Wednesday, August 24th, 02005

My friend Adrian Sannier has recently taken a position at ASU as their University Technology Officer.

He's currently blogging about the issues that are coming up as his team plans and implements a next generation university IT infrastructure. You don't often see this kind of conversation happening in the open. It's highly recommended reading, if you're interested in the future of large-scale university IT and the thought that's shaping it.

Final RAGBRAI Photos Have Been Posted

Wednesday, August 24th, 02005

In case you've been waiting, all of my photos from this year's RAGBRAI were posted a few days ago.

A Pictorial Demonstration of Solaris Lameness

Tuesday, August 23rd, 02005

Sun's vi sucks

Parsing /etc/group in Ruby

Monday, August 22nd, 02005

Here's some Ruby code to parse /etc/group off the top of my head. There's probably a library to do this kind of thing, but I'm taking the opportunity as a learning experience. I know I'm not taking full advantage Ruby's expressiveness here, so... let's call it a challenge or a motivation to do it better in the future (but still creating the two data structures shown below (groups and users)):


#!/path/to/ruby
	
# groups = {'group1' => ['user1','user2',...], 'group2' => [...], ...}
# users  = {'user1' => ['group1','group2',...], 'user2' => [...], ...}
groups = {}
users  = {}
	
File.open('/etc/group').each_line do |line|
  if line != /^#/
    fields = line.chomp.split(':')
    groups[fields[0]] = fields[3].split(',') if fields[3]
  end
end
	
groups.each_value do |members|
  members.each do |member|
    users[member] ||= []
  end
end
users.each_key do |user|
  groups.each_pair do |group,members|
    members.each do |member|
      users[user] << group if member == user
    end
  end
end

An awesome update from the comments using part of the Ruby standard lib:

require 'etc'
	
groups = {}
users  = {}
	
Etc.group do |gr|
  groups[gr.name] = gr.mem
  gr.mem.each do |member|
    users[member] ||= []
    users[member] << gr.name
  end
end

Which brings to mind an obvious optimization to my original, continuing to avoid libraries:

groups = {}
users = {}
	
File.open('/etc/group').each_line do |line|
  if line != /^#/
    fields = line.chomp.split(':')
    groups[fields[0]] = fields[3].split(',') if fields[3]
  end
end
	
groups.each_pair do |group, members|
  members.each do |member|
    users[member] ||= []
    users[member] << group
  end
end

Further...

groups = {}
users = {}
	
File.open('/etc/group').each_line do |line|
  if line != /^#/
    fields = line.chomp.split(':')
    group = fields[0]
    members = fields[3] ? fields[3].split(',') : []
    groups[group] = members
    members.each do |member|
      users[member] ||= []
      users[member] << group
    end
  end
end

sackvsbeef.com is reborn

Friday, August 19th, 02005

Sackvsbeef.com has been reborn and is now aggregating Beef's blog with mine via Planet.

Awesome Doc Browser Plugin for Firefox

Wednesday, August 17th, 02005

Have all the docs for HTML, CSS, XUL, Ruby, and Rails always at your fingertips with this Firefox sidebar extension. (via RedHanded where you'll find a screenshot).

Back Posting RAGBRAI Stuff

Monday, August 15th, 02005

I'm going to be back posting RAGBRAI stuff starting tonight - one day of the ride, every night. Scroll down or click on the appropriate link:

X Day 0: Le Mars
X Day 1: Le Mars to Sheldon
X Day 2: Sheldon to Estherville
X Day 3: Estherville to Algona
X Day 4: Algona to Northwood
X Day 5: Northwood to Cresco
X Day 6: Cresco to West Union
X Day 7: West Union to Guttenberg

A One-liner with Rails and ActiveRecord

Monday, August 15th, 02005

I'm playing with setting up Typo as a replacement for Wordpress. Both of these packages are webloging software - you use them to make a blog. Typo's quite new, but its built with Ruby on Rails, which I'm interested in exploring, and it has a number of cool Web 2.0 features (AJAX search, etc.). Wordpress is a built with PHP, which isn't very sexy, but the package has been in development for a lot longer and is a little more mature as a result.

The Problem:

After using the conversion script supplied with Typo to copy data from my Wordpress database, convert it to Typo format, and finally save it into a new Typo database, everything was mostly good, except that all the image references were relative, instead of fully qualified. This was a small problem, because the referenced images weren't available via the server that I was testing Typo on -- not a critical deficiency in test mode, but I really wanted to see how Typo would display my real weblog entries - images and all. To make things show up nicely, I needed to replace every image reference with its fully qualified version.

That is, I needed to search each of my blog entries for every string that looked something like the following:

<img src="/images/foo/bar/biz.jpg">

Each time one of these strings was found, I needed to replace it with something like this (adding the bolded bit):

<img src="http://bohnsack.com/images/foo/bar/biz.jpg">

The Conventional Solution:

Most times, this kind of problem is solved by writing a script that loops through records obtained from a SQL SELECT, massages the data, and then does a SQL UPDATE to save every modified record. If you wanted to get this problem solved with Perl in this manner, it would look something like this:


#!/path/to/perl -w
	
use strict;
use DBI;
	
my $dbh = DBI->connect(''DBI:mysql:database=typo;host=localhost', 'username', 'password');
	
my $sth = $dbh->prepare('SELECT id, body FROM articles');
$sth->execute();
	
while( my $row = $sth->fetchrow_hashref() )
{
    $row->{'body'} =~  s/src=\"(\/.*.(jpg|gif|png))/src=\"http:\/\/bohnsack.com$1/g;
	
    $sql = 'UPDATE articles SET body = ? WHERE id = ?';
    my $sth2 = $dbh->prepare($sql);
	
    $sth2->execute($row->{'body'}, $row->{'id'});
}

The preceding code isn't hard to write in any language. A Ruby version looks fairly similar:


#!/path/to/ruby
	
require 'rubygems'
require 'mysql'
	
dbh = Mysql.real_connect('localhost', 'root', 'username', 'password')
	
dbh.query('SELECT id, body FROM articles').each_hash do |row|
	
  row['body'].gsub!(/src="(\/.*.(jpg|gif|png))/, 'src=\"http://bohnsack.com\1')
	
  dbh.query 'UPDATE articles SET body = \'' + Mysql.escape_string(row['body']) +
            '\' WHERE id = ' + Mysql.escape_string(row['id'])
end

There isn't a huge difference between the Perl and Ruby code shown above, but there is a fairly large difference, when you use the stuff that comes with the Rails framework. With Rails' ActiveRecord, we're able to get this task completed with just a single line of code...

The Rails Solution:


$ ./script/console
	
Loading development environment.
>> Article.find_all.each { |a| a.body.gsub!(/src="\/(.*.(jpg|gif|png))/, 'src=\"http://bohnsack.com\1');  a.save }

Wow! Pretty cool. I am the one-line-of-code commander.

Let's take this step-by-step:

  1. console is a script that comes with rails. It invokes Ruby's irb (Interactive Ruby Shell) and takes care of setting of setting up environment, loading libraries, and connecting to your database(s). It gives you a prompt and allows you to program in Ruby interactively:
    $ ./script/console
    Loading development environment.
    >>
  2. After invoking this script, we use the irb session to access the Article class and its find_all class method. This class springs forth almost automatically from the articles table, as it's defined in the database. There's no application-specific code, except for three lines that tell Article to use ActiveRecord as its base class. find_all returns an array of Article objects. In this case, the array contains an object for every article record in the database:
    >> Article.find_all
  3. Now that we have an array of Article instances, we can use one of Ruby's iterators (Array#each) to loop through each element:
    
    >> Article.find_all.each
  4. each expects a block (a major Rubyism). A block is a chunk of code delimited by curly braces or a do/end construct. The block gets run by each, with an Article object getting passed to the block via |a| during every iteration. In other words, the block is run for every object in the array, and the block has access to the object via a variable local to the block's scope, defined as the variable between the pipes (|a|):
    
    >> Article.find_all.each { |a| ... } 
  5. Because a.body, a member variable corresponding to the article table's body column, is a string, it automatically has the gsub! method. We use this method to search and replace with a regular expression:
    
    >> Article.find_all.each { |a| a.body.gsub!(/src="\/(.*.(jpg|gif|png))/, 'src=\"http://bohnsack.com\1'); ... } 
  6. Finally, we persist the changes made to each record back to the database by invoking ActiveRecord's save method. Before doing save, the record is only changed in memory - not in the database. When save is executed, ActiveRecord does a database UPDATE under the covers, without us having to write a single line of SQL:
    
    >> Article.find_all.each { |a| a.body.gsub!(/src="\/(.*.(jpg|gif|png))/, 'src=\"http://bohnsack.com\1'); a.save  } 

That's it. Simple, but very powerful, and all with only one line of code.

Updates Aug 17th:

  • Lots of good suggestions in the comments and here - I've implemented some of them, but I was just geeked that I got it to work, not really knowing what I was doing. The statement I created was mostly a result of bouncing on the tab key in irb, picking methods that looked good, looking at their inspect output, and then repeating a few times until everything worked.
  • Should have used find(:all) instead of find_all() (which is deprecated).
  • update_attribute() would have been cleaner that a.body.gsub!(); a.save()
  • Parentheses look better around methods that take more than one argument. I've made this change where I call gsub!().

Cinnamon is Damn Good for You

Monday, August 15th, 02005

It turns out that cinnamon is damn good for you - via Hog on Ice.

Half a tablespoon with my oatmeal every morning from now on...

The Regex Coach

Sunday, August 14th, 02005

If you use regular expressions, you might find the Regex Coach to be an awesome development tool.

RAGBRAI is Easy

Sunday, August 14th, 02005

Some people think it's a feat to make it across Iowa on RAGBRAI. It ain't nothing compared to The Trans Iowa Race: 2 days, 300+ miles, self-supported, rural gravel roads, COLD, and only 9 finishers this year. Wow!