Cookie Notice

As far as I know, and as far as I remember, nothing in this page does anything with Cookies.


Contemplating Beautiful Code...

Honestly, I thought I had written this a year ago.

I received a review copy of the O'Reilly book Beautiful Code over a year ago, and I was hopeful from the time I heard about it. For any technical subject I knew, the go-to book was always the O'Reilly. I learned C++ from O'Reilly. I learned lex and yacc from O'Reilly. I learned Perl from a book with a Camel on the front. Later, when Linux and Open Source started to get a foothold in the mainstream computer world, O'Reilly published an excellent oral history with Open Sources. When I saw O'Reilly and Beautiful Code together, I thought it would be an excellent resource.

And then I started to read.

I just couldn't finish.

There are many words in the jargon file that can lean toward implying beauty. Elegant, for example, or clean. "Clever" is used but has no entry. Many more describing variations on ugly, but this is understandable. "Readable" isn't in the Jargon File but is a common complaint against Perl, my language of choice.

Absence of complication leads to elegance, but is elegance beauty? Is cleverness beauty? If code is readable, is makes it easier to understand, easy to change, but does that mean beauty? The Keats test, "Beauty is truth, truth beauty,—that is all Ye know on earth, and all ye need to know", seems insufficient. And nothing I read made a utilitarian or functional argument for the benefit of beauty in a code base.

I was disappointed in O'Reilly for this. They're still my go-to supplier for technical books. As I write this, I'm waiting with bated breath for Amazon to deliver The Productive Programmer. It should arrive today. Productivity, that's something measurable, something I understand the value of. I hope it's more ueseful than Beautiful Code.

Reconsidering a Point...

This is a callback on the post on "wireless monitors".

