Saturday, August 30, 2008

Perl vs Ruby

First off, an apology to Matt Harrison, who seemed to be deeply offended by my Perl vs Python article. That was not my intent. For the record, Matt did give a great presentation. The fact that he went so fast was because he was given less time than he thought he had, and I think he was trying to make up for it. His slides were killer, especially those that had a built-in Python shell. My post was only meant to reflect a few thoughts that I was having, and was not meant to convey a professional comparison of two things that I have no right to compare professionally. By the end of a few comments and replies, I had expressed some personal biases that I have. I tried to express them in as opinions, not facts, and I hope they were construed as such. Matt, I hope you didn't take it personally.

This post isn't meant to be a professional comparison of two languages either. I have yet to see a single line of Ruby code, mostly because I do not yet have the time, but I do have the inclination. I just wanted to express a few observations that I've made so far at the conference.

I met a lot of Ruby programmers there. I knew some beforehand as well, and there have been some recurring themes with these people. First of all, while none of them have said "I'm proud of the language that I have chosen to work in", at least not in actual words, you could see that sentiment just by listening to them talk. These people love the language that they work in, and they are very clearly proud of Ruby's many accomplishments. I talked to one gentleman in particular about Puppet, which he seemed to believe would replace cfengine in very short order. Interestingly, the one project that seems to be dropping in popularity is Ruby on Rails, which once seemed to be the thing that Ruby folk were most proud of.

I've also noticed that Ruby programmers generally refer to the language as "fun". I've lost track of the number of times I've heard the words "Ruby" and "fun" used in the same sentence. I've also found a lot of Perl programmers that have switched to Ruby, and they seem to be the ones that use those two words together the most.

Something else that I noticed at the conference was kind of new to me, which may be because I haven't been paying much attention to Ruby, except in extremely general terms. Whenever Ruby or a project in Ruby was mentioned, it was almost always accompanied by a statement about performance. And no, I did not hear a single soul (including and especially Ruby programmers) talk about good performance. Now, I know that performance isn't everything. Fact of the matter is, the best program written in assembly will always outperform anything written in any other language. So why don't we write everything in assembly? Because writing in assembly sucks, that's why. Performance isn't the only thing that counts.

One interesting thing that I noticed in Phil Windley's presentation about Apache was an offhand comment about Ruby. Phil's talk was really about using mod_perl with Apache. At one point he explained something about the request lifecycle, and said something to the effect of, "that's right Ruby programmers, this thing that you're all of a sudden so excited about, we've had for years in mod_perl." And maybe I was just imagining it, but it seemed that a lot of the people in the room were thinking, "and that's not all!"

Again, not a professional comparison. Not much of a comparison at all, really. Just observations. I don't think there are any conclusions to be drawn here except that Ruby programmers love and are proud of their language, and that Perl programmers still say smug things about their language. That's all. Thank you, drive thru.

Friday, August 29, 2008

Using cronolog with Apache and AWStats

I've been meaning to do this for a long time, I've just never gotten around to it. My access_log file for Apache is currently somewhere around 638mb, and starts somewhere around 2 1/2 years ago. I've always wanted to name my log files with the year and month, I've just never gotten around to it. Today Phil Windley made mention of cronolog in his UTOSC presentation, and my first thought was, "hey, I've been meaning to do that!"

Installation was easy:

yum install cronolog

Then a quick change to my httpd.conf file:

ErrorLog "|/usr/sbin/cronolog /path/to/error_log_%Y-%m"
CustomLog "|/usr/sbin/cronolog /path/to/access_log_%Y-%m" combined

The %Y will give you a four-digit year, %m will give you a two-digit month. Restart Apache, make sure everything works. Then edit your awstats.*.conf file:


Slightly different date syntax, but you get most of it: %YYYY is a four-digit year, %MM is a two-digit month. AWStats also includes a -n after the date code, which refers to the number of hours back to go. %YYYY-2 would mean whatever the year was two hours ago.

Guess what? That's it! If you're like me, and you want small log files sorted by date, this is the way to go. Apache doesn't do it by itself, and in retrospect it's probably pretty trivial to set something up, but cronolog is already there, and setting it up is even more trivial. AWStats already has support for date-stamped files built-in, so it's just as easy to set it up.

Have fun with that one.

Perl vs Python

I've been trying to learn Python lately. Yesterday I attended Matt Harrison's "90% of the Python you need to know" at the Utah Open Source Conference. Unfortunately, he was expecting to have 90 minutes and he ended up having about 60, so he said he would be able to cover 55% of the Python you need to know. He still tried to fit in as much as possible, and as a result he went really, really fast. I started out taking notes and trying out his examples as he lectured, and eventually gave up, hoping that I could get access to his slides and a recording of his talk later.

