Last night, I spent several frustrating hours trying to untangle a problem with the update manifest for my Firefox extensions. After releasing my updated extensions, I noted that while CoLT automatically updated without any problems, Googlebar Lite did not. I double-checked, triple-checked, and even quadruple-checked everything I was doing. Everything I had done for CoLT was exactly what I was doing for Googlebar Lite. But the automatic update consistently failed.

As past experiences have taught me, simply walking away from the problem is occasionally all that is needed. Taking a mental break is a surprisingly effective way of going directly to a problem's solution. And this is exactly what happened last night.

Being well past my usual bed time, and having made no progress towards a solution, I decided to call it a night, and so headed to the bathroom to take a shower and brush my teeth. As I stepped into the shower, the solution instantly occurred to me! I was incorrectly using a wild card in the minVersion value in my installer manifests (2.0.0.* instead of 2.0). Immediately after getting out of the shower, I rushed to test the solution. Lo and behold, it worked.

Sometimes, all it takes is walking away.

At work, I'm in charge of 20 individual build systems for one of our larger software project (18 Linux systems and 2 Windows systems). Every machine is connected to a private network that cannot see the outside world. As you might expect, the occasional "clock skew" warning would be thrown by gcc, since some of the source files had date stamps in the future. To fix this, I set out to learn about configuring NTP on a private network. As is typical of the Linux world, there was little useful documentation to be found. After gleaning little bits of information from a number of sources, I figured out how to do it, and I'm writing it down for everybody's benefit.

Creating the NTP Master Server

Our first step is to create a 'server' machine from which all of our other machines will get the time. In this tutorial, our master machine is a Linux box. Here's how to set things up:

Step 1: Edit ntp.conf
The first course of action is to edit the ntp.conf file in the /etc directory. Place the following lines in this file, removing any others that may exist (you may want to back up your existing ntp.conf file just in case):
# Use the local clock
server 127.127.1.0 prefer
fudge  127.127.1.0 stratum 10
driftfile /var/lib/ntp/drift
broadcastdelay 0.008

# Give localhost full access rights
restrict 127.0.0.1

# Give machines on our network access to query us
restrict 192.1.1.0 mask 255.255.255.0 nomodify notrap
You'll want to replace the highlighted sections with the private network address range that should be allowed to query this server, along with the corresponding mask, respectively. In this example, any machine on the 192.1.1.xxx network can query the master server for time updates.
Step 2: Restart the NTP daemon
Once the above changes have been made, the NTP daemon needs to be restarted. How to do this unfortunately differs among Linux distributions. Here are a few commands that I figured out for the OS families I care about:
  • RedHat: service ntpd restart
  • SLES 8/9: /etc/init.d/xntpd restart
  • SLES 10: /etc/init.d/ntp restart
Step 3: Configure NTP to start on reboot
Perhaps the most important step in this process is configuring the NTP daemon to start up on a reboot. Here's how to do it:
  • RedHat: chkconfig ntpd on
  • SLES 8/9: chkconfig xntpd on
  • SLES 10: chkconfig ntp on

Configuring the Client Machines

Step 1: Edit ntp.conf
Client machines must also have their ntp.conf file updated (again, in the /etc directory). Place the following lines in the configuration file:
# Point to our network's master time server
server 192.1.1.100

restrict default ignore
restrict 127.0.0.1
restrict 192.1.1.100 mask 255.255.255.255 nomodify notrap noquery

driftfile /var/lib/ntp/drift
Both of the highlighted sections above should point to the master server (in this case, with an IP address of 192.1.1.100).
Step 2: Stop running NTP daemons
Use one of the following to stop any running NTP daemons:
  • RedHat: service ntpd stop
  • SLES 8/9: /etc/init.d/xntpd stop
  • SLES 10: /etc/init.d/ntp stop
Step 3: Force an update
We must force the client to update now, in case the offset is larger than 1000 seconds (the largest offset NTP allows). To do this, issue the following command:
ntpdate -u 192.1.1.100
Again, replace the highlighted section with the IP address of the master server. Note that you may need to do this forced update two or three times to make sure things are synchronized.
Step 4: Start the NTP daemon
Now that we've synced the client, we should restart the daemon:
  • RedHat: service ntpd start
  • SLES 8/9: /etc/init.d/xntpd start
  • SLES 10: /etc/init.d/ntp start
