Cookie Notice

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


TV on my PC? We live in the Future

Several weeks ago, I got a Diamond ATA TV Wonder 650 PCI TV tuner. This means I can watch and store shows on my computer. I'm curious about workflow possibilities with this: I want to convert the files to smaller formats and copy them to better places. It will be a period of learning, I am convinced.


Lies! All Lies!

Most of the lab wants to take the week between Christmas and New Years off. But there are researchers who are still dropping off samples today, the day before Festivus. I've got a lot of problems with you people!


The 12 Days: an analysis

Using this code:


use 5.010 ;
use strict ;
use warnings ;
use DateTime::TimeZone ;
use File::stat ;

my @count ;
my @days ;

$days[1] = 'Partridge in a Pear Tree' ;
$days[2] = 'Turtle Doves' ;
$days[3] = 'French Hens' ;
$days[4] = 'Calling Birds' ;
$days[5] = 'Golden Rings' ;
$days[6] = 'Geese A-laying' ;
$days[7] = 'Swans A-swimming' ;
$days[8] = 'Maids A-milking' ;
$days[9] = 'Ladies Dancing' ;
$days[10] = 'Lords A-leaping' ;
$days[11] = 'Pipers Piping' ;
$days[12] = 'Drummers Drumming' ;

for my $a ( 1 .. 12 ) {
for my $b ( 1 .. 12 ) {
next if $b > $a ;
$count[$b] ++ ;

for my $a ( 1 .. 12 ) {
say join ' ' , $count[$a] * $a , $days[$a] ;

I determined the precise number of each gift as presented in the song.

12 Partridge in a Pear Tree
22 Turtle Doves
30 French Hens
36 Calling Birds
40 Golden Rings
42 Geese A-laying
42 Swans A-swimming
40 Maids A-milking
36 Ladies Dancing
30 Lords A-leaping
22 Pipers Piping
12 Drummers Drumming

I suppose it preferable to have a smaller number of drummers than geese. Time to get into the geese and swan market, though.


A MySQL Bug? A Programmer Bug?

I have been trying to teach myself data analysis. I have been keeping some weather data in a MySQL database so I can take it out, munge it and graph it. The above example is done with the Perl module Chart::Clicker, which I am sure will take a large role in my current job. Especially if it works fast and graphs correctly.

On that topic, take a look at it. The red line represents the day's highs, the green line, the day's lows, and the purlple line the day's average temperature. Here's the code that determines what the numbers should be.

my $sql ;
$sql .= 'SELECT ' .
'cast( avg( temp_f ) as unsigned ) , ' .
'min(temp_f) , ' .
'max(temp_f) , ' .
'DATE(time) ' .
'from weather_data where zip = "47909" ' .
'and DATEDIFF( CURDATE() , DATE(time) ) < 7 ' .
'group by DATE(time)' ;

And here's the schema for this code.

CREATE TABLE weather_data (
id int(10) not null auto_increment primary key ,
time TIMESTAMP not null ,
zip varchar(5) ,
city varchar(255) ,
temp_c varchar(255) ,
temp_f varchar(255) ,
humidity varchar(255) ,
wind varchar(255) ,
conditions varchar(255)
) ;

I'll admit that it's pretty lazy. If the current conditions stretches beyond 20 characters, that's some complex weather. The main problem, I believe, is that temperature data is being saved as a string rather than a signed integer. Why it mostly shows up as error on that one day, I don't know. Here's all the temperature data for that day. (Thank you, Google Weather API.)
2009-12-10 00:00:0228-2
2009-12-10 00:10:0228-2
2009-12-10 00:30:0328-2
2009-12-10 00:40:0228-2
2009-12-10 00:50:0228-2
2009-12-10 01:00:0228-2
2009-12-10 01:10:0228-2
2009-12-10 01:30:0216-9
2009-12-10 01:40:0216-9
2009-12-10 02:00:0316-9
2009-12-10 02:10:0216-9
2009-12-10 02:20:0216-9
2009-12-10 02:40:0214-10
2009-12-10 02:50:0215-9
2009-12-10 03:00:0215-9
2009-12-10 03:10:0215-9
2009-12-10 03:20:0215-9
2009-12-10 03:30:0314-10
2009-12-10 03:40:0114-10
2009-12-10 03:50:0115-9
2009-12-10 04:00:0315-9
2009-12-10 04:10:0214-10
2009-12-10 04:20:0214-10
2009-12-10 04:30:0212-11
2009-12-10 04:40:0212-11
2009-12-10 05:00:0213-11
2009-12-10 05:10:0212-11
2009-12-10 05:20:0212-11
2009-12-10 05:30:0312-11
2009-12-10 05:40:0212-11
2009-12-10 05:50:0212-11
2009-12-10 06:00:0312-11
2009-12-10 06:10:0211-12
2009-12-10 06:20:0211-12
2009-12-10 06:30:0211-12
2009-12-10 06:40:0111-12
2009-12-10 07:00:0311-12
2009-12-10 07:10:0210-12
2009-12-10 07:20:0210-12
2009-12-10 07:30:0210-12
2009-12-10 07:40:0410-12
2009-12-10 07:50:0210-12
2009-12-10 08:00:099-13
2009-12-10 08:10:059-13
2009-12-10 08:20:069-13
2009-12-10 08:30:059-13
2009-12-10 08:40:069-13
2009-12-10 08:50:059-13
2009-12-10 09:00:068-13
2009-12-10 09:10:088-13
2009-12-10 09:20:088-13
2009-12-10 09:30:088-13
2009-12-10 09:40:138-13
2009-12-10 09:50:079-13
2009-12-10 10:00:0710-12
2009-12-10 10:10:0710-12
2009-12-10 10:30:0710-12
2009-12-10 10:40:1010-12
2009-12-10 10:50:0712-11
2009-12-10 11:00:0712-11
2009-12-10 11:10:0512-11
2009-12-10 11:20:0812-11
2009-12-10 11:40:0812-11
2009-12-10 12:00:0914-10
2009-12-10 12:30:0714-10
2009-12-10 12:50:0714-10
2009-12-10 13:00:0914-10
2009-12-10 13:10:0615-9
2009-12-10 13:20:0815-9
2009-12-10 13:30:0615-9
2009-12-10 13:50:0717-8
2009-12-10 14:00:0917-8
2009-12-10 14:10:0717-8
2009-12-10 14:20:0817-8
2009-12-10 14:40:0918-8
2009-12-10 14:50:0817-8
2009-12-10 15:20:0818-8
2009-12-10 15:30:1518-8
2009-12-10 15:40:0818-8
2009-12-10 15:50:1119-7
2009-12-10 16:00:1119-7
2009-12-10 16:10:0819-7
2009-12-10 16:20:0819-7
2009-12-10 16:30:0719-7
2009-12-10 16:40:1019-7
2009-12-10 16:50:0819-7
2009-12-10 17:00:0319-7
2009-12-10 17:10:0319-7
2009-12-10 17:30:0219-7
2009-12-10 17:40:0218-8
2009-12-10 17:50:0218-8
2009-12-10 18:00:0218-8
2009-12-10 18:10:0217-8
2009-12-10 18:20:0217-8
2009-12-10 18:30:0217-8
2009-12-10 18:40:0216-9
2009-12-10 18:50:0116-9
2009-12-10 19:00:0217-8
2009-12-10 19:10:0217-8
2009-12-10 19:20:0217-8
2009-12-10 19:40:0217-8
2009-12-10 19:50:0217-8
2009-12-10 20:00:0217-8
2009-12-10 20:20:0217-8
2009-12-10 20:30:0217-8
2009-12-10 20:40:0217-8
2009-12-10 21:00:0317-8
2009-12-10 21:10:0117-8
2009-12-10 21:20:0218-8
2009-12-10 21:30:0218-8
2009-12-10 21:40:0218-8
2009-12-10 22:00:0217-8
2009-12-10 22:10:0217-8
2009-12-10 22:20:0218-8
2009-12-10 22:30:0218-8
2009-12-10 22:40:0218-8
2009-12-10 22:50:0118-8
2009-12-10 23:00:0218-8
2009-12-10 23:10:0118-8
2009-12-10 23:20:0218-8
2009-12-10 23:30:0218-8
2009-12-10 23:40:0218-8
2009-12-10 23:50:0218-8

I could show you the temp_c graph, but that's just beyond the pale wrong, which makes sense as the temperature has been bouncing between positive and negative the whole time.

Ultimately, I got used to Perl's ability to effortlessly bounce between strings and numbers, and here I'm bitten. I can only use that data in a meaningful way if I pull it all and manipulate it in Perl, which cuts off some labor-saving tools. Let that be a lesson to you, and to me.


Terry Childs Trial Begins


As an admin, I hold that Childs is in jail for proper system administration. I hold that Childs is in jail for protecting the networks of the city of San Francisco, ultimately protecting the people of San Francisco, from his bosses.

San Francisco remains a city that jails people for doing system administration right.


Instinctive and Alarming

As I have said, I now use a Samsung Instinct s30.

And as I have said, I haven't been happy with the alarm. I love how many alarm it has, but it never seemed to go off.

I understand the problem now.

I didn't dime the volume. Do that and it is OK.


A Perfect Stocking Stuffer

Bluetooth USB dongle. Push it into your USB port and you can talk to your fancy schancy smart phone. What can you then do? Don't know yet. I don't have one yet. I guess soon after I'll start wanting a Bluetooth headset, a Bluetooth external DVD burner, a Bluetooth toothbrush. But one step at a time.


New Gear Day

There's one thing I find about being a geek, which is that when people who aren't geeks give up on trying to make a thing work, it gets passed on to me. Sometimes I can pass it on — a while ago, a rack-mount UPS got passed on to me, and today that UPS, that danged-heavy lead-filled monster, protects some servers that serve, among other things, the Purdue Perl Mongers site. Yayness.

The newest thing to land on my lap is, well, swank. An HP Pavilion Slimline. 320 GB SATA. 3GB memory. Dual-core processor. It's running Vista, which yeah, could be a blessing, could be a curse. We'll see. I have the technology to upgrade it to XP at will, and of course I can jump to Ubuntu. It's a tight little case, so not much room to upgrade. Seeing that it's far faster and better than anything sitting around the house, that should be no problem.

The problem it had in Mom's hands was that it couldn't keep connected to AOL. That will NOT become a problem with me.

I think I want to stick with Vista, though. At least at the moment. I am a big fan and user of Open Source software, but my user experience as a Unix guy has not really been strongly changed since I first started working with Unix in the mid-1990s. Unix, a shell (then tcsh, now bash), X, terms, and browsers. Vista is wildly different, and I think coming to terms with the differences, with what Vista has to offer. Similarly, I'd keep MacOSX around if it landed on my lap. This, more or less, is why I bought BeOS back in the day, to get another view on things.

So, we'll see. Thanks Ma!

Sprint Rant as Modem, pt 1 of ... 1

My home is a reasonably-networked environment. My work is a well-networked environment. I have a USB dingus that lets me link my Compaq Mini 110 to the Sprint phone network, but between my two computing environments, I don't need it very often.

K, on the other hand, has much more of a need for it. But it has not worked for her and her EeePC. Never has. It's gone back to the shop recently to get some work, but it's still flaky. I have just now downloaded the new Sprint SmartView software ...

I don't even get to get into it. I downloaded the newest version of SmartView, it grabbed newer drivers for the USB dingus, and now K can use the USB dingus to connect at Bill-Kurtis-like speeds. I was going to write down all my notes toward using her Samsung Rant as a modem, but the dingus works.

Don't you hate it when you're just about to get a nice hate-filled rant on and the thing just works?

Annotated jQuery, or pass me the crack pipe

Here's some code. This is what is on my mind today.

$( '<div/>' ) // We create a DIV tag
.attr( 'id' , 'e_solid' ) // give it a unique identifier
.text( 'solid' ) // put text into it
.appendTo('#head') // give it a unique identifier
.click( function() { // and set what happens when you click it
var ajax = a_dir + '2g_slide_formats.cgi' + '?e=solid' ; // which is, set a URL
$( '#e_454' ).css( 'color' , '#abc' ) ; // do some CSS stuff
$( '#e_solid' ).css( 'color' , '#000' ) ; // that won't work by
// setting it in the CSS file
$( '#run' ).empty() ; // clear some other
$( '#slide' ).empty() ; // subordinate tags
$( '<div/>') // We create a new DIV tag
.text('Slide Type') // fill it
.appendTo('#run') // put it into another tag
$( '<select/>') // we create a select box
.attr('id','holder') // give it an id
.appendTo('#run') // put it in the same tag
.wrap(document.createElement("div")) // put a DIV tag around it
.change( function() { // and an action for when
// the select changes
var value = $(this).val() ;
$( '#slide' ).empty() ; // empty '#slide' again
for ( var i = 1 ; i <= value ; i++ ) { // and figure the number of
// regions from the select value
var div_name = 'region_' + i ; // and make a name
$( '<div/>' )
.attr( 'id' , div_name ) // which we use to name a new DIV
.text( 'Region ' + i ) // which we fill
.addClass( 'region' ) // class
.appendTo( '#slide' ) // and append to the emptied #slide
$( '<span/>') // then add a SPAN
.appendTo( '#' + div_name ) // which we append to that new DIV
.text( 'Add barcode' )
.click( function() { // and when you click it ...
var accession = prompt( // you're prompted for one field
'Set Accession Number'
) ;
var barcode = prompt( // and then another
'Set Barcode, or Make Blank' , 'MID'
) ;
var strID = 'div_' + div_count ++ ;
alert( div_name ) ; // this is a bit of debugging.
$( '<div/>' ) // yet another DIV
.attr( 'id' , strID )
.appendTo( '#' + div_name + ' .body' )
; // which should go to the .body
// but doesn't, which is why I'm writing
$( '<span/>' )
.appendTo( '#' + strID)
.text( accession )
.addClass( 'accession' ) // and we add SPANs to that DIV
$( '<span/>' )
.appendTo( '#' + strID)
.text( barcode )
.addClass( 'barcode' ) // which are the data we are
; // prompted for
$( '<span/>' )
.appendTo( '#' + strID)
.text( 'delete' )
.addClass( 'delete')
.click(function(){ // and another SPAN
$( '#' + strID ).remove() ;
}) ; // that you click to remove
}) ; // this whole DIV and all in it
}) ; // It looks like we're done but that's just the end
// of the definition of the SELECT
// which we fill with AJAX and JSON
$.getJSON( ajax , function(data){ // we get a data chunk from JSON
var objD = eval( data ) ; // convert it to an object
for ( var i = 0 ; i < 100 ; i++ ) { // The shotgun approach saves me
if ( objD[i] != undefined ) { // from having to be clever
$( '<option/>') // and we add all the OPTIONS
.attr('value', objD[i].max_regions )
.text( objD[i].format ) // to the previously mentioned SELECT
.appendTo('#holder') // Remember the SELECT?
}) ;
}) // And here we end it. That was all one "line"
; // and it isn't quite correct.

My brain hurts.


Memento Mori

I have a cast-away desktop machine I'm trying to patch into a vaguely useful machine for my son. I have a 40GB drive into it, which is a bit tiny — it's XP, so 10GB will be taken by the OS and programs before he even starts trying to use it — so I'm have been trying to slip in a second 40GB drive that came from a machine whose power supply died on him. But the number two drive is not working.

I'm not sure why. I'm mostly sure that it's a jumper setting, but to check it, I will put back the Zip drive I took out to makeo room.

I remember when I put stuff on ZIP drives, when they were a good alternative to CDROMs, which when burned were unchangable, and floppy discs, which were and are just too small. I remember how proud I was, how cool I thought I was when I installed a Zip drive onto my beater Celeron about a decade ago.

I was filling it up so there would be something on it when I tried to load it on that machine. I remember thinking that Zip drives had just massive amounts of space. First thing I tried to put on there would not fit. It was too big.

That's the way, isn't it? Time was, I thought a 1200-baud modem was fast, and now I want broadband. I was once satisfied with memory measured in Ks while now you want multiple Gs. And so it goes.

And if you'll excuse me, I have a computer to fix.


Hardware Fun

A friend gave me a cast-off desktop, a white Gateway. He had it set up to be his MythTV box, doing network boot. I tried to get it going and it kept saying it couldn't find a bootable drive and looking for something in the A:. Finally figured out what BIOS mod was necessary — the drive was set as the secondary drive on the IDE bus — and now it's booting and running and installing.

Now I'm putitng on XP SP3. That should take another hour.....


Gizmo - The Rest of the Story

I reinstalled XP on my netbook. I just thought about Gizmo. I've dealt with this before, but this time, post-reinstall, it works.

Just to clarify what I mean by "it works". I have called my laptop with my cellphone. I have called my cellphone with my laptop. I was able to call. I was able to answer. It works.

Google did buy Gizmo, so, like GrandCentral before it, it will soon be integrated directly into the Google stack. Expect it to be integrated first with Google Voice and then with the Android. Which ultimately gets to an interesting point.

My friend Patrick says that when VoIP becaomes universal, VoIP companies will be superfluous. Or words to that effect; I could look it up in my GTalk logs, but nah. When is easy and commonplace for people to call point-to-point via whatever networked device they have, with nothing but TCP/IP between them, what's the point of the AT&Ts and Verizons and Vonages of the world? And with Google making the OS for that device, plus the mechanism (Gizmo) and voice mailbox for this to work, it seems like they're pushing for that future.

Anyway, it's working.


Love The Phone You're With

I used to be on Verizon, and when I was there, I had a Blackberry Pearl. I have to say, it's a swank phone. Never had an iPhone, so I don't know the full experience of the ultimate app-phone, so to me, the coolest phone I ever held is that Blackberry.

But that's not my phone anymore.

Right now, I carry a Samsung Instinct. It is not the phone I want. But it is the phone I have.

I am not a bleeding-edge wired individual, but I have been electronically connected for over 20 years. I'm wired and wireless and all that. And today, Google is the center of all connectivity. Between the phone and the provider, it was quick and painless to set up Google Voice as my voice mail, which is nice. Someone calls you and it translates it and sends it to you. That's sweet. Plus, web interface, which you don't have to deal with the confusing "If you want X, dial 4" stuff.

Google Mail was also an easy config. I do most of my GMail manipulation from Thunderbird via IMAP and between that and sorting, I've gone hog-wild for labels, but the mail interface is inbox-only. This just means I have to be more clear in sorting and filtering to make sure only what I want enters the inbox, but that's OK.

But that's it. I want to sync the on-board calendar with my Google Calendar, but it seems there's no connection capability. I learned the joy of having an online calendar when I worked for the clinic, but the calendar I had was the clinic's Exchange calendar, so I lost all my stuff when I left. The onboard calendar is pretty neat looking, but you can't have it synchronize with my main contacts list in Gmail. Yeah, there's a synch through Sprint, and that's fine. It means I can get my contacts back should I lose my phone, but that still means I manage them through on-screen one-handed typing rather than the full keyboard on my desktop.

I use XMPP, mostly through Google Talk, and the choices I have are AIM, Yahoo or MSN, and I went to GTalk to avoid those three. And there's no connection between my connections in GMail and my phone connections.

Plus, it uses a different power and connect cable than everything else I own, which I think use Micro-AB USB. The industry should unify on one.

But it is pretty, it has Bluetooth, it has a camera, it takes a microSD card, and it works just fine as a phone. It even works in the house, while K's phone kinda doesn't. There are elements I don't like about it, sure, but I do like it. I am decided in being happy with it.


Testing from the new phone

I have a new phone, a Samsung s30. It is a pretty thing but has a problem. Only AIM and Yahoo Messenger and I'm a Google Talk guy. Anyone know of a GTalk client for this phone?


Making Graphs with Perl and Chart::Clicker

The Graph

The Code

use 5.010 ;
use strict ;
use warnings ;
use Chart::Clicker;
use Chart::Clicker::Data::Series;
use Chart::Clicker::Data::DataSet;

my $pi = 3.14159265358979;

sub deg_to_rad { ($_[0]/180) * $pi }
sub rad_to_deg { ($_[0]/$pi) * 180 }

my @core = ( 0 .. 1_000 ) ;
my @sine ;
my @cosine ;
for my $a ( @core ) {
push @sine , sin(deg_to_rad($a)) ;
push @cosine , cos(deg_to_rad($a)) ;

my $cc = Chart::Clicker->new;
my $series1 = Chart::Clicker::Data::Series->new(
keys => \@core ,
values => \@sine
my $series2 = Chart::Clicker::Data::Series->new(
keys => \@core ,
values => \@cosine
my $dataset = Chart::Clicker::Data::DataSet->new(
series => [ $series1 , $series2 ],
$cc->add_to_datasets($dataset) ;
exit ;

There's lots of ways to do graphs. The way we do some graphs here is to do a system call to R. R is powerful, sure, but there's no good way to set up a batch of complex graphs in Perl and send them to R for graphing. There are ways, sure, but not good ways. So, I expect to do a lot more with Chart::Clicker in the future.


Letting It Go, or Why Ask Why?

I was at the library Saturday. While I sat in periodicals, reading Guitar World, there was a bit of a dust-up at the reference desk. I don't know what the person was asking about, but evidently it was, in his mind, easily-spelled, yet the librarian felt lead to ask.

This caused the guy to switch his interest. He wanted to know why she could not spell.

Now, if you were a librarian, there trying to help people, and people instead attack you, you would naturally be disinclined to be helpful. In this case, after several repeats of the phrase "This conversation is over", the head librarian was called over and the patron was escorted out the door.

There's a point here. Beyond the obvious "Don't Be An Obsessive-Compulsive Psycho." Clearly, that is important. The point I have is Why is Not Important. Of all the Ws, it is the least important in most parts of your life. Who: Someone, from a waitress to Mordoc, Preventer of Information Services. What: A good or service. Something they have and you want. When: If a deal is being made, urgency has been established. So, now, if not sooner. How: Sometimes this is crucial. As a parent, I know the results when "carefully, half that much, with both hands" is ignored. Someone has to sweep up the broken stuff. But Why? "Why can't you spell?" Is there a possible answer that will be satisfactory? "Ah, so that's why you can't spell! That explains it perfectly!"

I have found that it makes no sense to ask questions when I'm trying to get something done. Give orders? Make requests? Sure. But questions? I don't want to know the answers. I just want what I'm trying to get.


Windows Essentials?

OK, I munged it up. I couldn't create new accounts or add new MSI packages to the netbook. It had to go. It had to go. The problem I had was that my install media was on CDROM, but the netbook, being a netbook, has no optical drive from which to read a CDROM. But college campuses collect computer geeks and computer gear, so a quick Hey Rube got me a loaner USB optical drive. (What's crazy is that this drive is almost exactly the size of the netbook. I'll put up a picture tomorrow.)

So, I have the initial install. That was fast enough. There's the drivers to make the thing usable. I shoved a chunk of 'em onto my thumb drive, but I am sure I missed more than a few, including the work printer. After that, go to windowsupdate and get the thing up to the newest. And honestly, I'm still downloading and installing Service Pack 3 here. But that's just minimal function. We're not talking apps yet.

First place I went to was Ninite. There's an awful lot installers you can get at once. I picked up a bunch of browsers — I rock Firefox because Delicious has my bookmarks, but I have Chrome and Safari running, too — plus Hulu and VLC, Microsoft Security Essentials for virus protection and such, .Net and Dropbox and CCleaner and Notepad++ and PuTTY. Not a bad bunch of stuff, but not complete.

Dave Winer calls Dropbox the coolest software of the decade. I'm not quite there yet, but I'm close. It is pretty neat.

I live in a very networked world, and I have 15GB of SSD total on this thing, so I'd rather run Google Apps for what few Office Suite things I need and keep the space. I mean, if I'm somewhere not home and not work, it's very unlikely that I need an office suite. So, I went to get the Google Pack.

All things told, I probably shouldn't have put on Google Earth. Probably too big with little enough use. We'll see.

There's also a whole bunch of tweaks for XP that only come from the source. Power Toys. I first went for TweakUI, but the ClearType Tweaker and Alt-Tab replacement, are really near-essential add-ons. And Virtual Desktop Manager is SO nice.

But that doesn't get into the core issues. I have IE6. It is inexcuable to not have IE8. I need PowerShell. It isn't a Gnome terminal with a bash shell, but it's better than Command Prompt.

He's a few required SourceForge bits. Synergy allows you to share one keyboard and mouse across many computers, which is great when I'm at work. I can type on a netbook keyboard but I probably couldn't work on one, program on one. And there's XMing, an X server for Windows, which connects to the crucial PuTTY and allows you to have your big heavy windowing applications run on the big server and show up on the netbook as just the pictures.

One thing I'm pondering but not decided on is Growl for Windows. It's like my beloved notify-osd with a networking protocol bolted onto it, it seems.

Which leads me to these few questions: I need a Perl, but do I need Strawberry or Activestate? And is Notebook++ good enough for my programming on Windows needs, or should I get Komodo Edit? I've gone Komodo for 80% of my coding work.

And the big one. What did I forget? What Windows program have I omitted that's essential and just plain cool?


jBiff - Announcing New Mail via XMPP/Jabber

The Productivity People say turn off alerts for new mail, because it will suck your brain and suck your time. That's fine well and good. Except when you're coding and your boss shows up over your shoulder and says "Did you get my email?"

I hate having to respond "What email?" So, there's good reasons to have highly-specific alerts. And, to my knowledge, you can't really do that with Thunderbird and Epiphany. So, I began to wonder why I should even use those. Why not use Perl? It has Net::XMPP and more than one IMAP module.

So, I wrote jBiff. First there was biff, the command line tool. Then there was xbiff. Now, we have jBiff, telling your jabber client "You have mail."

I will put it on Github, soon after I figure out how.


# -imap -x -s foo -s bar -s blee

use Carp ;
use Data::Dumper ;
use Getopt::Long ;
use IO::Socket::SSL ;
use IO::Interactive qw{interactive} ;
use Mail::IMAPClient ;
use Modern::Perl ;
use Net::XMPP ;
use subs qw{ imap_part xmpp_part } ;

$Data::Dumper::Indent = 1 ;
my @sender ;
my $debug ;
my $xmpp_identity ;
my $imap_identity ;
GetOptions( 'sender=s' => \@sender,
'debug=i' => \$debug,
'xmpp=s' => \$xmpp_identity,
'imap=s' => \$imap_identity, ) or exit( 1 ) ;

exit if !defined $imap_identity ;
exit if !defined $xmpp_identity ;
exit if length $imap_identity < 1 ;
exit if length $xmpp_identity < 1 ;

imap_part @sender ;

# ====================================================================
# Pull credentials from a configuration file
# ====================================================================
sub get_credentials {
my ( $protocol, $identity ) = @_ ;
my %config_files ;
my %config_vals ;
my %config ;

$config_files{ imap } = '.imap_identities' ;
$config_files{ smtp } = '.smtp_identities' ;
$config_files{ xmpp } = '.xmpp_identities' ;

$config_vals{ imap } = [ qw{
key server port username password directory
} ] ;
$config_vals{ xmpp } = [ qw{
key host component sender password recipient resource
} ] ;
my $stat = ( stat "$ENV{HOME}/$config_files{$protocol}" )[ 2 ] ;
my $hex_stat = sprintf '%04o', $stat ;

if ( $hex_stat != 100600 ) {
say 'You should ensure that this file is not executable,' ;
say ' and not world or group-readable or -writable.' ;
exit ;

if ( -f "$ENV{HOME}/$config_files{$protocol}"
&& -r "$ENV{HOME}/$config_files{$protocol}" ) {
if ( open my $fh, '<', "$ENV{HOME}/$config_files{$protocol}" ) {
while ( <$fh> ) {
chomp $_ ;
$_ = ( split m{\#}mx, $_ )[ 0 ] ;
my @creds = split m{\s*,\s*}mx, $_ ;
next if scalar @creds < 6 ;
for my $i ( 1 .. $#creds ) {
my $key = $creds[ 0 ] ;
my $val = $creds[ $i ] ;
my $key2 = $config_vals{ $protocol }[ $i ] ;
$config{ $key }{ $key2 } = $val ;
close $fh ;
my $href = $config{ $identity } ;
return %$href ;
else {
say "No Configuration" ;
exit ;
exit ;

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

# ====================================================================
# connect to and search your mail server via IMAP
# ====================================================================
sub imap_part {
my @sender = @_ ;
my $sender = join '|', @sender ;
my %creds = get_credentials( 'imap', $imap_identity ) ;

my $socket = IO::Socket::SSL->new( PeerAddr => $creds{ server },
PeerPort => $creds{ port },
) or die "socket(): $@" ;

my $client = Mail::IMAPClient->new( Socket => $socket,
User => $creds{ username },
Password => $creds{ password },
) or die "new(): $@" ;

if ( $client->IsAuthenticated() ) {
$client->select( $creds{ directory } )
or die "Select '$creds{directory}' error: ",
$client->LastError, "\n" ;

for my $msg ( reverse $client->unseen ) {
my $from = $client->get_header( $msg, 'From' ) ;
my $to = $client->get_header( $msg, 'To' ) ;
my $subject = $client->subject( $msg )
or die "Could not subject $@\n" ;
if ( $from =~ m{$sender}i ) {
my $title = 'New mail from ' . $from ;
my $body = $subject ;
$body = join q{"}, '', $body, '' ;
xmpp_part "$title - $body" ;
$client->logout() ;
else {
say 'FAIL ' . $! ;

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

# ====================================================================
# send message via XMPP/Jabber
# ====================================================================
sub xmpp_part {
my $args = shift ;
my %creds = get_credentials( 'xmpp', $xmpp_identity ) ;

# connection
my $hostname = $creds{ host } ;
my $port = 5222 ;
my $componentname = $creds{ component } ;
my $connectiontype = 'tcpip' ;
my $tls = 1 ;

my $username = $creds{ sender } ;
my $password = $creds{ password } ;
my $resource = $creds{ resource } ;

my @field ;
push @field, $creds{ recipient } ;

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 ) ) ) {
print "ERROR: XMPP connection failed.\n" ;
print " ($!)\n" ;
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
foreach ( @field ) {
$Connection->MessageSend( to => "$_\@$componentname",
resource => $resource,
subject => "Notification",
type => "chat",
body => $args ) ;

$Connection->Disconnect() ;

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


Pieces-Parts To Program, Toward A Better Programming Life.

Just to be clear: I do not have advanced digital cable. We get the basic analog cable that comes with our internet. We have asked to not get it, because we don't want to be surprised into having to pay for it. This means we don't have the TiVo-like interface to remember when the show we want.

What we do have is the TVGuide Channel. Which is the Michael Jackson and Ugly Betty channel, which sucks.

And, which never remembers the settings I want to have it set. It's a reasonable. But there's the big big big table of all that's on. I don't care about that. I have a much smaller list of shows I want to watch.

And want to watch is a key. We're not talking is fine to watch, which I can search for the best thing right now. I'm talking about the things I want to be sure for the whens of my favorite shows.

This is what I want, what I think I can do.
  • get_TV_data - an API to access what's on what channel
  • set_google_calendar_event - an API to create an event on a Google Calendar calendar. I want this anyway, and I'm pretty sure that it's on CPAN.
  • google_calendar_alert - When you set an event in Google Calendar, it will either pop up (useless if you're not in Google Calendar), send an email, or send an SMS, which is essentially an email. What I want is for it to talk to me via GoogleTalk, which is Jabber, or XMPP. I have the XMPP part, I more than have that, so it's just the reading of the calendars.

Everything on that is pie in the sky, but it should be doable.


Another Little Pessimizations

chromatic has a post on the Modern Perl site called Removing the Little Pessimizations where he mentions and expands on bit from Perl Hacks. He suggested adding this line to your .alias:
 alias realias='$EDITOR ~/.aliases; source ~/.aliases' 

I just came up with another one. This one should go into your crontab:
 0 * * * * /usr/bin/crontab -l > ~/.latest_crontab  

Every hour, on the hour, it copies your crontab into a local directory.

I just reinstalled Ubuntu, hoping that this fixed the problem that occurred after the Jackalope->Koala upgrade. It didn't, but I lost some stuff, including my crontab. I have a separate partition for /home, so I didn't lose everything in the reinstall, but crontabs are not stored in your local dir and thus are wiped.

And, thank you Damian Conway and chromatic for the realias thing!

That's It!

I have my notify-osd back!

I have a Radeon 7000 dual-head card, and evidently there's a known issue with the driver that comes with Ubuntu Koala. Saying Driver "vesa" like the thread said didn't work, but telling my X config to shut off hardware accelleration did.

Section "Device"
Identifier "Card0"
Driver "radeon"
VendorName "ATI Technologies Inc"
BoardName "Radeon RV100 QY [Radeon 7000/VE]"
BusID "PCI:1:0:0"
Option "NoAccel" "TRUE" # []

Will post a pic with all the goodness running later. Thanks, Shub-Internet!

Other Broken Things in Ubuntu Koala

This is Gnome System Monitor. In an ugly pink punk tartan.

Thing is, it's usable, except it's not. I mean, I can right-click and I get a drop-down in some other indecipherable pattern. I can double-click where the angry pink tartan should have a menu and have it roll up like any other window. I just can't see it!

Any thoughts as to how to fix this?


notify-osd is broken under Ubuntu Koala

At least for me. Because that image, which shows a pink punk tartan, should be telling me that it's 55° and sunny in my home town today. I wrote a script that gathered the weather, put on a nice icon and displayed it. And it worked under Jaunty. But when I upgraded to Karmic, no dice. And now, after I spent the morning reinstalling , still no dice.

Any thoughts? Any help?


Configuration: The Devil is in the Details

I work in a lab. The simple fact is that, in the 21st Century, all science is computer science, and that's especially true here. We have several computers whose entire purpose is to control scientific instruments and handle the data that comes from them. But we don't want the data to be on the instrument machine. We want it to be on the server.

This is where FTP, and especially the Perl module Net::FTP, come in. We try to keep it locked down, configured at the firewall so that only the server can FTP into the instrument and even then can only move instrument->server, not the other way around.

One specific machine was set up with Windows 2000 and the FileZilla FTP server. The software, we were told, wanted 2K, and so we ran with that. FileZilla was about the first Google result I hit when I searched on "windows ftp server", and I cannot say there was ever a point where I regretted using FileZilla for all my FTP needs.

Then there was a necessary upgrade that needed Windows XP. The machine had 2 HDs in it, so I installed XP on disc 2 and made it dual boot. And, since it was XP Pro, I had IIS already. I may have had it on the 2K, I never thought to check. Anyway, the machine now spends most of the time under XP. I have had to change the upload-and-munge script to handle the new, and I'm not sure how much is IIS-vs-FileZilla and how much is Instrument-Software 1.3 vs Instrument-Software 2.0.

Where the story threatens to become interesting is this: The person who runs on that instrument, she makes a CSV config. Normally, she copys it, changes it, and seemingly, as long as the Excel file was open, it wouldn't upload. This was the 2K and FZ behavior.

Windows XP and IIS, it seems, FTP anyway, no matter if the Excel file is still open. And I had to clean up after it because of it. Not a problem, to be sure, but something to be aware of.


My first Perl one-liner

jacoby@oz:~$ ls -l *iso | perl -E 'while (<STDIN>) { $x=(split m{\s+}mx , $_)[4] ; say int $x * 100 / 723488768 , "% done" } '

I'm downloading Ubuntu 9.10 via FTP. I know the final size. Via ls I know the current file size. if a/b = y/100, where a = the current size, b = the final size and y = the percentage done, this gets the data and solves for y and converts to an integer. (Do I really need it to seven points? No.).

Thank you -E for making command-line Perl so much easier

Running an OddMuse wiki with CKeditor

I admin a few wikis, all using the OddMuse engine. I like Wiki markup, but it is difficult to make it do certain things. One thing we like doing at work is import Excel-style tables, so to do that, we use the FCKeditor.

I have always liked the function. I have not always liked the name. It seems like I'm cussing, which is something I have spent some time trying to stop doing. If I resort to vulgarity, I want it to be because the circumstances have overwhelmed me, not because they reside in the forefront of my vocabulary, and FCK reminds me of a shirt. Never mind the fact that the programmer named it after himself, Frederico Caldeira Knabben.

I must not have been the only person feeling like that, because the new name is CKeditor. But while there are docs for making my wiki engine of choice work with FCKeditor, not so much for the shiny new CKeditor. And it is shiny....

The problem, at the moment, is that I can get it to write wiki markup but I can't get it to write and save HTML, which really is helpful if you want to display tables, which I do.

Will post code once I figure it out


Reading IMAP directories with Perl

I use and like Thunderbird. Not the greatest thing since sliced bread, surely, but better for managing most of my mailboxes than pine and the school's web interface, which might soon be replaced with Gmail. Plus, IMAP!

The thing that sucks is alerting. If a mailing list gets updated, don't tell me. I shunt that stuff off into a subdirectory for a reason. In fact, there are three classes of people whose emails I want alerts about:
  • Family — mostly my wife and parents, but also my children, cousins, etc.
  • Bosses and Co-Workers — If you're involved in me getting paid, of course I need to know when you contact me
  • Friends — this is a low third, which is understandable, I hope.
Everyone else, all the spammers and mailing lists, I'll read your mail when I get around to it.

So, I looked into Perl's Mail::IMAPClient.

use Modern::Perl ;
use IO::Socket::SSL ;
use Mail::IMAPClient ;
use Getopt::Long ;
use Carp ;
use Data::Dumper ;

$Data::Dumper::Indent = 1 ;

my $server = '' ;
my $username = 'me' ;
my $password = 'nope' ;
my @sender ;

'sender=s' => \@sender ,
) ;

my $sender = join '|' , @sender ;

my $socket = IO::Socket::SSL->new(
PeerAddr => $server ,
PeerPort => 993,
or die "socket(): $@";

my $client = Mail::IMAPClient->new(
Socket => $socket,
User => $username ,
Password => $password ,
Ignoresizeerrors => 1 ,
or die "new(): $@";

if ( $client->IsAuthenticated() ) {
$client->select( 'INBOX' )
or die "Select 'INBOX' error: ", $client->LastError, "\n";
#for my $msg ( reverse $client->messages ) {
for my $msg ( reverse $client->unseen ) {
#my $string = $client->message_string($msg)
#or die "Could not message_string: $@\n";
my $from = $client->get_header( $msg , 'From' ) ;
my $to = $client->get_header( $msg , 'To' ) ;
my $subject = $client->subject($msg)
or die "Could not subject $@\n";
if ( $from =~ m{$sender}i ) {
my $notify = '/usr/bin/notify-send' ;
my $title = 'New mail from ' . $from ;
my $body = $subject ;
my $icon = '-i ~/Pictures/Icons/icon_black_muffin.jpg' ;
my $time = '-t ' . (1000 * 10 ) ;
$body =~ s/(['"])/\\$1/g;
$title =~ s/(['"])/\\$1/g;
$title = join q{"} , '' , $title , '' ;
$body = join q{"} , '' , $body , '' ;
qx{ $notify $title $body $icon $time } ;

It takes one or more sender substrings. -sender '' , for example, would pop notifications from all mail from Purdue University addresses. And the good thing is, you don't need to change much more than the server name, username and password to make it work on my work server.


TV: Conjecture about White Collar

I didn't intend for this space as a place for me as a place to talk about TV, but it's where I have cut tags to protect people from spoilers. C'est la vie.

White Collar is a show on USA Network. The main character is Neil Caffrey, a con man. He was caught by Peter Burke, an FBI agent. He escapes on the cusp of his release, looking for his wife. Peter catches him again, and, in part inspired by his sense of fairness, springs him to serve as a consultant. There we have the premise.

At one point, Peter is looking for a way to get a warrant to enter a warehouse he is sure but cannot prove is the location of a crime scene. Neil, a criminal not a cop, wonders why they just don't go in. Peter then passes him the Big Book of Warrant Law. Neil reads the Big Book, figures it out, and gets himself and the ankle bracelet location tracker dragged into the warehouse. Peter knows the game when he follows the machine-gun-toting FBI entry team into the warehouse, quoting chapter and verse as to why he can go in without a warrant. I don't know that Peter knew what he was doing when he gave the book, but he certainly knew when he got there.

Consider, for a moment, The Sting. That's the great con movie, and while we're in on great parts of the con, we don't know the final bit until the end. Same with the Ocean's Eleven remake. The audience can't know it all. So, what's the underlying con for White Collar.

We don't know what's going on with Neil's wife, but we know
  • Neil knows Peter about as well as Peter knew Neil
  • This includes Peter being smart and liking smart, and we mean really smart. He has great ire over the large number of Harvard graduates in his unit who are not nearly as on-the-ball as he is.
He had to know that Peter would come after him if he escaped. If he just waited a month, he would've been a free man, rather being chained to Peter for four years, but now he has a badge. Presumably, he thinks he needs that kind of backing, the kind of backing that can fill a warehouse with armed agents in very little time, to confront whoever has his wife. Which makes an acceptable series-long Big Bad.


Trying Dropbox

I'm trying DropBox. It seems neat. I'm at work. I have two machines running, my main Linux box and my XP netbook. I have a directory in Linux, /home/jacoby/Dropbox/, where I can put things. I put it there, and after some time for uploading and downloading, the items in that directory are placed in C:/Documents and Settings/jacoby/My Documents/My Dropbox/ on my netbook, and the ~/Dropbox/ directory at home.

Isn't that cool?

I can also tell DropBox to share a subdirectory or file with friends who also use DropBox.

This is where you come in.

Sign up and you get to share things with me, and we both get 256MB additions to our default 2GB disk quota.

The thing I'm starting to do is put the images I use a lot, my favorite user icons and background images, in ~/Dropbox/Photos? so that they're effortlessly spread across all the places I'd use them. I'm also considering a ~/Dropbox/bin/ directory that will hold the scripts I go to most often. A poor excuse to not sit down and learn to love git, true, but still kinda neat.


A Few Words on Net Neutrality

I am a user of an ISP. I'm sure you heard of it. I feed my TV through the same wire I feed my home network with. I get 10mbps down and 3 up, more or less, but I share a local network with those people in my neighborhood, so if lots of folks are running some tools (BitTorrent, for example), that could tend to hinder my network usage. This makes me unhappy with my ISP, and this makes my ISP unhappy, so they throttle back the network traffic associated with those tools.

This capability is built into the high-level switches that ISPs use. There's an acronym, QoC for "quality of service", that's all about this kind of thing.

I used to use a service, and I did like it, called Vonage. This provides VoIP, or Voice over IP. My ISP, which also does cable TV, is becoming a competitor to Vonage, handling their own VoIP. It seems like it would be relatively simple to throttle network going to and from Vonage just like they throttle traffic handling BitTorrent packets. This would be technologically easy for them — we've established that they have the technology — but if you, like me, have decided that Vonage is the way you want to go, you get tired of an ISP that sucks like that and move on to one that doesn't suck like that.

This is what I understood Net Neutrality to be about.

But I'm thinking I might be getting to be wrong about that.

I think my statements so far shows my biases. To a certain extent, shaping the traffic of a network to make it more usable is the business of an ISP. But there are points where that is illegitimate. My feeling is that Networks should have Neutrality, but that, with an acceptable level of competition, ISPs that don't mess with you have a competitive advantage over those who do. But, ultimately, that's an issue between the people who provide the network to my house and the people who have things running on their servers. As a programmer, I can see myself eventually working for a start-up, but beyond that, really, there's little direct effect this would have on me personally, and for most people.

Glenn Beck is Glenn Beck. Like him or not. I'm not going to try to argue into accepting him. Skip ahead to 3:55 and you see Van Jones talking about Net Neutrality. Or something that's unrelated to Net Neutrality as I understand it, but going by that name. Net Neutrality meaning free internet to everybody, that doesn't seem ... well, forget "right" or "wrong". It doesn't seem related to the subject at hand.

Let us step back and look sideways. Let us assume that this graph is right. Phones these days have more powerful chips than any computer I had before 2002. And that's Verizon, AT&T, Sprint, T-Mobile — lots of companies that are ISPs. I'm not seeing the problem Van Jones sees, but I can see that Net Neutrality having a generally neutral effect on the population at large.

But what, if anything, am I missing?


Perl IS a community!

Ever have code that doesn't work and you don't know why? I do on occasion, and the error messages didn't tell me anything useful, so I decided to try Perl::Critic on it. This is less a tool to debug your non-functioning program than a program that tells you a better way to have your functioning program function, but I thought it could tell me something.

I generally start all my programs these days with:

use Modern::Perl ;
This takes the place of this:

use 5.010 ;
use strict ;
use warnings ;
This is very nice, in that it gets you to the cool stuff in Perl in one line.


Perl::Critic wants you to run using strict and warnings, and when you use Modern::Perl, it doesn't explicitly say that you are using them, and Critic dinks you for it.

I thought that was interesting.

And, today, when you find something interesting, you tweet it. I also put it on, which is like twitter but mostly programmer types go there. And I got a response. From chromatic on and from the Critic folks on Twitter.

That just warms my heart. Not specifically the help to make it work, which is of course great, but that the developers are listening.

And, incidently, making a .perlcritic file with this in it makes it work:

equivalent_modules = Modern::Perl


Modern One-Liner Perl

I have never been much of a fan of Perl one-liners. Take every slur about Perl that exists in the popular imagination, and that's the reality for one-liners.

perl -e 'print 51 * 51 , "\n"'
But now, by going -E instead of -e, you bring in Perl 5.10. This means you get say, which is by far my fave Perl 5.10 addition.

perl -E 'say 51 * 51'
I'm already starting to do one-liners more, now that I have say. Using realias is also helpful with this.

Credit where due.


Avoiding Wallop with Perl

This is a little bit of Perl code that copies a file, but if a file by that name exists, appends a number between the name and the suffix.

use Modern::Perl ;
use File::Copy ;

my $from = '/home/jacoby/' ;
my $to = '/home/jacoby/' ;

while ( -f $to ) {
my @to = split m{\.}mx , $to ;
my $suffix = pop @to ;
if ( scalar @to == 1 ) {
my $num = 1 ;
push @to , $num ;
push @to , $suffix ;
elsif ( $to[-1] !~ m{\D}mx ) {
my $num = pop @to ;
$num ++ ;
push @to , $num ;
push @to , $suffix ;
else {
my $num = 1 ;
push @to , $num ;
push @to , $suffix ;
$to = join '.' , @to ;
say "F\t" . $from ;
say "T\t" . $to ;
copy $from , $to ;


Perl Rocks

I keep meaning to blog on Perl, but I can't find anything new and useful to bring up. I just can't be a Perl iron man, it seems.

In lieu of content, I'll just say this:

Perl Rocks!


Gizmo + GoogleVoice = Frustration

I'm a big fan of the idea of GoogleVoice, but I don't have a cell phone at the moment and work in a sub-basement anyway, so I want to use it with a computer phone. But I've been on this before.

What I have changed is Auto-Answer. I clicked that and tried again. I hear the voice, but I can't input the numbers. Go to about 8:35 on the YouTube video above and you'll see exactly won't come up.

Skype won't uninstall, so I'm reinstalling to deinstall. I hope that will help.


Desperately Seeking Google Weather API Vocabulary

I work in a sub-basement. From about 9am to about 5pm, I don't see the sun. Great amounts of change can happen in that time, and I hate coming up for air without knowing what's up. So, great amounts of my programming come from trying to keep track of conditions. I send the weather info to local printers. I have a twitter feed. I have gravitated to using XML::DOM and Google's Weather API to give me the information. It's not too detailed, it's fast, and if Google's down, the Internet is down.

I have since found notify-send (mentioned here) and have found a set of weather icons that I like. And I'm working on getting the notifications look good.

My problem is that I'm not seeing a one-to-one mapping between the condition strings I'm getting from Google and the file names I'm getting from the icon sets. Nor are the image names listed in the XML.

So, I created a simple mapping of Condition strings to icon names.

sub config_icons {
my $path = '/home/jacoby/Pictures/weather_icons/' ;
my %config ;
$config{ 'Clear' } = $path . 'sunny.png' ;
$config{ 'Partly Cloudy' } = $path . 'cloudy1.png' ;
$config{ 'Mostly Cloudy' } = $path . 'cloudy3.png' ;
$config{ 'Cloudy' } = $path . 'cloudy5.png' ;
$config{ 'Overcast' } = $path . 'overcast.png' ;
$config{ 'Haze' } = $path . 'fog.png' ;
$config{ 'Fog' } = $path . 'fog.png' ;
$config{ 'ELSE' } = $path . 'dunno.png' ;
return \%config ;
This is a list of weather conditions that were observable in the American Midwest in summer and early fall, 2009. This is not the whole list of weather conditions.

What I am looking for today are the other ones, so I can finish this code and maybe send it out to you. Any help?


The better way for Javascript

Previously, In the post Why People Hate Javascript, I spotlight an example where Firefox does one thing and Internet Explorer — I'll step out and say that Firefox does the right thing and IE does the wrong thing, but if there's doubt about which is correct in the language specification, that's a bad on the standards committee — and I was rightly, correctly informed that Javascript, through the DOM, had a means to get the information I needed without relying on the hated x.split(). Which I include below the cut.

$(function() {
var protocol = window.location.protocol ;
var hostname = window.location.hostname ;
var path = window.location.pathname ;
var query = ;
var hash = window.location.hash ;
var url = protocol + '//' + host + path + query + hash ;
if ( host != hostname ) {
window.location.replace( url ) ;
} ) ;
The hostname you want to redirect to is placed at your discretion as var host, but I choose not to include it here. The only jQuery aspect to this is the wrapper, which makes this script run when the page is fully loaded. Which probably isn't strictly necessary. And this does work on both IE and FF.


Compiling Rakudo on Ubuntu

During the last meeting of my local Perl Mongers group, our point person on Perl 6 stated that he couldn't get it to compile, he couldn't get it to compile 2 months ago, and if it can't compile, nobody's ever going to use it and it's dead.

I tweeted it, of course, and got a response.
@JacobyDave It works over here. Which instructions did you use? I use 3 hours ago from Tweetie in reply to JacobyDave

So, of course, I had to try it.

jacoby@oz:~$ $ git clone git://
bash: $: command not found

It seems I didn't have git installed.

jacoby@oz:~$ apt-cache git
E: Invalid operation git
jacoby@oz:~$ apt-cache search git | wc -l
jacoby@oz:~$ apt-cache search git | grep -i '^git'
git-core - fast, scalable, distributed revision control system
git-doc - fast, scalable, distributed revision control system (documentation)
gitk - fast, scalable, distributed revision control system (revision tree visualizer)
git - transitional dummy package which can be safely removed
git-arch - fast, scalable, distributed revision control system (arch interoperability)
git-buildpackage - Suite to help with Debian packages in Git repositories
git-cola - highly caffeinated git gui
git-cvs - fast, scalable, distributed revision control system (cvs interoperability)
git-daemon-run - fast, scalable, distributed revision control system (git-daemon service)
git-email - fast, scalable, distributed revision control system (email add-on)
git-gui - fast, scalable, distributed revision control system (GUI)
git-load-dirs - Import upstream archives into git
git-svn - fast, scalable, distributed revision control system (svn interoperability)
gitmagic - Guide about Git version control system
gitosis - git repository hosting application
gitpkg - helper scripts for maintaining packages with git
gitweb - fast, scalable, distributed revision control system (web interface)
jacoby@oz:~$ sudo apt-get install git gitmagic git-doc
[sudo] password for jacoby:
Reading package lists... Done
Building dependency tree
Reading state information... Done
git is already the newest version.
Suggested packages:
git-core git-arch git-cvs git-svn git-email gitk gitweb
The following NEW packages will be installed:
git-doc gitmagic
0 upgraded, 2 newly installed, 0 to remove and 8 not upgraded.
Need to get 1333kB of archives.
After this operation, 6136kB of additional disk space will be used.
Get:1 jaunty/main git-doc 1: [1126kB]
Get:2 jaunty/universe gitmagic 20090101-1 [207kB]
Fetched 1333kB in 2s (587kB/s)
Selecting previously deselected package git-doc.
(Reading database ... 206981 files and directories currently installed.)
Unpacking git-doc (from .../git-doc_1%3a1.6.0.4-1ubuntu2_all.deb) ...
Selecting previously deselected package gitmagic.
Unpacking gitmagic (from .../gitmagic_20090101-1_all.deb) ...
Processing triggers for doc-base ...
Processing 1 added doc-base file(s)...
Registering documents with scrollkeeper...
Setting up git-doc (1: ...
Setting up gitmagic (20090101-1) ...

jacoby@oz:~$ $ git clone git://
bash: $: command not found
jacoby@oz:~$ git clone git://
The program 'git' is currently not installed. You can install it by typing:
sudo apt-get install git-core
bash: git: command not found
jacoby@oz:~$ sudo apt-get install git-core
Reading package lists... Done
Building dependency tree
Reading state information... Done
Suggested packages:
git-arch git-cvs git-svn git-email git-daemon-run git-gui gitk gitweb
The following NEW packages will be installed:
0 upgraded, 1 newly installed, 0 to remove and 8 not upgraded.
Need to get 4322kB of archives.
After this operation, 8995kB of additional disk space will be used.
Get:1 jaunty/main git-core 1: [4322kB]
Fetched 4322kB in 7s (599kB/s)
Selecting previously deselected package git-core.
(Reading database ... 207451 files and directories currently installed.)
Unpacking git-core (from .../git-core_1%3a1.6.0.4-1ubuntu2_i386.deb) ...
Processing triggers for man-db ...
Setting up git-core (1: ...
Setting up git-core (1: ...
jacoby@oz:~$ git clone git://
Initialized empty Git repository in /home/jacoby/rakudo/.git/[0:]: errno=Connection timed out
fatal: unable to connect a socket (Connection timed out)
jacoby@oz:~$ jacoby@oz:~$

Needed to open up a hole in the firewall to allow git.

jacoby@oz:~$ git clone git://
Initialized empty Git repository in /home/jacoby/rakudo/.git/
remote: Counting objects: 18798, done.
remote: Compressing objects: 100% (5049/5049), done.
remote: Total 18798 (delta 13754), reused 18345 (delta 13370)
Receiving objects: 100% (18798/18798), 2.49 MiB | 723 KiB/s, done.
Resolving deltas: 100% (13754/13754), done.

Creating Makefile ...
Cleaning up ...

You can now use 'make' to build Rakudo Perl.
After that, you can use 'make test' to run some local tests,
or 'make spectest' to check out (via svn) a copy of the Perl 6
official test suite and run its tests.

jacoby@oz:~/rakudo$ make
/home/jacoby/rakudo/parrot_install/bin/parrot /home/jacoby/rakudo/parrot_install/lib/1.6.0-devel/library/PGE/Perl6Grammar.pbc \
--output=src/gen_grammar.pir --encoding=utf8 \
src/parser/ src/parser/

jacoby@oz:~$ cat
say 'hello' ;
jacoby@oz:~$ rakudo/parrot_install/bin/perl6

It compiles on my Jaunty Ubuntu box. I don't have a clue as to why it wouldn't compile on his Fedora box. And, at some point, I'll have to try it on Windows.


Why People Hate Javascript, or Must Mean Chum

I work with a web front-end to a genomics database. This is what pays my bills. We recently moved the URL from one associated with my university to a We decided to push all users coming into the .edu address to the .org address. Easy javascript, I thought. I had finished something and decided to test it with IE, which I never use. "The only legitimate use for Internet Explorer is to download Firefox", as I always say.

But in IE, I got bouunced to some weird, wrong URL. So, I added some debug code to figure out what's going on.

Here's the code that generated this, with dyked-out relocation code.

$(function() {
var u = $( document ).attr('URL') ;
var v = u.split( /\//g )[2] ;
var w = u.split( /\//g ) ;

if ( v != host ) {
w[2] = host ;
x = w.join('/') ;
alert( u + '\n' + v + '\n' + w + '\n' + x + '\n') ;
// window.location.replace( x ) ;

} ) ;

u is the URL. Both the same.

v should be the host, which is the problem. A url looks like this: protocol://host/path/?querystring, where path could contain many slashes. Split on slashes,
protocol should be the first element, or element [0]. Element [1] should be blank. Element [2] should be host.

But it just isn't.

w is an array, made from the URL and joined with a comma for display purposes. The alert from Firefox says http,,host,path, showing a blank element 1, as it should be. The alert from IE says http,host,path. Evidently, it thinks the regular expression was variable.split( /\/+/g ),which matches and splits on one or more slash, rather than variable.split( /\//g ), which matches and splits on one and only one slash.

There is a scene in Cabin Boy where Chris Eliot, a candidate for upper-class twit of the year, tells the existing cabin boy (Andy Richter) that he wants some fancy soup for dinner. The cabin boy walks off and decides "He must mean chum". Chum is rotting fish guts. Microsoft decided that I must have meant chum.


Flawed Perl

Take my Weather Notification on the Printer script and add the notify-send program which connects to Gnome's OSD setup and you can get some pretty cool stuff.

Except, it seems, something doesn't like Unicode.

At first, I thought the problem was on notify-send, but 1) remembering what had gone on with my twitter weather script (@PurdueWeather) and 2) testing with direct use of Unicode made me decide that it's Perl's fault.

And there are many solutions.

It strikes me that there should be something along the lines of use Unicode ; that, with one line, tells Perl you're using Unicode strings. I'm sure there's a Unicode module, and I'm reasonably sure that's not what it does.

Anyway, code for using notify-send and the Google Weather API to tell you what's going on with the atmosphere is under the cut. For my next trick, I will add images.


# $Id: 11 2006-03-22 01:21:03Z yaakov $

# Connects to a JetDirect equipped HP printer and uses
# HP's control language to set the ready message on the
# LCD display. Takes an IP address and message on the
# command line. My favorite message is "INSERT COIN".
# Keep in mind the limitations of the display when composing
# your clever verbiage.
# Yaakov ( )
# Modified by Garrett Hoofman
# 10/18/2007

# Modified by David Jacoby
# 12/10/2008

# Modified by David Jacoby, using notify-send and tweaking Unicode
# 09/08/2008

use strict ;
use warnings ;
use 5.010 ;
use Getopt::Long ;
use IO::Interactive qw{ interactive } ;
use IO::Socket ;
use XML::DOM ;
use Data::Dumper ;
use subs qw{ get_weather notify } ;

my $zip = '' ;
my $forc = 'F' ;
my $interactive = '' ;
my $degree = '°' ; #the unicode, straight
$degree = "\x{00b0}" ; #the unicode, specified
my $rdymsg = "Ready" ;

'zipcode=s' => \$zip ,
'forc=s' => \$forc ,
) ;

if ( $forc eq 'c' || $forc eq 'C' ) { $forc = 'C' }
else { $forc = 'F' }

$zip !~ /\d/ and exit 0 ;
my $weather = get_weather ;
notify $weather ;

exit ;

########## ########## ########## ########## ########## ########## ##########
sub get_weather {
my $rdymsg ;
my $parser = XML::DOM::Parser->new() ;
my $file = '' ;
#my $zip = shift ;
$zip =~ s{(\d{5})}{}mx ;
$zip = $1 ;
$file =~ s/XXXXX/$zip/mx ;
my $doc = $parser->parsefile( $file ) ;
my $city =
$doc->getElementsByTagName( 'city' )->item( 0 )->getAttribute('data') ;
my $curr_temp ;
if ( $forc eq 'C' ) {
$curr_temp =
$doc->getElementsByTagName( 'temp_c' )->item( 0 )->getAttribute('data') ;
else {
$curr_temp =
$doc->getElementsByTagName( 'temp_f' )->item( 0 )->getAttribute('data') ;
my $curr_cond =
$doc->getElementsByTagName( 'condition' )->item( 0 )->getAttribute('data') ;

my @output ;
push @output , qq{Conditions for $city} ;
push @output , qq{ $curr_temp$degree $forc, $curr_cond } ;
return join "\n" , @output ;
########## ########## ########## ########## ########## ########## ##########

########## ########## ########## ########## ########## ########## ##########
sub notify {
my $notify = '/usr/bin/notify-send' ;
my $weather = shift ;
say qq{ $notify $weather } ;
$weather = join q{'} , '' , $weather , '' ;
qx{ $notify $weather } ;
return ;
########## ########## ########## ########## ########## ########## ##########


People share the gift of gab between themselves

I am a Google Voice user, and I have been since it's been GrandCentral. I use it because voice mail connecting to email is an obviously good thing, transcribing your voice mail is a really good thing and the dial-in voice mail interface is an obvious dog. Also, I work in a sub-basement where cell phone signals do not reach. If I want to know that people are trying to get ahold of me, I had better have a voicemail service that uses email.

But that just means that I can hear the voice mail. What if I want to answer?

Lifehacker has a post on using Gizmo to do just that. They make it sound so simple. Set up Gizmo. Tell Google Voice you have a Gizmo Phone. Have Google Voice confirm your Gizmo number. Then you're golden.

Unless you're not.

Here is my entirely unhelpful order of events.
  • Tell Google Voice I want to verify my Gizmo phone.
  • My computer rings.
  • Time passes.
  • Google Voice gives up.
  • Gizmo's soft phone pops up to tell me I have a missed call.
I have tried Skype and it has ... kinda worked. The problem is, nobody I know uses Skype. On second thought, the problems are and they are nobody uses Skype, and if I'm being cheap (and I am) I'm not going to pay for SkypeIn.

It might be something simple and stupid. My current cannot-be-checked-at-work theory about my wife's laptop is that it's a permissions error. I'll work it out and see.

Oz never gave nothin' to the Tin Man...

Tinman is the name of my Compaq Mini netbook. Twiki* is the name I gave to my wife's netbook, which is an EeePC. Both, at this point, run Windows XP. Yeah, I'm the big Linux guy, but as a web developer, I find it useful to have a machine running Internet Explorer that I can test against.

We got the Mini with a deal with Sprint. We get the card Bill Kurtis has been pushing, which would allow someone to use the Internet when far away from wireless access points, using the Sprint cell network for data. It also provides good and useful GPS information like location and speed and the way to the closest Sprint store. I got a netbook out of the deal (yay) but I live in a house with Wi-Fi and work in a dank sub-basement with Wi-Fi and sufficient network cables. I don't find the need to check email much when I'm not either at work or at home. However, K spends her day running around a lot. It therefore makes reasonable sense for her to use it. So she asked me if she could have it.

Let me cut to the end, of the story, just for a moment. The dingus, once set up, is set up. You have to reinstall the interface software, sure, but anything you plug it into should be able to quickly get online, because by plugging it in you've done all you have to do to log onto the network.

Unless you have some sort of problem with your USB. Which Twiki seems to have.

* In the beginning of the Mystery Science Theater take on Catalina Caper, Joel has the bots say their prayers, even for Twiki. My eldest asked "Who is Twiki?" This is the description I gave.

There was a show in the late 70s and early 80s called Buck Rogers. There was a character whose name I don't recall, who was a hyperintelligent computer which takes the form of a of a blinged-out hubcap. Being a hubcab, that character cannot move, so there's Twiki, who looks like a cartoon seven-year-old with a bowl cut frozen in carbonite, who wears the blinged hubcap like Flavor Flav wears a clock.

This caused my son to laugh out loud.

I know the time, boieee

The installer comes with the Sprint card, and I have installed it four times. I have talked to the Sprint helpdesk. I have tried this process on three (3) computers ( Twiki, Tinman and Maria, named after the evil Maria from Metropolis ) and the problem comes up only on Twiki. Yeah, I have other Windows machines I can test against, sure. But the take-away seems that there's something wrong with K's machine.

Just had a thought. K might not be running as Admin. In general, that's good, but if she is, she can't install the drivers in the protected places and thus can't get networking going. I thought she was running with Admin privs, but I do not recall. Still, that's worth a look. ETA I checked, and she's running as Admin. It isn't that.


Enabling "Read More"

There is an explanation in Blogger's Answer section: How can I create expandable post summaries? It is not the most clear, although it is better than some documentation I have worked with.

Just to know, I use a more modern template for this blog, and this post will use those conventions.

  1. Modifying The Post Template
    When you move to make a new post, you have to add a span element named "fullpost".
    It's in that span that the part of your post that you plan to Read More sits. You can try to add this each time, but the easiest way is to put that as part of your default Post Template, which can be modified at:
    Settings << Formatting, toward the bottom of the page.
  2. Adding The "Read More" Text
    Now we have to move to editing the template. You find it here: Layout << Edit HTML. You are modifying the Post widget at this point, so you have to check Expand Widget Templates. Look for this line within the Template:
    I am not sure what the underlying engine is processing this code — I'm sure I could find out without too much trouble, but here we're adding a conditional which adds this chunk of text and a link if the pageType is not item.

    <b:if cond='data:blog.pageType != "item"'><br /><a expr:href='data:post.url'>Read more!</a></b:if>
    This adds a link to the bottom of the page. It does not hide the contents of the element we added to the template. Yet.
  3. Changing The Display Here we get into the wonder of Cascading Style Sheets (CSS). CSS is all about controlling how your page looks. The block that holds the CSS looks much like this:

    ... Large Chunks Removed ...
    The recommended code to hide the Read More text is as follows:

    <b:if cond='data:blog.pageType == "item"'>
    span.fullpost {display:inline;}
    span.fullpost {display:none;}
    The problem I have found is that the CSS addition breaks the page a little and doesn't work. What I have found to work is putting a style block right under the generated block and putting the code within that:

    <b:if cond='data:blog.pageType == "item"'>
    span.fullpost {display:inline;}
    span.fullpost {display:none;}
There we have it; everything you need to add expandable post summaries. Good night and good luck.



Honestly, I don't think I write here nearly enough to justify enabling cut-text. I don't think my posts are long enough, either. But my wife has asked me to look into it. So I am.

Here will be the cut, when I have one. I don't see the parts in my template for this, however.

I used this as a template for the READ MORE stuff. The one problem I found was that my conditionals were breaking the stylesheet definition. I don't know what engine or tools underlie Blogspot, and I couldn't really see what was saying STYLE and /STYLE, but when I made a second style block and stuck their stylesheet stuff into that, and it worked.