Consider a netbook with a current-generation SSD drive. 6-8 gigabytes. Sure, years ago that was positively massive, but today, that's next to nothing. But, something that small would be a great candidate for your remote desktop scheme of choice. One thing I've discovered about Remote Desktops in the Windows world, one clear benefit over X forwarding in Unix, is that you forward sound as well as graphics. (Mark your calendars, folks, because you won't get such a clear comment favoring Windows again any time soon.)

So, for $300, you get your self an 8" monitor that you can take with you. I've been a Palm guy long enough, even with that time being past, to be soured on the concept of a device being a metaphorical prehensile tail to the desktop system.

Laptop sales have leaped above desktops in sales recently, and I see that trend going on. I'm not seeing why you'd keep a desktop if you had a sufficient laptop.

But there must be something to this idea, or else I'd let go of it.


Annoyed by ...

I read web text by highlighting it. Not all the time, but often enough. The paragraph I'm focusing on, that's the one I've dragged my mouse over, and I might bring it down to a sentence if it's sufficiently insightful. I'm thinking about many things, and this is a way to help myself focus.

But, when I do that, the New York Times website seems to think I'm asking for it to define things for me. It can define a word, but asking for it to define a paragraph blows it's little mind.

I know there's a means to shut this off by telling your machine that or something is I don't read NYT stuff enough to make this worth my while. But maybe someday soon.

Discuss Wireless Monitors ...

IdeaStorm, a Dell website, is talking about the wireless monitors.

I've seen them advertised, but as a gizmo that plugs into your VGA cable slot and another to the outbound cable from your monitor. Get a wireless monitor, wireless keyboard and wireless mouse, and you could be many yards from your main PC. Which sucks if you need to plug in your thumbdrive, it being across the room and all. Which, I guess, is a good reason to have Bluetooth.

Consider, instead, having a Citrix connection or Remote Desktop to a desktop machine from a laptop. Except, it's all the desktop and none the laptop. There, it almost sounds appealing.

Until you think about it.

The further you get from the desktop, the worse the performance gets. A wireless desktop (keyboard and mouse) comes in about $100, and a netbook comes in around $300. Having a machine that looks like a netbook, costs like a netbook but isn't a netbook and can't be ported like a netbook? That dog don't hunt.


A pass at coding for Twitter and, kinda, Blogspot

So, you write something in your blog, and you want to tell somebody, right?

Me, too. And here, I've automated the process. This script,, reads your Atom feed, looks to see if the newest post is new, and then sends a tweet to your Twitter feed.

I use AnyDBM_File to save the most recent, even though I don't nearly tap the awesome power of it, because opening it as a hash is a lot easier than reading then writing a file.

XML::Atom was the tough one to install. CPAN never did finish it, so I used apt-get to install it instead. The laugh is that XML is anything like human-readable.

And Net::Twitter just could not be easier.

# ========= ========= ========= ========= ========= =========
# AUTHOR - Dave Jacoby
# Copyright (c) 2008. David Jacoby.
# This program is free software; you can redistribute it
# and/or modify it under the same terms as Perl itself.
# See
# ---------

use 5.010 ;
use strict ;
use warnings ;
use AnyDBM_File ;
use Carp ;
use Net::Twitter ;
use XML::Atom::Client ;
use XML::Atom::Entry ;
use XML::Atom::Feed ;
use subs qw( get_entry send_to_twitter ) ;

dbmopen my %dbm, '/path/to/.database.dbm', 0600 or croak $! ;
if ( !defined $dbm{ 'current' } ) { $dbm{ 'current' } = '' ; }
say 'C ' . $dbm{ 'current' } ;

my $url = 'your_blogspot_Atom_ feed' ;
# I think that it'll autodetect if you just put the URL
my $entry = get_entry $url ;
my $text = 'New post to my blog - ' . $entry ;

if ( $entry ne $dbm{ 'current' } ) {
send_to_twitter $text ;
$dbm{ 'current' } = $entry ;

exit ;

# ===================================================================
sub get_entry {
my $url = shift ;
my $tweet_link ;
my $client = XML::Atom::Client->new ;
my $feed = $client->getFeed( $url ) ;
my @entries = $feed->entries ;

for my $link ( $entries[ 0 ]->link ) {
if ( $link->type eq 'text/html' ) {
$tweet_link = $link->href ;

#we should be picking it up 2nd pass
return $tweet_link ;

# -------------------------------------------------------------------

# ===================================================================
sub send_to_twitter {
my $user = 'username' ;
my $pass = 'password' ;
my $status = shift ;
my $tweet = Net::Twitter->new( username => $user,
password => $pass, ) ;
if ( $tweet->update( $status ) ) { say 'OK' ; }
else { say 'FAIL' ; }
# -------------------------------------------------------------------

I'd like to get the URL and subject in, but that can't be guaranteed to be under 140 characters.

Coding Jabber, the first pass ...

My current obsessions are Jabber and Twitter, finding ways to use them that work with what I'm doing. I've made a program that works a bit like mail on a Unix command line. You might list a directory and mail it to yourself like this: ls | mail This will work about the same way, except I build in a default target, so you can ls | as well as ls | . I have it set up so I can also do Insert message here .

My next goal is to add presence, which I regard as the cool thing about Jabber.


# ========= ========= ========= ========= ========= =========
# AUTHOR - Dave Jacoby
# Copyright (c) 2008. David Jacoby.
# This program is free software; you can redistribute it
# and/or modify it under the same terms as Perl itself.
# See
# ---------
use 5.010 ;
use strict ;
use warnings ;
use Carp ;
use Net::XMPP ;

my $verbose = 0 ;

if ( $ENV{ PATH } eq '/usr/bin:/bin' ) {
$verbose = 0 ;
elsif ( defined $ENV{ EDITOR } ) {
$verbose = 1 ;
elsif ( !defined $ENV{ EDITOR } ) {
#could almost say 'else'
exit 0 ;

# connection vars
my $hostname = '' ;
my $port = 5222 ;
my $componentname = '' ;
my $connectiontype = 'tcpip' ;
my $tls = 1 ;

# user vars
my $username = 'xxx' ;
my $password = 'xxx' ;
my $resource = 'Test' ;

# message
my $addr = '' ;
my @field ;

my $arg = shift @ARGV ;
$arg =~ m{([A-Za-z0-9_.+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4})}mix ;
$addr = $1 ;

if ( $addr eq '' ) {
push @field, '' ;
unshift @ARGV, $arg ;
else {
push @field, $addr ;

my $args = join ' ', @ARGV ;
if ( length $args == 0 ) {
while ( ) {
$args .= $_ ;
if ( length $args == 0 ) { $args = 'blank' ; }
if ( length $args > 139 ) { $args = substr $args, 0, 139 ; }

my $Connection = new Net::XMPP::Client() ;

# Connect to
my $status = $Connection->Connect( hostname => $hostname,
port => $port,
componentname => $componentname,
connectiontype => $connectiontype,
tls => $tls ) ;
if ( !( defined( $status ) ) ) {
$verbose and say 'ERROR: XMPP connection failed.' ;
$verbose and say $! ;
exit( 0 ) ;

# Change hostname
my $sid = $Connection->{ SESSION }->{ id } ;
$Connection->{ STREAM }->{ SIDS }->{ $sid }->{ hostname } = $componentname ;

# Authenticate
my @result = $Connection->AuthSend( username => $username,
password => $password,
resource => $resource ) ;

if ( $result[ 0 ] ne "ok" ) {
print "ERROR: Authorization failed: $result[0] - $result[1]\n" ;
exit( 0 ) ;

# Send messages
for my $address ( @field ) {
$Connection->MessageSend( to => $address,
resource => $resource,
subject => "Notification",
type => "chat",
body => $args ) ;

$verbose and say 'TO: ' . $address ;
$verbose and say $args ;

$verbose and say 'end' ;
exit ;


Considering the CHIMP ...

My son wants a CHIMP for Christmas.

Not a chimpanzee. A CHIMP. Basically, a rear-view mirror for the geek set. CHIMP is a recursive acronym, meaning CHIMP Has Invincible Monkey Powers.

I don't have a CHIMP.

I have a baby mirror, and I have a webcam. Both serve the same purpose, which is giving me a visual indicator of motion behind me, so I don't have to be surprised and scared when someone comes up to me.

The pic of my desktop (and no, my walls are not nearly that yellow) comes from my camera phone, which appears in both the mirror and the webcam.



Pondering Amazon's Suggestions...

I have many machines whose speed I'm relatively happy with but whose storage limits are much too small. In 2008, 40GB is just too small. It might be obvious, but the machines I'm talking about have EIDE. They're just not new enough for SATA.

There's nothing wrong with SATA. In fact, I'd say that the skinny connectors of SATA are far better than the fragile pins and wide ribbons of EIDE. But, I have no SATA at home. Nothing's new enough.

So, I'm stuck on the horns of a dilemma. I want as massive a jump in drive space as I can, but I don't want to be stuck in the past. They stopped making EIDE a year ago. So, what do I do?

There's a 500GB EIDE drive on Amazon at near the price point I'm hoping for. 500GB isn't a terabyte, but it certainly isn't 40GB.

But what gets me is the suggestion box. If you're buying a Stephen King book and they suggest that you might want to get The Stand, too. That makes sense. When you're buying a Punch Brothers CD and they suggest that you might want to get Nickel Creek, too, that's logical. When you're looking at a 500GB EIDE hard drive and they suggest that you might want a 500GB SATA drive, too, that makes no sense.

While I was on Amazon, I thought I might look for a few more things. I work in a dank sub-basement and have no phone on my desk, so I thought getting a Skype phone might be useful. I saw The GE 2-in-1 phone, first at Wal-Mart and then on Amazon. I've seen them before. I'm thinking that a portable phone that talks Bluetooth and Wifi is nothing but win, especially if I can afford to Skype out eventually. But there's a big massive downside. Phone talks to PC, PC talks to Skype. And that means Phone talks to Microsoft-Operating-System-bearing PC, PC talks to Skype. I've used enough Unix and Linux and enough Windows to know that I want to use more Unix, so I want to use less and less to no Windows. Later versions are pure Skype phones, with no connection to a PC. Later versions are $100+. I still think it's a good idea.

GE is also starting to make home phones which call out and pick up on your cell phone, connecting via Bluetooth. On one hand, it makes a bit of sense. When I was an undergrad the second time, about 10 years ago, I was beginning to see and hear about people who were turning off local phone service and only using their cell phone. This makes a reasonable amount of sense to me. In my household, we have cellphones and Vonage and we're considering switching to a cheaper Asterisk solution. So, doing away with the local phone makes sense. But I don't know the benefit of having the phone you use at home not be the phone you use when you're away. The vision I have is of exploding the parts of the phone, not replicating the unified phone of the past. You can get Bluetooth headsets that allow you to talk while using your hands. You can get Bluetooth watches that flash the CallerID information when you get a call. Your phone is in your pocket. What's the point of having a separate home phone that isn't really a separate home phone?

Speaking of, I'm drawn to a Bluetooth dongle I've seen at Wal-Mart for $20. I have a Bluetooth earpiece and a phone that can talk to it, and maybe more and maybe not. So, I don't know what I'd get with that. But hopefully, it'll be cool.

In other news, my friend Patrick has beaten the final boss on OpenSolaris-vs-Windows-Server-2003. Joe User has penetrated the walls of Solaris via su, console, GTK and SSH. And I'm burning the game onto a CD-RW I had floating around. The drive in my #1 Linux box is a bit flakey, so I'm burning on my Windows box, a laptop with a broken screen. I've not been able to burn ISOs in Windows, but this evening I found cdburn, which comes from Microsoft's Windows Server 2003 Resource Kit. It's a command-line tool, which the Unix guy in me loves. And now, or soon, I'll be able to burn ISOs from the common Windows machine at work.

Tryin' to tell the story of my life ...

Only, for me, it's college.


Going Through The Inbox ...

Hopefully, this isn't a boring thing. But it does have to be done.

This being the process of going through the magazines on my desk, putting the information onto the blog, and, the process, into my head.

Dr. Dobb's Journal, January 2009.

  • Functional Programming: Has It's Ship Come In?

    Functional programming: It's hot, it's cool, it maybe maps to multi-core better than Procedural and Object-Oriented programming, but it isn't good with IO so it hasn't been big like some other languages. It's interesting. When I hear procedural, I think cop shows. When I hear functional, I think "it works". A procedural language follows a procedure. A functional language works via functions. This is the stereotype: function( function( function( function( function( function( function( function( function( function( function( function( ) ) ) ) ) ) ) ) ) ) ) ) If it fails to work, just throw a few more close-parens.
    The interesting thing about this article is that it suggests a few

  • Mono, Linux and .NET Development

    It's less that the thought of Microsoft stuff on Linux is repugnant to me than it seems like an odd sort of virtualization.

Just noticed something interesting. The Blogspot web interface traps Control-S and does a save of the current post text to the server, not the current page to the desktop. Pretty neat.


Organizing My Thoughts on Catalyst

I am about three hours from presenting on Catalyst for my Perl Mongers meeting.

For those who don't know, Catalyst is a Web Framework using the MVC (Model-View-Controller) format to make for easier web development.

Imagine the operators that you see sometimes in 1930s movies, or in old reruns of Laugh-In. The Model is the trunk line with people with information trying to connect in. The View is the person in Suite 14 receiving the calls.

The Controller, Catalyst and the code you write for it, is Lily Tomlin.

Up in Suite 14, running the View, is Template::Toolkit. I've never had reason for templating before, but I'm learning to like it. It's a powerful tool. The institutional view here in the subbasement is that you should limit the amount of logic you put in the View, doing all that mess in the Controller.

The Model is DBIx::Class, and the more I deal with it, the more I accept it as a powerful tool. I have been saying that Catalyst has made it hard for me to leverage the awesome power of SQL, but today I have been beating my head against the switchboard and whipping myself with patch cables, trying to do two simple things. If I get those two things done, I can use one View, one Template Toolkit file, with Catalyst

First, we have lastname and firstname, but we want name = firstname . ' ' . lastname . Unless there is no firstname, in which case name = lastname.

Next, each person does something, and there's a table showing each time that person did that thing. We want to count each thing and establish count.

I can do that. I can use DBIx to get all that information. What I cannot do is put the genie back in the bottle. Or, I cannot patch it back into the View.

Which means, LOL fashion, that I'm doin' it wrong.

So, I'm off to read up on DBIx::Class, and there's next to zero chance that I'll be able to get this work before Perl Mongers.


Taking control of my environment ...

As mentioned, I now have OpenSolaris available at my beck and call via VirtualBox.

Interesting story: Right about the time I finished that installation, I had problems with my screen setup. You see, I was bored, so I was playing with screen resolutions. My #1 monitor wants to be at 1680x1050, and due to my futzing, Gnome wouldn't let me get to anything closer than 1280x1024. Which looked like crap and kept the panels out of view.

By the way, I love multiple monitors.

Anyway, you can right-click on the desktop and set your screen resolution under Windows. You can right-click on the desktop and set your screen resolution via Gnome under OpenSolaris. It is a menu option for Ubuntu. You cannot get to it via right-click, and sometimes you really need to.

That is, without modification.

Make a ~/.gnome2/nautilus-scripts/ directory. Make a file called Screen Resolution. Make it executable. And make it say this:


Probably the easiest program I ever wrote! And with Intrepid, I didn't have to HUP Nautilus to make it see the scripts, which is always useful.


Getting it going ....

When i worked at the other place, we used Synergy. Not the bad and byzantine source-control Synergy, but the software KVM tool.

I have a laptop that's unusable as a laptop, so it is my Windows machine. The screen is busted, so I have it connected to a big screen, and the keyboard is busted, so it's not all that much fun to use. So, I tried the power of Synergy, like I had been using at work.

And I failed.

Talking to Patrick, I figured out the issue. Synergy wants to talk names, not raw IP addresses. I had no local DNS. What few machines needed to talk to each other, I have their 192.168 addresses memorized. But Synergy wanted to work with names.

The solution?


Or c:\Windows\system32\drivers\etc\hosts

(There's no legacy BSD code involved with XP. Nope.)

So, I made the wired NIC on the laptop static, named it, and set up Synergy again. And I'm writing on my XP machine via the keyboard on one of my Ubuntu machines' keyboard.

Honestly, I have that keyboard hooked to a KVM switch going between two Ubuntu machines, but that's another story.

Showing the most useful piece of Catalyst documentation yet ....

Not that it is particularly useful.

Useful Test

I'm mostly going to test how to put code samples here, but if you're going to test, might as well make it useful, right?

I run Ubuntu, and I have sshfs installed. sshfs is part of FUSE, Filesystems in Userspace. What SSH allows you to do is mount the file systems on other machines via SSH.

The issue I ran into was that I wanted certain continual mounts all the time. I created a ~/Mount directory and put the mountpoints in there, and had mounting and unmounting shell scripts. If I wanted everything, I got everything. If I just wanted to unmount and remount one, well, I had to grep for the commands I want.

I have two example machines to mount: Home and Work. mounts both. -q unmounts both. -m Home mounts just the Home filesystem. -u Home unmounts just the Home filesystem.

It could easily be set up to mount and unmount the NTFS filesystem of a dual-boot computer using ntfsmount, or interact with Windows systems via smbmount, or other things. Right now, it seems way too small to try to put together as a project, but if you find it useful, feel free to comment.


use strict ;
use warnings ;
use Getopt::Long ;
use 5.010 ;
use subs qw( mount unmount ) ;

# Definition
#                   --   mounts all in the config
# -Q                -- unmounts all in the config
# -m foo            --   mounts foo, if foo is in config
# -u foo            -- unmounts foo, if foo is in config
# -m foo -u bar     --   mounts and unmounts can be mixed

my @mount ;
my @unmount ;
my $unmount ;
my %local ;
my %remote ;

my $mountprog   = '/usr/bin/sshfs' ;
my $unmountprog = '/bin/fusermount' ;

GetOptions( 'mount=s'   => \@mount,
            'unmount=s' => \@unmount,
            'quit'      => \$unmount, ) ;

while (  ) {
    chomp ;
    my $line = $_ ;
    next if $line !~ m{\w}mx ;
    my $result = ( split m{\#}mx, $line )[ 0 ] ;
    $line = $result ;
    next if $line !~ m{\w}mx ;
    my ( $name, $remote, $local ) = split m{\s*\|\s*}mx, $line ;
    $local{ $name }  = $local ;
    $remote{ $name } = $remote ;

if ( $unmount ) {
    for my $mount ( sort keys %local ) {
        unmount $mount , $local{ $mount } ;

elsif ( ( $#mount == -1 ) && ( $#unmount == -1 ) ) {
    for my $mount ( sort keys %local ) {
        mount $mount , $remote{ $mount }, $local{ $mount } ;

else {

    # mounts first
    for my $mount ( @mount ) {
        mount $mount , $remote{ $mount }, $local{ $mount } ;

    # then unmounts
    for my $mount ( @unmount ) {
        unmount $mount , $local{ $mount } ;

exit 0 ;

sub mount {
    my $name   = shift ;
    my $remote = shift ;
    my $local  = shift ;
    return 0 if $name !~ /\w/mx ;
    return 0 if $remote !~ /\w/mx ;
    return 0 if $local !~ /\w/mx ;
    return 0 if !-d $local ;
    say 'Mounting ' . $name ;
    say qx( /usr/bin/sshfs $remote $local ) ;
    return 1 ;

sub unmount {
    my $name  = shift ;
    my $local = shift ;
    return 0 if $name !~ /\w/mx ;
    return 0 if $local !~ /\w/mx ;
    return 0 if !-d $local ;
    say 'Unmounting ' . $name ;
    say qx( /bin/fusermount -u $local ) ;
    return 1 ;

Work     | | /home/rant/Mount/work
Home     | | /home/rant/Mount/home

(I plan to beautify the means to dump code in the near future.)


Considering the Vast Array of Possibility...

At the end of work today, I had a fully-functional OpenSolaris machine running under VirtualBox.

I have tried, at various points in time, to keep a Solaris x86 machine around — "But, Mom! It followed me home! Honest!" — but in the end, I always wiped it. That is, if I ever got the installation finished. Solaris has not been an easy installation.

This wasn't real. This was virtual. A virtual ISO sat in a fake CD-ROM drive and filled a phony chunk of memory full of OpenSolaris. I clicked "GO", moved to another desktop and beat my head on Catalyst and MySQL for a little while. Then, I moved back to the desktop and clicked OK, and it was done. I had my first stab at Solaris package management trying to install the "Guest" packages.

First time I sat behind a Solaris box, I was using CDE. Ever use CDE? CDE is the reason people started looking in to window managers. So they could get away from it! OpenSolaris comes with Gnome, and it's nice. Nice like the Gnome that comes with Ubuntu. And they're both Live CDs.

If the OpenSolaris user experience is, within Δ, the Ubuntu user experience, why use OpenSolaris? You want to integrate into a huge Sun environment. You develop in Java or otherwise want to have your Sun-based development environment. You're used to Sun. Or you wish to prove your manhood by grappling with the OS that was the go-to Unix when Linus was in high school.

I almost have a use for the similar XP install on my desktop. I don't really have one for OpenSolaris yet. So, what do I use it for?


Reading the Documentation ....

My boss has a flatbed scanner he wants to work. An HP ScanJet 3670.

I tell you the model number so that you too can do what I have done, which is look up the XSane compatability list. You will find that the 3670 is explicitly listed as not working with XSane, which means ito be non-Linux-compliant.

So, my boss suggests I dual-boot the thing. And my other boss — Boss1 can hire and fire me, but Boss2 controls the hardware I deal with on a day-to-day basis — suggests I try VirtualBox, running XP in a virtual machine under Ubuntu. I'm happy to do this, as I would much rather have most of the user software running on Linux than Windows. That's the kind of guy I am.

This process is complicated by the Thanksgiving weekend, which means that all the people I need for getting XP install media (to run in the VirtualBox) are on vacation just when I need to do it. So, finally, I get my hands on install media, get everything running, and guess what!?!

VirtualBox OSE, the open source edition, has no USB support. None. None at all.

This makes me frown.

Want to know what made me smile?

The VirtualBox License.

You can use VirtualBox, the closed, feature-rich version, if you are
  1. Using it just for yourself
  2. Evaluating it for your company, or
  3. Part of an academic institution

Like, for example, a research lab of a large land-grand university!

So, a little apt-get here and there and I have the real VirtualBox running.

Now I just have to convince the ScanJet to talk nice. I could still be setting up a dual-boot yet.

ETA: Adding this to your /etc/fstab and restarting helped a lot, too.

none /proc/bus/usb usbfs devgid=[GUID of vboxusers],devmode=0666 0 0

Assuming you add your users into that group. Thank you, noorez!