Step 5: Configure NTP to start on reboot
Finally, we need to make sure the daemon starts up at boot time (like we did for the server):
  • RedHat: chkconfig ntpd on
  • SLES 8/9: chkconfig xntpd on
  • SLES 10: chkconfig ntp on

Once you've set this up, all the client machines will keep their clocks synchronized with the master. If you update the master server time, the clients should follow (as long as the update isn't larger than 1000 seconds). I believe you can even point Windows systems to the master, though I have yet to try that.

I have now migrated this website to WordPress 2.5. Better yet, my installs are now managed with Subversion, which will make future updates as easy as issuing a single command from my web-server command line. This all comes thanks to a handy article in the WordPress Codex that gives step-by-step instructions.

This new install was done in a virgin folder (for subversion's sake), and I had to copy existing files over to the new location. If you spot any breakage, please let me know and I'll fix it.

WordPress 2.5

Mar 30, 2008

The latest release of WordPress is now available. I've installed it in a sandbox, and I have to admit that I really like the new look of the admin area, courtesy of the folks at Happy Cog (Jeffrey Zeldman, Jason Santa Maria, and Liz Danzico specifically). Thankfully, my theme still works in the new version, as does Spam Karma and Official Comments.

I want to spend a little more time with the sandbox, but I'll probably migrate this site to 2.5 in the next few days.

Google recently enabled "Search Suggest" at their official home page. I find this feature annoying, and I wanted a way to disable it. Thankfully, the solution was very simple:

  1. Visit the Search Preferences page
  2. Set the Query Suggestions option to "Do not provide query suggestions in the search box"
  3. Save your preferences

I wish Google had made disabling this a little clearer, rather than quietly adding the preference to the preferences page.

For some time now, Firefox has supported an experimental CSS technique for rounding border corners (-moz-border-radius). The rendering engine in Firefox 2 does a barely acceptable job with this, though the rounded corners don't appear to be uniformly sized, nor are they anti-aliased. Cairo, which drives the rendering engine in Firefox 3, does a much better job at handling the rounded corners, and the results are quite nice.

As such, I'm offering some 'eye-candy' to those users who visit this site with either Minefield or a Firefox 3 beta build. Those users will now note that code blocks (pre elements), as well as comment blocks, have nicely rounded edges. The end result looks great, and I hope you agree.

By default, Windows Explorer opens up in the "My Documents" folder, which is far from useful (assuming you don't store all your documents there). Just today, I figured out how to get Windows Explorer to open in a folder that you specify. Here's how to do it:

  1. Right click the Windows Explorer shortcut and select Properties.
  2. Make sure you are on the "Shortcut" tab.
  3. Clear the Start in: field. Contrary to what you might think, Windows Explorer seems to ignore whatever you type here (which seems stupid to me).
  4. Change the Target: field to the following:
    %SystemRoot%\explorer.exe /n,/e,{Desired_Path}. For example: %SystemRoot%\explorer.exe /n,/e,C:\. Note that the commas are required!
  5. Accept your changes.

Now, each time you open Windows Explorer, it will point to your desired location. This is an incredibly useful tip that will now save me two clicks for every explorer window that I open!

Playing in a Minefield

Mar 13, 2008

For the most part, I haven't spent much time with Minefield. Firefox 2 works well enough for me that I haven't had much desire to play around with the new stuff, especially seeing as many portions are inevitably either incomplete or broken. However, the recent beta 4 release prompted me to take it for a spin around the web. Here are a few thoughts on the latest build I've tested as of this writing (2008031205):

New Look
The new skin is interesting, but portions of it will definitely take some getting used to. Surely it's not final (these things never are until the thing is actually released), so I'm hopeful there will still be a few tweaks. When using large toolbar buttons, the back button appears round, while the forward button is much smaller and rectangular; an odd pairing which is reminiscent of Internet Explorer 7. I tend to use the small toolbar buttons, so this change doesn't affect me too much. The forward and back history menus have been consolidated into one menu (again, like IE7), which I think is a nice improvement. The new URL bar looks nice and provides a lot more information than the previous one did. A little star icon at the far right of the bar provides a quick means of bookmarking the current page, which is handy.
Improved Memory Usage
I put the new build through its paces at Google Maps, dragging around, zooming in and out, and generally trying to run up memory consumption (which I did successfully). After closing the corresponding tab, I noted that memory usage dropped considerably, and continued to decrease over time. The new garbage collection and memory defragmentation that has been implemented is clearly a big improvement. Firefox is still a hog, but it's heading in the right direction.
Faster JavaScript
The JavaScript improvements which I recently mentioned are immediately noticeable. GMail and Google Maps feel a lot faster than they typically do, which is super great.
URL Bar Autocompletion
Autocompletion in the URL bar is now handled in a new (and exciting) way. As you type, matches are offered based on all text associated with a link. The page title, the URL itself, and bookmark keywords are all searched. Matched text can appear anywhere in the string, which is really handy.
Password Manager Prompts
The password manager now slides down from the top (like the information bar), so it's not quite as intrusive. However, the handy keyboard shortcuts are no longer the same. In order to quickly answer the 'Not Now' choice, you have to press Alt+N instead of just N. This will take some getting used to.
Page Zoom
The new page zoom feature works really well. Images are magnified, as is the text on the page. There's even an option to only zoom the text, leaving images alone. Pretty neat!

There are plenty of other changes in Minefield, so I recommend checking it out. I am starting to work on adding FF3 support to CoLT and Googlebar Lite, but it's turning out to be a little more difficult than I initially thought. A host of code changes are needed in Googlebar Lite, since I'm currently using interfaces that are now deprecated. Hopefully I can get things updated in the near future.

SlickEdit 2007 Rocks!

Mar 7, 2008

My license for SlickEdit at work was renewed recently, so I upgraded to SlickEdit 2007, the latest release of this already amazing program. A boat-load of new features are included in this new release, but my absolute favorite is the new dynamic surround feature. Check out this demo of the feature in action (be sure to turn up your speakers; the sound is a little low). How super cool is that? I have actually wanted this particular feature for some time, so I'm very excited that it has actually been implemented. You can even unsurround things, should you choose to do so!

There are plenty of other great new features to be had:

  • Improved XML / HTML formatting
  • Export documents to HTML (preserving all syntax-highlighting ... how great is this?!?)
  • Copy and paste in color
  • Drag and drop support in KDE and Gnome
  • Get live errors in Java as you type (similar to the corresponding functionality in Eclipse, I assume)
  • And more!

You can check out the complete list [PDF] of new features (all 5 pages worth) at the SlickEdit website. I'm seriously considering upgrading my license at home, though the $139 upgrade price is pretty steep. If you are in the market for a good code editor, I strongly recommend SlickEdit.

Never before I have felt so connected to a Penny Arcade comic. I recently picked up Professor Layton and the Curious Village, a puzzle-adventure game for the Nintendo DS. After roughly 10 hours of game play, I've completed the game, so I thought I'd post some thoughts on it. Before we get to that, however, I'd like to explain how this game works.

Professor Layton is one of those hybrid titles like Puzzle Quest. It is neither an adventure game, nor is it a puzzle game; it's somewhere right in the middle. Layton himself is a private detective of sorts who is hired to figure out a puzzling will left behind by the late Baron Reinhold. Along with his assistant Luke, Layton quickly finds himself in an ever-increasing mysterious situation. There are twists and turns all over the place, and plenty of mysteries to be solved in the process.

Each person you meet will give you clues to the ever increasing list of mysteries you encounter, but only if you solve a puzzle for them. And by puzzle, I mostly mean 'brain teaser.' The puzzle difficulties are all over the place in this game. Some puzzles are easy to solve, while others will have you banging your head against a hard surface in frustration. There's a hint system in the game that offers you three hints per puzzle, which is often enough to help you figure things out, but sometimes the hints are themselves quite cryptic. Getting a hint costs you a 'hint coin,' of which there are a limited amount (though plenty are hidden throughout the game world). When you solve a puzzle successfully, you are awarded a number of 'picarats' (essentially points). Each puzzle is worth so many of these picarats, with harder puzzles being worth more. Answer incorrectly and the value awarded goes down. I'm not sure what this point system is good for. At one point you learn that if you get enough of these picarats, something special happens. I never saw anything happen as a result of my score, so I must not have gotten enough. But enough about these details. Let's jump into my review.

The Good

Gorgeous Graphics
Professor Layton is drawn in an anime-style, with a distinctly European vibe. This particular title feels a little like something Hayao Miyazaki and his friends at Studio Ghibli would do, much in the vein of Howl's Moving Castle (a great movie, by the way). Not only does the static art look great, but there are a number of animated cut-scenes which are stunningly nice to watch. Hopefully more games will make use of this visual style!
Interesting Story
The storyline is quite unique, which is refreshing. I really felt as if I were playing through a movie, and the twists and turns throughout the story were entertaining. Much of the writing is top-notch, and a few genuinely funny moments made me laugh out loud.
Plenty of Puzzles
There are a total of 120 puzzles in this game, which offers plenty of game-play time. I only found about 100 of the puzzles (some of them are hidden in various parts of the village), so I plan on playing through one more time to make sure I find everything. Several mini-games (or mini-puzzles, whichever you may prefer) are also made available to you as you play through. You must build a device with 'gizmos' that you find, repair a painting via scraps that you find, and furnish the living quarters of both the Professor and Luke. The publisher even offers weekly downloads of new puzzles, though I haven't tried out that feature.
Great Voice Acting
A few of the animated cut-scenes include voice acting, the quality of which is excellent. The characters sound believable, and it's clear that a lot of work went into giving each one a unique personality.

The Bad

Difficulty Extremes
One of the most frustrating aspects of this game is the wildly varying difficulty levels between puzzles. Some are very straightforward, while others are ultimate mind-benders. A few of the puzzles had fairly low difficulty ratings in game, but I found myself stuck, indicating to me that not all of them are rated as accurately as they should be.
Little Punishment for Failure
There is very little punishment for failure on any given puzzle. Suppose you have a puzzle that's worth 50 picarats. Each time you fail, the value comes down by 5. But this deduction only ever happens 3 times. So, regardless of how many times you try this particular puzzle, you will score at least 35 picarats. This essentially means that you can brute force each puzzle, especially those that offer multiple choice answers. This feels like a cheap way to beat the system (though it's a handy way to get past those truly difficult puzzles).
Repetitive Music
The music, while not gratingly annoying like in Puzzle Quest, is very repetitive. To my knowledge, there's no way to turn it off either. You could turn down the DS speaker volume, but you might miss the audio in a cut-scene as a result (and you definitely don't want to do that). An option to disable the game music would be very welcome.
Over-sensitive Handwriting Recognition
Handwriting recognition is used throughout the game for you to enter answers to various puzzles. It seems a little too sensitive to me, and doesn't give you nearly long enough to write some characters that require two or more strokes (the letters T and F for example). As a result, some trial-and-error is required in order to answer correctly.
Not Enough Voice Acting
As impressed as I was with the animated cut-scenes and voice acting, I was disappointed that there wasn't more of it. The little snippets we get are truly high quality, but more would have been great.
Little Replay Value
Once you've solved all the puzzles, there's very little to draw you back to this title. The weekly puzzle releases from the publisher are interesting, but I doubt I'll keep up with them.