Still, I did get a good feel for a few things in Python. By the time he hit classes I was totally lost, but I better understand things like whitespace, a few basic commands, and kind of the whole idea behind Python. In fact, it was summed up pretty well in a command in the Python shell:

jhall@bourdain ~$ python
Python 2.5.2 (r252:60911, Jul 31 2008, 17:28:52)
[GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Later on I was looking for something inside the man pages, and I found myself in the man page for Perl. The first paragraph of that file also sums up that language really well, I think:

Perl is a language optimized for scanning arbitrary text files,
extracting information from those text files, and printing reports
based on that information. It’s also a good language for many
system management tasks. The language is intended to be practical
(easy to use, efficient, complete) rather than beautiful (tiny,
elegant, minimal).

Granted, I'm not the best programmer in the world, and I certainly don't know enough Python just yet to make a lot of observations on the language itself (though I have made some). But based on what the users of those languages are trying to tell me, in addition to my own limited observations here's what I'm ending up with:

Python values form over function, while Perl values function over form.

I'm not saying (at the moment) that Python is a bad language. I'm just saying that it has a different focus than Perl. A lot of Python programmers have done a lot of really good work in their language, but I'm not sure I like the amount of energy they put into not just making their code look pretty, but also forcing users to make their code look pretty. Apparently forcing users doesn't work, however. I've also had more than one Python programmer (including Matt) tell me that they've seen some really bad Python code.

Pretty much anybody that's worked in Perl has also seen (and probably written) some really bad code. A lot of early Perl hackers seem to forget that readability does count, and that just because it's awesome that you can do so much with a single line of code doesn't mean you shouldn't break it out into 4 or 5 lines of code.

One thought that occured to me several times yesterday was an ice cream analogy. Perl and Python are two different brands of exactly the same flavor of ice cream. Probably not vanilla, neither language should ever be accused of that. Maybe rocky road or tin roof sundae. The point is, Perl feels to me like the ice cream that somebody would make at home, while Python feels more like the ice cream that one would buy at the store. There is some really bad homemade ice cream out there, but there's also some really good stuff. And homemade ice cream, unless you have access to things like commercial stabilizers like me, generally only has a few ingredients, and they all have words that we can pronounce. And the taste may vary wildly, depending on the cook. Python, at the moment, feels like that commercial ice cream that I guy at the grocery store because I don't have the time or inclination to do it myself. The flavor is consistent, to the point where it almost tastes chemically clean. Right now I don't understand all of the ingredients, but I know some people that do, and they assure me that they're perfectly safe, and good.

That's how I'm feeling about the languages right now. That's subject to change as I learn more Python. I don't know that I'll ever switch to writing Python for production use, but when I'm done hopefully I can intelligently consider it, and whether or not it's appropriate for the situation. We'll see how it goes.

Saturday, August 23, 2008

Review: Valdosta Pecans

I haven't done a review for a while, so maybe this is due. This past week I picked up a bag of Valdosta Pecans by Sahale Snacks. This wasn't my first bag. Or second. Or even third. In fact, I've pretty much lost count by this point. I have become an addict.

First of all, Sahale Snacks has other nut blends as well. These are not your traditional trail mixes with a few cliche roasted peanuts plus some crappy dried fruit. Oh, no. These are high-end. There is some sugar, but not enough to be overpowering; just enough to stick some flavors together. There really isn't so much of an emphasis on nuts, despite being called a "nut blend". The focus seems to be on making a single dish of flavors that compliment and even enhance each other.

I've found however that if you don't like the nut that the blend is based on, you won't like the rest of the blend either, even if you would normally like all of the other ingredients separately. For instance, I didn't care much for Soledad, featuring "a sunkissed combination of almonds, flax seeds & tender dates, tickled with balsamic vinegar and cayenne". Man, that all sounds good... except for the almonds. I hate whole almonds. But I'm in the minority there.

Perhaps you'd be interested in Sing Buri, with "tastes of Lemongrass, soy-glazed cashews, pinapple, peanuts & sesame seeds, lightly dusted with Chinese chili". It all sounded so good, so perfect! But when I tasted it, the wow factor just wasn't there. Don't get me wrong, it was good. But again, just not my thing.

Then I tried Valdosta, "pecans with sweet cranberries, black pepper & orange zest". So simple. Such a beautiful list of ingredients. It has sweet, but also spicy. Cranberry and orange are a match made in heaven, and pecans only add to the delight. But that black pepper bit, that was just genius. I once bought two or three bags of this stuff at once, and it didn't last the weekend. And bonus: this stuff seems to be kind of good for you too. It has a little saturated fat and a little sugar, but it seems to come from the right places. The closest the ingredient list comes to sounding like processed food is "organic evaporated cane juice", followed by "organic tapioca syrup".

This is a great snack. It's extremely low in sodium, has no cholesterol, and no fake sweeteners. Not even a drop of corn syrup. But heed my warning well: this stuff is addictive. You may stop eating "real food" in favor of it. Then again, if by "real food" you mean a burger and fries, maybe filling up on this stuff will do you better anyway.

Sunday, August 17, 2008

nzbsize Revisited: slurp

My nzbsize program was nice and all, at least for small nzb files. Then I downloaded one that was big. It was real big. It indexed a 64gb Usenet post. I didn't realize when I downloaded it that it was that big. When I tried to see how big it was, nzbsize took forever. I glance at the source code, and knew exactly what was wrong right away. No, I'm not super-smart. It just isn't a long program.

The culprit is something that I think most Perl pragrammers take for granted. Let's say we want to work with a file. Perl's file operation commands are quick. But since Perl was originally designed as a reporting language (so they say), it normally only operates one line at a time. This makes sense. We pull in a line of data, we parse it, add it to the report, and continue with the next line.

But sometimes we want to work with multiple lines at once. Parsing HTML is a great example of this, since tags can easily span multiple lines. I think most Perl programmers, when faced with this situation, prefer to slurp in the whole file at once. I suspect a lot of Perl programmers had sitting in their arsenal for years a subroutine that just pulled in an entire file at one time. I called mine readfile. It looked kind of like this:

sub readfile {
my ( $filename ) = @_;
open INPUT, "<$filename";
my @contents = <INPUT>;
close INPUT;
return join '', @contents;

This became so common that the Perl developers finally gave us a built-in called slurp. But that wasn't introduced until Perl 5.10, which isn't exactly common at the moment. And really, it was just one of those pieces of functionality that was made for Perl 6, but that the devs decided to pull into Perl 5.x now because people wanted it now.

Since I'm not running either of those versions of Perl yet, I just renamed my sub to slurp. At one point I showed a piece of my code to Tene, who gave me an optimized version of the slurp sub:

sub slurp {
my ( $file_name ) = @_;
local $/;
open INPUT, "<$file_name";
return <INPUT>;

Perl programmers love optimizations. Tene told me once that Perl was about making life easier for the programmer, not necessarily the compiler, but I can't help but notice a lot of Perl programmers doing a lot of optimizations designed to make the compiler do less work. Most Perl programmers that I know thrive on this. Then again, I suspect that Perl programmers eventually start to think the same way as the compiler too (a side effect of the language itself, maybe?), and that makes for tight code.

When it comes down to it, my code still processed the file a line at a time. Sure, it shoved the whole thing into an array in one line of code, and then returned it joined into a string in another, but it was still doing a list operation, twice. Tene's optimization told the compiler to ignore line breaks, which basically turned the file into a single-item list, which was really just a scalar. Nice.

Now, think about my original nzbsize script. It slurped in a file, then it went through that file line by line looking for a byte value, which it then added to a grand total. Even using Tene's superior slurp sub, I was still processing the entire file a second time. In fact, since I was using a while statement and removing each byte count one by one, it had to reprocess the entire file again for each byte count that it encountered. Even on a smallish nzb file, that's going to be a lot of work for the compiler. On a file that indexes 64gb worth of data, well, on my little notebook it took somewhere around half an hour. That's just not good code.

So I went back to the way I should have done it in the first place. When it comes down to it, I'm running a report. And that report needs to be analyzed one line at a time. the new nzbsize program looks like this:


use strict;
use Number::Bytes::Human qw(format_bytes);

my $file_name = $ARGV[0];
my $bytes;

open INPUT, "<$file_name";
while ( my $file = <INPUT> ) {
$bytes += $1 if $file =~ s{bytes="(.*?)"}{};
close INPUT;

my $hr = format_bytes( $bytes );

print "$ARGV[0]: $hr\n";

This new piece of code returns the size of the nzb file in under a second. That's one 18mb file indexing 64gb worth of data, and the processor didn't even flinch.

jhall@bourdain nzb$ time nzbsize Lots\ o\ Data.nzb
Lots\ o\ Data.nzb: 64G

real 0m0.564s
user 0m0.440s
sys 0m0.020s
jhall@bourdain nzb$

Don't take things like slurp for granted. In the short run it may save a little typing, but in the long run it may cause serious performance issues. It's not just a matter of using the right tool for the right job, it's a matter of using the right version of the right tool. A claw hammer, a ball-peen hammer and a rubber mallet may look similar and the interface is pretty much the same, but I wouldn't use the rubber mallet to drive nails, and I wouldn't use the claw hammer to tap my new bathroom towel rack into place.

Friday, August 15, 2008

A Taste Experiment

I'm still unhappy about the chevre thing. But I suspect that most people who bothered to read it just thought I was nuts, or at least a little overzealous. So as an attempt to clarify myself, I think it's time for us to do a little taste experiment. With any luck, it will ruin you.

I need you to go find some foods that you like. I'll use some of my own favorite foods as an example, but the same principles will apply to whatever you choose. I'm going to start with fresh strawberries, and Nutella.

First, take a fresh strawberry and slice it in half. Tap the cut half against your tongue, just for an instant. What did it taste like? Did it taste like a strawberry? You might have caught a little zing. It probably didn't taste much like a strawberry though. It's kind of like when you start to plug a lamp into the wall, and then it doesn't make it all the way and falls out. There might have been a spark between the plug and the outlet, and the lamp may even have lit for a fraction of a second, but it was largely useless.

Go ahead and stick the half strawberry in your mouth, but don't chew it yet. Feel it with your tongue. Even if you washed it (you did wash it first, right?), the outside part of it probably feels a little rough. The cut side of it is much smoother, but is it completely smooth? Maybe not completely. Do you taste much strawberry? More than before, but you're still not experiencing the whole strawberry. So go ahead and chew it. Pay attention to the flavor, and the mouth feel. Have you ever spent so much energy tasting a strawberry? Go ahead and swallow it. You can eat the other half too, if you want to. When you're done, drink some water. You want your palate to be clean for the next part.

Grab yourself a spoonful of Nutella. You can tap it against your tongue if you want, like you did with the strawberry. Taste a taste of it. You don't have to lick off the whole spoonful all at once, save some for a second taste. While you're tasting it, think about the flavor and the texture. It's much smoother than the strawberry, isn't it? But is it completely smooth? Maybe it's a little gritty. That's okay. When dealing with things like chocolate, any particles larger than 20 microns will feel gritty to the tongue. Nutella doesn't have to go through the same process as chocolate bars, plus it has hazelnuts in it, so there may be some grittiness. Go ahead and finish off your spoonful, but don't drink any water just yet.

Before you drink any water, I want you to eat another strawberry. There's going to be some Nutella residue left, and that's okay. What you're tasting now is a burst of strawberry combined with the aftertaste of Nutella. The strawberry tastes a little different now, doesn't it?

This next part may remind you of a certain recent movie. With a clean spoon (no double-dipping), grab some more Nutella and another strawberry. Taste them together. Think about how they tasted separately, and now how they taste at the same time, each at full-strength. Do you like it? Was the strawberry sweet enough, or was it too tart? Could the strawberry have used more time to ripen on the vine? How well do the flavors match?

You might want to try this experiment again, using something other than Nutella. How about a spoonful of Hershey's chocolate syrup? Maybe a melted bar of Guittard chocolate. Maybe even a bar of Amano Chocolate. With each different type of chocolate, the experience is going to change. How about a different fruit? You might want to try raspberry or blueberry. Maybe a mango or pineapple. If you're really feeling daring, try lettuce or celery. Try something that you know will taste horrible. Light has no meaning if you do not also know what dark is.

We're not done yet, but it is time to move onto the next part. For this part you need three pieces of chicken. Go with whatever you like, but I would recommend chicken tenders because they're small, quick and easy to cook, and without seasoning they are probably the most flavorless part of the chicken. That's important. That's also why I didn't choose beef, lamb, bison, or some other strongly-flavored meat. Vegetarians, feel free to use three slices of zucchini or yellow squash. The idea will be close enough.

These three things need to be cooked. Use as neutral of a cooking oil as possible. Canola oil or cooking spray is fine. Olive oil is not. The first piece needs to be cooked with no seasoning at all. The second should be seasoned with salt and only salt. The third should be seasoned with one of the following: chile powder (and salt if the chile powder doesn't have any), Italian seasoning, herbs du Provence, Chinese 5 spice, garam masala, or whatever else you like. The point is, it needs more seasoning than just the salt and pepper. Be careful not to accidentally season one piece of meat with another piece of meat.

When it's finished cooking, go ahead and try the unseasoned chicken. Tastes like crap, doesn't it? Seasoning helps food taste more like itself. Without it, meat (and often other foods) are just not worth having. Try salting it and taking another bite. Better, but at this point you're just flavoring the food with more salt, not seasoning it.

Before you taste the second piece of chicken, rinse your mouth with water and taste a couple of grains of salt. Unless you really like salt, this will probably not be the most enjoyable experience of your life, especially if you used regular table salt instead of Kosher salt. When you have an idea of what salt tastes like on its own, rinse your mouth with water again and try the piece of chicken that was seasoned with just salt. It's better, isn't it? It might even be worth eating the whole thing. The salt has actually had time to get together with the chicken and mingle with it. The flavors have had time to marry, and that's important.

Go ahead and rinse your mouth with water again. Smell the spice mixture by itself. Does it smell the way you expect it to? Taste it. Does it taste the way it smelled? Rinse your mouth with water and try the piece of chicken that it was meant to flavor. Since you (or the spice blend) added salt to the chicken, it was properly seasoned. But the rest of the spices have also caused some seasoning to happen, and they've also added some flavoring. If you've chosen a spice blend that you like, this should be the best of the three pieces of chicken.

Think about how you ate those three pieces of chicken. I didn't tell you to let any of them linger in your mouth before chewing them, but did you anyway? After the strawberry experiment, I'm betting some people did. Hopefully some people also paid attention to things like texture, mouth feel, maybe even how dry or juicy the meat was, or how tender or tough, depending on how well it was cooked.

You don't have to do this next part right away, but I do encourage you to try it. Think about some sort of dish that you like to make that uses a spread. It could be as simple as a sandwich with mayo, or even a bagel with cream cheese. It could be more advanced, like a pasta or potato salad, again with mayo or maybe even just oil. I want you to make your dish again, exactly the way you normally do, but I want you to change the spread to something that you've never used before. If you're feeling ambitious, make the same dish twice, one the normal way and one the new way. On your bagel, try a slice of cheddar, or even a dollop of Cheez Whiz. On your sandwich or salad, try using bleu cheese or ranch dressing instead of mayo, or mayo instead of oil. Yes, I said ranch. I've never hidden my contempt for ranch dressing, and I'm not hiding it now. I've already done this particular experiment hundreds of times, and at least one of those did involve ranch. This experiment is now for you.

Compare your new creation with the old. Did the new ingredient improve your dish? Did it make it worse? Or has it become another way to prepare your dish, along with the one you already knew and loved? I encourage you to try this experiment again and again, on other dishes. Don't just swap out spreads, try pineapple instead of tomato in something. Lamb instead of chicken. Don't be afraid of anything, except possibly spending too much money. If you feel iffy about the possible outcome of your dish, try making a small test batch first. I don't want you wasting food.

Speaking of wasted food, we have now come to the next part of our experiment. Go to a local fast food chain and buy a burger. Then go to another and buy another burger. Maybe you could get together with some friends and have each one go to a different restaurant and pick up a burger. Don't go for anything fancy, just get the cheapest, plainest burgers you can find. This will probably work better with friends, because you can cut each of the burgers into portions to be shared with others. The last thing I want you to do is eat four whole burgers at a time, and I certainly don't want you to be wasteful. Vegetarians, make your own substitution. Go with a salad, a veggie burger, whatever you think is most appropriate.

But I do want you to sample four different burgers at the same time. If you can just get ahold of two or three, that's fine. You'll probably notice that each burger is vastly different from the others. Each burger joint has their own way of cooking the meat, their own type of buns that they use, and most certainly their own types of toppings and condiments that they add. Each of these things is important, and the combination of them will define that restaurant's offering. Take note of which ingredients you like, which ones you don't, and why. Did you not like that onion because it was raw? Would you have liked it better if it was cooked? Take these things into consideration.

For the last part, it's time to go shopping. Go to the grocery store and pick out a type of packaged product. It doesn't really matter which one you pick out. You could go with raspberry yogurt, chocolate pudding, wheat bread, even canned asparagus. The important thing here is that you pick up at least two different brands of the same item, making sure that you also get the same flavor for each kind. For instance, don't pick up banana-flavored Yoplait yogurt and strawberry-flavored Dannon yogurt.

I think you know what to do by now. You're comparing the two different brands. You're not just deciding which is your favorite brand, you're deciding why. Perhaps you like them both, but each has an element that you like that the other doesn't have. Maybe this brand is creamier, but this one has a stronger fruit flavor. Maybe one is too sweet, but the other isn't sweet enough. Maybe one would be perfect if they did such and such.

I hope you're able to try some of these experiments, maybe even all of them. What I'm trying to do here is teach you how to taste food. Once you know how to taste food, it will be that much easier to know how to eat food. Trust me, you're probably doing it wrong. And when you know how to eat food, then you will have some idea of how to cook food. You need to be aware of what your diners target audience is going through before you try to make them happy. If you are preparing food for somebody, your number one concern should be giving them the maximum enjoyment of your abilities. If you are cooking solely for technical merit or some crap, then I hope you're not cooking for anybody but yourself.

One last warning. Beware of snobbery. This world has a lot of great food in it. This week I found myself deciding whether to visit a high-end restaurant for dinner or a hole-in-the-wall little kabob place. Price was of little concern, since work was paying for it anyway. I'd been to both a few times, and greatly enjoyed them both. That night I decided that kababs were going to win out, though I did order a type of kabob that I hadn't tried before. I had no regrets about my decision then, and given the choice now, I might choose the kabobs again.

The point is, I would like you to refine your taste. But I don't want you to refine it so much that you can't be happy with the rest of the world. Maybe your mother-in-law's cooking doesn't surpass Thomas Keller's. I doubt that anyone's does. That doesn't mean you can't enjoy it when you go to visit. You should enjoy it, unless she truly is a horrific cook. Learn to enjoy the fine things in life, but not at the expense of the other things in life that make you happy.

Wednesday, August 13, 2008

"Add Some Chevre..."

It was a hot summer day in Austin. My first trip for Guru Labs, teaching my first Linux class. It must have been about Wednesday or Thursday. Early that week I had discovered two important things: the Whole Foods Market near the training center, and the fact that I was allowed to spend some of my per diem there, despite it not being a restaurant. I remember buying what I thought was high-end olive oil, and what I knew was only pretending to be high-end chocolate. I bought some actual dinner from the deli, and I recall it being overly-pretentious and pretty much sub-standard. And while I was on what felt like a small culinary shopping spree, I spotted the cheese counter. There it was, tantalizing me, taunting me. A fresh slice of goat cheese. I'd somehow never had it, and now I was going to try it.

Why did I want to try it? It was new. It was chic. It was a buzzword that all the chefs seemed to like to toss around. And I wanted to be just like them. And now I could gain that luscious glimpse into their world, experience yet another element that made them chefs and made me wish I was a chef. I brought it back to my hotel room, pulled out a plastic knife from the deli, and tasted my first morsel. My first thought was about how very fresh it was. My second thought involved a realization that it tastes extremely fresh. My third thought was little more than, "this tastes like grass clippings."

I was willing to keep an open mind. I've had goat cheese a few times since. Each time I was overwhelmed at how much it tasted like some body's lawn. It eventually found itself filed in the "gross, pretentious food" category of my brain. It wasn't something I gave much thought to after that, of course. Not unless it briefly crossed my path.

Like today. I'm a big fan of a blog called The Pioneer Woman Cooks. This woman is awesome, and apparently commands a small army of fans. Yesterday she posted about a failed recipe, and asked for ideas for improvement. The recipe looked like it should have been good, but there were elements that were obvious to me that should be changed. I thought I'd add my feeble comments, knowing that they were too far down for her to even notice them. Later I thought I'd check, wishing, hoping that perhaps she saw my comments and responded briefly to them. What I finally saw horrified me:

"607: Add some chevre to the cream cheese for a flavor boost."

GAH! For those who haven't clicked yet, the recipe is for what looks like an adaptation of the classic spinach and artichoke dip, minus the spinach. I was thinking in terms of complimentary flavors, and not hiding important ingredients with things like cream, just for the sake of adding cream. This person? I have no idea what they hoped to accomplish. There was nothing else to their comment. No reasoning for poisoning this dish with a flavor that even for one who liked that sort of thing would prove too harsh an element, tearing apart any cohesion that the other ingredients may have enjoyed. Seemingly, somebody thought they'd add their two cents worth with a buzzword, just to make themselves sound smart.

When I started thinking up ideas, I found myself several steps into mentally preparing for what I needed to pick up on the way home, what I needed to do when I got home, before I realized that I was a long way from home. I'm in Baltimore, which is not exactly a hop, skip and a jump away from Salt Lake. Heartbroken, I realized that I was not going to be able to attempt my creation that night. I now wonder, did this person even consider attempting their blasphemy? I kind of hope they do. Maybe they'll learn to think about flavors in terms of flavors, rather than buzzwords.

Wednesday, August 6, 2008


I came across a useful Perl module today called Number::Bytes::Human. I occassionally download files from the newsgroups using nzbperl, which tells me once it's started how big the download is expected to be. That's all well and good, but what if I want to find that out before starting up nzbperl?

I decided to write a quick script to extract the byte size from the .nzb file, but it occurred to me halfway through writing it that I didn't want to spend the brainpower this evening to make the output human readable (megabytes and gigabytes, as opposed to bytes). CPAN to the rescue! My script isn't long, so I thought I'd go ahead and post it here. I saved it as ~/bin/nzbsize, but you can call it whatever you want.


use strict;
use Number::Bytes::Human qw(format_bytes);

my $file = slurp( $ARGV[0] );
my $bytes;

while ( $file =~ s{bytes="(.*?)"}{} ) {
$bytes += $1;
my $hr = format_bytes( $bytes );

print "Bytes: $bytes\n";
print "Human Readable: $hr\n";

# Since I'm not running Perl 5.10 just yet
sub slurp {
my ( $file_name ) = @_;
local $/;
open INPUT, "<$file_name";
return <INPUT>;

The output's going to look something of like this:

jhall@bourdain nzb$ nzbsize Knoppix5.1.1.nzb
Bytes: 782635787
Human Readable: 747M
jhall@bourdain nzb$

Update: instead of using this version, you probably want to check out the optimized version.

Thinkpad R61i Review

My old laptop, nobu, finally bit the dust. Well, he's not entirely dead, but after five years, the screen has choked out its last viewable pixel. I'm actually surprised it took this long. The touchpad hasn't worked for years, and the optical drive has been pretty much worthless for even longer. I replaced the hard drive almost three years ago. The PCMCIA slots became worthless last November when the computer fell on the side that they were on, while a wi-fi card was plugged into one of them. And the proprietary, so-called quality that I've come to expect from Sony this past decade made opening the computer for any repairs pretty much impossible.

I had already been looking around at new laptops, and been giving serious consideration to Lenovo's Thinkpad series. I'd already decided that Dell was out of the question, and HP even more so. Plus, the majority of my coworkers have Thinkpads that they love, and with an office full of seasoned Linux geeks, that really says something. But since I just bought a new house and any small wealth I once had has been sucked into it, the infamous T61p was out of the question. Fortunately, Newegg had an R61i at a really great price, and I had them overnight one to me.

Rather than posting initial thoughts, I decided to give it a couple of weeks before posting what I thought about it. I think it takes at least that long to get a good feel for a piece of hardware like this. So far I have found things that I like, things that I don't like, and even things that I thought I wouldn't like that ended up being pretty okay.

The Bad

Let's get the bad things out of the way first. The touchpad seemed to work well, but after a few minutes typing, I found myself wishing it were about an inch and a half to the left, like it was on my old Vaio. Apparently Sony can do some things right, believe it or not. Some people at this point are wondering why I don't use the mouse nub that Thinkpads are so famous for, but I can't stand those things. In fact, it was one of the big reasons I considered looking at a different company altogether. But when the computer came with two replacement nubs, I realized I could just yank it out and not even think about it. File that with The Good.

I unfortunately ended up paying the Microsoft tax on this computer, but at least it was only the XP tax, and not sullied by the likes of Vista. I even booted to XP once. Just once. After a setup process that took several minutes, I was dumped to the once-familiar, hideous desktop that I had been forced to use in a previous life. It started out with two error messages telling me something about my anti-virus software, and some system update FUD. The desktop was already cluttered with icons that I would never click even if I ever used Windows, and was generally unfriendly from the start.

As much as I hate Windows, I decided to keep it. Not as my primary OS of course, but it still might come in handy. In particular, I have an old student copy of AutoCAD that I bought years ago that I still love, and have missed these past few years. If nothing else, that might be good enough reason to keep a Windows partition around. Unfortunately, the Thinkpad did not come with recovery discs. And unlike other models, it does not appear I can purchase them. They decided to set aside a FAT32 partition at the end of the drive with a copy, seriously hampering my abilities to repartition the drive for Linux. In the end, I used dd to make a copy of that filesystem, and then blew it away.

Unfortunately, when I killed the FAT32 partition the blue ThinkVantage button on the notebook stopped working. This seemed to be the primary way to get into the BIOS. But fortunately, I am still able to get to the BIOS's boot menu, which has an option to "Enter Setup". As you can imagine, I'm pretty unhappy with Lenovo by this point. But there are good things to say about this notebook.

The Good

Within hours of receiving my notebook, I had booted to an Ubuntu Hardy Heron Live CD to get a real OS going. Since Ubuntu ships GParted on their Live CDs, resizing the Windows NTFS partition down to 20 gig was trivial. Had I been thinking I would have popped up fdisk, made note of the starting and ending cylinders for the FAT32 partition before blasting it away. It was marked as a primary partition, and I wonder if I could have made it a logical partition later on and still had the ThinkVantage button work. I guess it's gone anyway.

I set up some Linux partitions and got Ubuntu's Hardy Heron release installed. In only a matter of minutes, I had a dual-boot set up with XP and Ubuntu, with Ubuntu as the default. When I booted to Ubuntu, it was configured. The install program had asked for far less than the Windows XP setup thingy, and on the first boot I was given a desktop that just worked. A review of Hardy itself will have to wait for another post. Here I'm going to focus on how the Thinkpad worked with Hardy.

Right off the bat, I started testing some of the special buttons on the Thinkpad. The mute and volume buttons worked right off the bat. When I opened Rhythm box, the Fn key plus the arrow keys were able to control it without a problem, even when it was on a different virtual desktop. Bluetooth works out of the box, but it was kind of a pain to find an interface for it. Fortunately, I was able to find several sites willing to tell me how to map Fn+F6 to toggle it. Most of the other Fn buttons seemed to work right off the bat, even including the external VGA functionality, which works beautifully in Linux, as opposed to my old Vaio which would fuzz out on VGA the second it went to any graphical mode.

Wireless also worked out of the box, as did the built-in ethernet jack. And I have blinky lights on my ethernet port! I'd been wishing I had them on the Vaio. A guy shouldn't have to check ethtool every time he needs to see if the hotel network jack is even active. I haven't had a chance to test the PCMCIA slots since, well, what am I going to use them for? The only thing I used it for on my old notebook was wireless, and that's built-in now. I also haven't had the chance, or even inclination to test the modem. It's almost a waste of real estate and resources.

Speaking of a waste of real estate, I also haven't played with the fingerprint scanner. I don't know how much it added to the cost of the machine, but if I could have bought an identical model minus the fingerprint reader and its associated cost, I would have. Some of my coworkers tell me that it's great in Ubuntu, but I've never been a fan.

This model came with a DVD/CD+/-R/RW burner. Sweet! It's not that my external burner really took up a lot of space in my luggage, but I'm glad to no longer have to pack it with me. And even better, this drive is removable! If it dies, I still have a nearly-identical burner laying around that I bought for my Vaio before I realized that actually repairing and replacing parts in a Vaio is no more than a shattered dream.

There are two keys on the keyboard next to the arrows that I haven't figured out. Each one looks like a page with the corner bent over, with one having an arrow pointing to the left, and the other having an arrow pointing to the right. I don't know what they were supposed to do in the Wild Wacky World of Windows, but it would be kind of cool if I could map them to something in Linux, like switching virtual desktop. The arrow keys are in a decent place, but I still haven't gotten used to the odd placement of the Insert, Delete, Home, End, PgUp and PgDn keys. I imagine that will come with time. It always takes time getting used to a new keyboard. The fact that this keyboard is slightly smaller than the Vaio took about a week to get used to.

There are three USB ports on this guy, two on the left side and one on the right. I have had zero problems with them. I also have a firewire port on the front. I have had zero need to test it. I did note with some dismay that it is the mini variety, which has given me no end to troubles in the past. I don't expect to use it in the future.

In short, while there is some hardware that I'm probably not ever going to bother with, but with the exception of the ThinkVantage button, the stuff that matters all works with Ubuntu. With the exception of the misplaced touchpad that my right palm keeps touching as I type, I find myself far more productive than I ever was on my Vaio, even though the processor is only slightly faster, the hard drive is only slightly larger, the keyboard is just slightly smaller, and the screen is just slightly wider.

All in all, this seems to be a great notebook for just about any Linux user. In fact, Linux seems to work even better on it than the copy of Windows that it actually shipped with. I wish that Newegg could sell an Ubuntu version of this guy, saving me the cost of the Microsoft tax. I'm increasingly starting to wonder how anybody takes Windows seriously anymore. It lost out to Linux in the server arena long ago (if indeed it ever was ahead), and now it's started to lose out in the desktop world as well. I guess now I'm getting preachy. Sorry about that. The point is, if you're looking for a good notebook to run Linux, I don't see how you could go wrong with a Thinkpad, especially the R61i.