The Verdict

This was a fairly fun game, and I really loved the art direction. While each puzzle is unique, they get a little monotonous after completing 75 or so. I have to admit that I was really tired of the game by the end, but my desire to solve each mystery I uncovered kept me going. At least one sequel is planned for Professor Layton. Unless the gameplay is tweaked, I'm not sure I'll pick up any subsequent titles. But this initial offering was entertaining, at least for a little while. The eye candy and unique story are worth the price of admission. My final verdict: B

The Acid3 test for web browsers has been released. Drunken Fist has a number of screenshots that show the failure rate among the various top browsers. There are some really interesting results from the tests:

  • Safari 3: 39% success (latest nightlies are up to 87%)
  • Firefox 3: 59% success
  • Firefox 2: 50% success
  • Opera 9: 46% success
  • IE 7: 12% success
  • IE 6: 11% success

Safari is the surprising top dog in the list, but what I find most interesting is that Firefox 3 (which passes the Acid2 test) only hits 59% in the new test. I would have guessed that being Acid2 compliant would mean being nearly Acid3 compliant. Apparently, that isn't the case. It looks like web browsers still have a long way to go in the standards race.

I ran into an interesting side-effect with the foreach loop in Perl today. I'm surprised that I haven't hit this before, but it may be a subtle enough issue that it only pops up under the right circumstances. Here's a sample program that we'll use as an example:

#!/usr/bin/perl
use strict;
use warnings;

my @array = ("Test NUM", "Line NUM", "Part NUM");

for (my $i=0; $i < 3; $i++)
{
    foreach (@array)
    {
        s/NUM/$i/;
        print "$_\n";
    }
    print "------\n";
}

What should the output for this little script look like? Here's what I assumed it would be:

Test 0
Line 0
Part 0
------
Test 1
Line 1
Part 1
------
Test 2
Line 2
Part 2
------

But here's the actual output:

Test 0
Line 0
Part 0
------
Test 0
Line 0
Part 0
------
Test 0
Line 0
Part 0
------

So what's going on here? Well, it turns out that the foreach construct doesn't act quite like I thought it did. Let's isolate just that loop:

foreach (@array)
{
    s/NUM/$i/;
    print "$_\n";
}

We simply loop over each element of the array, we do a substitution, and we print the result. Pretty simple. Pay attention to the fact that we are storing each iteration through the loop in Perl's global $. The point here is that $ doesn't represent a copy of the array element, it represents the actual array element. From the Programming Perl book (which I highly recommend):

foreach VAR (LIST) {
    ...
}
If LIST consists entirely of assignable values (meaning variables, generally, not enumerated constants), you can modify each of those variables by modifying VAR inside the loop. That's because the foreach loop index variable is an implicit alias for each item in the list that you're looping over.

This is an interesting side effect, which can be unwanted in some cases. As a workaround, I simply created a temporary buffer to operate on in my substitution call:

foreach (@array)
{
    my $temp = $_;
    $temp =~ s/NUM/$i/;
    print "$temp\n";
}

An easy fix to a not-so-obvious problem.

Firefox 3 Gets Faster

Feb 28, 2008

A special nightly build of Firefox 3.0 has been released that greatly improves JavaScript performance. The build was run against the SunSpider JavaScript Benchmark, and the results are really surprising. From the article:

  1. Firefox 3 Nightly (PGO Optimized): 7263.8ms
  2. Firefox 3 Nightly (02/25/2008 build): 8219.4ms
  3. Opera 9.5.9807 Beta: 10824.0ms
  4. Firefox 3 Beta 3: 16080.6ms
  5. Safari 3.0.4 Beta: 18012.6ms
  6. Firefox 2.0.0.12: 29376.4ms
  7. Internet Explorer 7: 72375.0ms

This optimized build is nearly 4 times faster than the current release of Firefox, and 10 times faster than IE 7; pretty cool!

I have yet to switch to Firefox 3, mostly because lots of my favorite extensions don't yet work (including the ones I've written). There are a handful of changes that have to be made in order for extensions to work in the new environment, some of which aren't exactly trivial. As we get closer to an actual release, I'll do my best to update my extensions.

As if we needed any more proof that CAPTCHAs don't always work, it seems that spammers have now successfully cracked the GMail CAPTCHA. A one-in-five success rate is being reported, and it appears that there are multiple bot-nets taking a tag-team approach in hacking the sign up process. This is particularly dangerous, since Google's domains are highly unlikely to be blocked by any website or ISP.

I don't know what the solution to this problem is (if I did I'd be rich), but hopefully Google will figure out a way to prevent this kind of nefarious activity from continuing to happen.

Slashdot is running a story on RoadRunner intercepting domain typos. My dad noticed this 'feature' a few weeks ago, and opted out via their preferences page. In addition to the Slashdot story, Ryan Govostes has an interesting article (written back in December) on the security holes lurking in this opt-out program. According to his post, one could wreak all kinds of havoc with TWC's poorly written page, enabling or disabling the service for essentially all RoadRunner customers. SQL injections also appear to be a possible line of exploits.

A little over a year ago, I inherited a productivity tool at work that allows users to enter weekly status reports for various products in our division. The tool is web-based and is written entirely in Perl. One of the mangers who uses this tool recently suggested a new feature, and I decided to implement it using cookies. Having never implemented cookies from a programming perspective, I was new to the subject and had to do some research on how to do it in Perl. It turns out to be quite easy, so I figured I would share my newfound knowledge:

Creating a Cookie

Although there are other ways to do this (as always with Perl), this tutorial will be making use of the CGI::Cookie module. It makes creating and reading cookies very easy, which is a good thing. Furthermore, this module ships with virtually all Perl distributions! Here's a chunk of code that creates a cookie:

use CGI qw(:all);

my $cgi = new CGI;
my $cookie = $cgi->cookie(-name => 'my_first_cookie',
                          -value => $someValueToStore,
                          -expires => '+1y',
                          -path => '/');

print $cgi->header(-cookie => $cookie);

I first import all of the CGI modules. This isn't exactly necessary, and it might be a little slower than using the :standard include directive, but I needed a number of sub-modules for the tool I was writing. I then create a new CGI object, and use it to call the cookie() subroutine. This routine takes a number of parameters, but the most important ones are shown.

The -name parameter is simply what you want to name this cookie. You should use something that clearly identifies what the cookie is being used for (though you should always be mindful of the associated security implications). The -value parameter is just that: the value you wish to store in the cookie. I believe cookies have a bounds of around 4K of storage, so remember to limit what you store. Next up is the -expires parameter, which specifies how far into the future (or past) the cookie should expire. The value of '+1y' that we specified in the example above indicates we should expire in one year's time. Values in the past (specified with a minus sign) simply indicate that the cookie should be expired immediately. No value will cause the cookie to expire when the user closes their browser. Finally, the -path parameter indicates for what paths on your site the cookie should apply. A value of '/cgi-bin/' for example will only allow the cookie to work for scripts in the /cgi-bin folder of your site. We specified '/' in our example above, which means the cookie is valid for any path at our site.

Finally we print our CGI header, passing along a -cookie parameter with our cookie variable. As always, the documentation for the CGI module will give you lots more information on what's available.

Reading a Cookie

Reading back the value stored in a cookie is even simpler:

use CGI qw(:all);

my $cgi = new CGI;
my $someValue= $cgi->cookie('my_first_cookie');

Again we create our CGI object, but this time we use it to read our cookie, simply by calling the cookie() routine with the name of the cookie we created before. If the cookie is found, the stored value is read and stored into our variable ($someValue in the example above). If the cookie is not found, a null value is returned.

One Gotcha

In the tool I was working with, I was handling storing and reading the cookie on the same page. Since we have to create our cookie via the header() call, I was concerned about how to handle the case where we weren't creating a cookie. The solution, it turns out, is pretty simple:

use CGI qw(:all);

my $cgi = new CGI;
unless (param())
{
    print $cgiquery->header;
}

In this example, we print out a generic CGI header only if no parameters were passed in (i.e. the user didn't push us either a POST or GET). If we do have parameters, we want to create a cookie, and we'll send the header after we have done so. Pretty easy!

The long awaited Team Fortress 2 update arrives today! A new gameplay type, gold rush, is headlining this new release. A new control-point map, named "Badlands," has been released for Team Fortress 2, along with a slew of other new updates. A complete change log details what's new. In addition to the new map and game type, several other maps have been fixed, most importantly cp_dustbowl (which is still ridiculously hard to win as the BLU team).

Update: I was wrong about the game type. It looks like the new badlands map is simply a new control point map (which I'm still excited about trying).

Perl 5.10

Feb 11, 2008

I just found out about Perl 5.10, which has been out for some time now (released on December 18 ... how did I miss this?). The perldelta documentation goes into detail on what's new, but here's a brief overview of some of the features I find most appealing:

The 'feature' pragma

First and foremost is the feature pragma, which is used to turn on the new features added by 5.10. By default, the new features are disabled, and you explicitly have to request their support (a great idea, in my opinion). A simple use feature; statement will do the trick.

New 'Defined-Or' operator

A new // operator is now available, for handling the 'defined-or' case. For example:

$a // $b; # This is equivalent to the line below

defined $a : $a ? $b; # Same meaning as above

This new operator has the same precedence as the logical-or operator. In typical Perl fashion, the new operator is simply a shortcut that makes your scripts shorter and more difficult to read one month after you write it. ;)

Switch statements

At long last, Perl has a switch statement. The syntax here is quite different from other programming languages with which you might be familiar:

given ($state)
{
    when ("state_1") { $a = 1; }
    when (/^abcdef/) { $b = 2; }
    default { $c = 0; }
}

The various when tests allow for some powerful options, including: array slices, string compares, regular expression matches, and beyond.

Named captures in regular expressions

Suppose we want to read in a configuration file that contains lines with the following structure: option = value. Today, we could write a regular expression to capture these values like this: /(\w+) = (\w+)/. We would then access the captured values with $1 and $2.

In Perl 5.10, we could write the same expression like this: /(<?option>\w+) = (<?value>\w+)/. Now, the captured values are accessed through either the %+ or %- magical hashes, using each label as the key into each hash (see the perldelta documentation for the differences between the two hashes). This will make complex regular expressions much easier to decipher, and gets rid of the annoying parenthesis counting that we currently have to do.

Just 'say' it

The new say keyword is just like print, but it automatically adds a newline at the end of what it prints. How great is that? This simplifies printing code a little bit, especially for loops. Instead of print "$_\n" for @items; we can now use say for @items;. Clean and simple!

Stackable file tests

Doing multiple file tests is much easier now. Instead of if (-f $file and -w $file and -z $file) we can now write if (-f -w -z $file). Again, this makes things much cleaner.

Better error messages

Have you ever seen this error message? I know I have:

$str = "Hello $name! Today is $day and the time is $time.\n";

Use of uninitialized value in concatenation (.) or string at test.pl line 3.

In 5.10, this same error message will read:


$str = "Hello $name! Today is $day and the time is $time.\n";

Use of uninitialized value $time in
concatenation (.) or string at test.pl line 3.

Now I can know exactly where the error occurred! Finally!

And lots more

There are plenty of other new features that I haven't touched here: recursive regular expressions, a new smart matching operator, state ("static") variables, inside-out objects, and lots more. I'm really looking forward to trying out some of these new features.

Another game I finished recently is The Legend of Zelda: Phantom Hourglass for the Nintendo DS. This game took me quite a while to beat, mainly because there's so much to do (and I didn't do everything). I thought I'd write up a few thoughts I had.

The Good

Classic Zelda Gameplay
Phantom Hourglass is as much Zelda fun as I've had since the SNES classic A Link to the Past. Puzzles in the game are quite challenging, the action is spot on, and there's a laundry list of side quests and challenges. This is classic Zelda, through and through, and that's a very good thing.
Excellent Use of the DS Hardware
As I have mentioned before, Phantom Hourglass makes great use of the Nintendo DS hardware. The touch screen controls are incredible (I hope future games use it as good as this title did), and clever use of the microphone really added a new dimension to the gameplay.
Great Writing
The writing in this Zelda title is particularly strong. There are a lot of really great scenes, and the ending is one of the best I've experienced in a while. Over the course of the game, I really grew fond of the various characters, which is rare for me in a game like this.
Fun Side Quests
A large portion of the game is spent sailing various oceans on a ship. Several side quests go along with this game play, including treasure salvage and fishing. The treasure salvage mini-game is pretty fun, and there's plenty of fun to be had on the high seas.
Bottomless Wallet
This is the first Zelda title I know of where Link has no apparent limit to the number of Rupies he can pick up (if there was a limit, I didn't hit it). Finally!

The Bad

Annoying Repetition
One of the main 'puzzles' in the game involves traversing through the temple of the Ocean King. You end up having to go through this Temple 4 or 5 times, which gets old pretty quick. As you gain new items, you can go through the temple quicker, but it still gets a little tedious.
Insanely Difficult Puzzles
A few of the puzzles throughout the game are insanely difficult. "Maze Island" is impossible to do without a guide of some sort, which really frustrated me. Thankfully, there aren't many of these.

The Verdict

This title is a must own. If you don't own this, go out and buy it immediately. My final rating: A+

Slashdot is running a story on how Time-Warner is considering moving to a per-gigabyte service fee. According to them, 5 percent of their customers use over 50 percent of the network. So, because of these few "bad apples," they'll make everyone pay more. Steven Levy of the Washington Post has an interesting theory that Time-Warner is trying to hobble movie rentals via iTunes (trying to keep their pay-per-view stuff alive in the process).

I hope above anything else that this 'idea' of theirs never sees the light of day. Capping folks at 5-gigabytes (which is their current idea ... can you believe that?) is incredibly poor judgment. This kind of thing will single-handedly destroy the online viewing capabilities of Netflix, it will ruin online gaming, and it will make MSDN subscriptions irrelevant.

And that might just be Time-Warner's ultimate goal. Let's hope they fail in every way possible.