Slash Boxes
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

grinder (1100)

  (email not shown publicly)
Yahoo! ID: perlgrinder (Add User, Send Message)

Editor of p5p summaries, member of the p5p peanut gallery.

Journal of grinder (1100)

Thursday February 12, 2009
04:15 PM

print scalar gmtime 1234567890

It seems like only yesterday we passed epoch 1000000000 when in fact it was nearly eight and a half years ago. On the other hand I remember epoch 1111111111 quite clearly since it was just before my birthday.

And now we come to another momentous epoch, that of 1234567890. I just happened to notice this as I was watching a Cyrus imapd logfile.

2009-02-13 23:31:30 UTC, by my reckoning. A good excuse for a pint, if you ask me.

Tuesday October 28, 2008
05:31 AM

Please test File::Path 2.06_06

A couple of usability bugs turned up when File::Path was dragged kicking and screaming into the third millennium, with its new options hash interface.

Refactoring the code introduced a nasty symlink chmod 777 error, and the heuristics for detecting the new way of calling rmtree and mkpath made the wrong call in some circumstances.

All should be fixed, and the code as it stands should be ready to be bundled with perl 5.8.9. To help this happen, could people give this a spin?

Notably, users of minicpan should see errors about uninitialized variables go away, and people who see spurious all-digits directories created in $HOME should also see them go away.

Also, is the documentation clear? Please lodge RT reports for any problems you encounter.

Friday October 19, 2007
06:20 AM

Another fun (?) SQL puzzle

So, I have a database with a particularly nasty design decision. We have people who belong to cost centres, usually only one, but sometimes with a prorata on two cost centres. The programmer responsable for creating the table denormalised things, so rather than having

    EMP1  UNIT1 50%
    EMP1  UNIT2 50%
    EMP2  UNIT3 100%
    EMP3  UNIT1 100%

we have something that looks like

    EMP1   UNIT1   UNIT2    50   50
    EMP2   UNIT3   null    100    0
    EMP3   UNIT1   null    100    0

That is, both cost centre ids in the same table, the second one usually null. It is a given that there will never be more than two. This table is of course an utter bitch to work with. Turns out we can cheat a bit, by only keeping track of the rate of the first centre, the second is just 100-first (which also helps cut down round-offs). Let us create a table to play with:

create table t1 (
   id_person varchar(10),
   rate      number(5,2),
   unit1     varchar(3),
   unit2     varchar(3),
   val1      number(10),
   val2      number(10)
insert into t1 values ('alice',   1, 'U1', null,   10,   20);
insert into t1 values ('bob',     1, 'U2', null,    4,    8);
insert into t1 values ('carol', 0.5, 'U1', 'U2',  300,  600);
insert into t1 values ('david', 0.2, 'U1', 'U3', 6000, 8000);

Now I want the sum the values val1 and val2 by unit, keeping in mind that for 'david', VAL1 6000 * 0.2 = 1200 is summed to U1, and the difference, 4800, to U3. Similarly, for VAL2, 1600 to U1 and 6400 to U3. In other words, I want the following result set:

    U1 1360 1920
    U2  154  308
    U3 4800 6400

Now the only way that I can see is to:

  1. Sum the value proratas for all people on their first cost centre. If they have one centre, they get the full hit, otherwise it's prorata'ed between it and the second.
  2. Union the above with the people having two centres, by subtracting the prorata of the first centre from the total value to arrive at the second prorata (to minimise roundoff errors, otherwise the sum of both centres will lose a cent compared with the initial sum from time to time).
  3. Treat all that as a derived table, and sum the results.

This gives the following:

    ,sum(V1) V1_TOT
    ,sum(V2) V2_TOT
from (
         unit1            UNIT
        ,sum(val1 * rate) V1
        ,sum(val2 * rate) V2
    group by
    union select
         unit2                   UNIT
        ,sum(val1 - val1 * rate) V1
        ,sum(val2 - val2 * rate) V2
        unit2 is not null
    group by
) S
group by S.UNIT
order by S.UNIT

That's pretty ugly. Is there a better way?

Thursday September 27, 2007
06:05 AM

Bitten by glob crypto context

/me is annoyed

I just spent a while chasing a stupid bug. I have an big log directory that I have to clean up. The number of files caused the shell's wildcard expansion to fail. So I wrote some perl to move things around.

And it didn't do anything. To cut a long story short, I needed the total number of files in the directory. So I had something along the lines of:

perl -le 'print scalar(glob("*"))'

That does not return the number of files. It returns the name of the first file. Or the last. I don't care.

You have to force array context and throw it away:

perl -le 'print scalar(()=glob("*"))'

This prints 31192. I wish Perl didn't do this. Nice interview question though, I guess.

Monday June 11, 2007
04:26 PM

How to recover from an out-of-sync Win32 screen resolution

Just a note to myself, in case I ever need this again, and it may help someone else....

I have a boring 17" no-name cathode ray monitor at home, coupled to a Wintel box with a reasonably useful graphics chipset on the motherboard.

The chipset appears to know how to do a virtual screen or 3000 or so pixels square, and window the screen display onto it, not that I find this particularly useful, but anyway...

One of my children has a computer game that kicks the screen into a certain resolution, and when you quit, it resets the screen resolution back into this mega-enormous resolution, and the screen attempts to try and display it at 70-80 times a second and fails dismally, instead of just setting a viewport into it. I have no idea who's fault this is. The result is what Neal Stephenson might call a snowcrash.

Actually, it's not. The machine is still completely functional except that it looks like you're looking at encrypted TV without a decoder.

After a number of reboots, the machine finally gets the message and resets the resolution to something sane. No, Safe Mode doesn't work. When I return to normal mode after a Safe session, the screen remains scrambled.

So finally after having done this too many times, I realised was that all I needed to do was to note the keyboard shortcut sequence, and then I could land the beast on instruments only.

And here is the recipe:

  1. Right-click # bring up the desktop/display menu
  2. P # select "Properties" (up arrow probably works too)
  3. Shift-Ctrl-Tab # select previous (i.e. last, right-most) display tab

  4. Alt-R # Resolution widget
  5. Left arrow 15 times # back to 800x600
  6. Enter

At the point the screen realigns itself with reality again, and then I can go and choose some other resolution.


Sunday May 27, 2007
09:37 AM

Call for testers: the new File::Path

The latest development version of File::Path (version 1.99_02) is winging its way around the world to a CPAN mirror near you. It needs to be tested on as wide a variety of platforms as possible. This includes Windows, VMS, OS/2, QNX, NFS file systems, AFS and anything else you can lay your hands on.

If all goes according to plan, it will be bundled with Perl 5.10, and it is also backwards-compatible all the way back to Perl 5.005 (and possibly earlier), which will allow older installations to be upgraded to the new version as well.

The main improvement is that instead of writing:

    rmtree( ['/foo/bar/rat', '/zug/zwang'], 1, 1 );

... (quick, what do those positional parameters do?) one may now write the more self-documenting

    rmtree( '/foo/bar/rat', '/zug/zwang',
        { verbose => 1, skip_others => 1 }

But all this needs to be tested as far as possible, to ensure that nothing has been broken during the renovations. Please report bugs on the File-Path RT queue (


Thursday May 03, 2007
03:25 PM

Ever heard of Pex::Text?

An item came up on the contact address the other day: someone was asking where to find Pex::Text since they couldn't install it.

My first stop was to try out a couple of things on, but the results were a little too helpful, i.e., pages and pages of results or nothing at all.

So I fired up my second tool of choice, based on acme's most excellent Parse::CPAN::Packages and after a couple of regexp searches I was satisfied nothing remotely like it exists.

I then turned to a reputable search engine and ran a search on "Pex::Text" and the first page was what looked to be like sploit sites, written in various slavic and asian languages I have trouble identifying.

So I closed the ticket saying that the person was on their own. But for my own edification, I'd like to know if anyone has heard anything about it (what it does, what it's used for/in), just for the record (and the fact that reputable search engines will no doubt pick up on this journal in the future).

Friday March 30, 2007
04:29 AM

Calculating years (anniversaries) between dates in SQL

Dear Lazyweb,

I've just spent the better part of an hour searching the web and coming up blank, and finally coding up my own SQL statement to solve the following problem: given a two dates, how many years apart are they? I didn't want to use Oracle's date minus date equals number of days, because I wanted to avoid the hassle of dealing with leap years.

    when (to_char(sysdate, 'MM'  ) - to_char(to_date(:dt), 'MM')) > 0
        then (to_char(sysdate, 'YYYY') - to_char(to_date(:dt), 'YYYY'))
    when (to_char(sysdate, 'MM'  ) - to_char(to_date(:dt), 'MM')) < 0
        then (to_char(sysdate, 'YYYY') - to_char(to_date(:dt), 'YYYY')) - 1
        case when (to_char(sysdate, 'DD'  ) - to_char(to_date(:dt), 'DD')) >= 0
            (to_char(sysdate, 'YYYY') - to_char(to_date(:dt), 'YYYY'))
            (to_char(sysdate, 'YYYY') - to_char(to_date(:dt), 'YYYY')) - 1
    end as "y"
    -- ,(to_char(sysdate, 'MM'  ) - to_char(to_date(:dt), 'MM'))   as "m",
    -- ,(to_char(sysdate, 'DD'  ) - to_char(to_date(:dt), 'DD'))   as "d"
from dual

I've tested a number of boundary conditions and it seems correct to me.

Now, after you stop sniggering, you may show me the function I overlooked that would have done this for me, or point out any obvious bugs.

Thursday December 14, 2006
07:22 AM

Crypt::SSLeay is broken and this is the fix (version 0.51)

I just a spent considerable amount of time to get Crypt::SSLeay installed. Far too much time. At first I blamed myself, my host, my OpenSSL installation, perl, everything.

Finally I searched the web and found the following message:

Turns out that there's a bug in the code, and a one-liner patch to SSLeay.xs fixes it. There's even an RT ticket on the matter. Grrr!

So, if you see the following warning in your build:

SSLeay.xs:252: warning: passing arg 2 of `SSL_set_info_callback' from incompatible pointer type

... and the test dumps core, then patch the source as follows:

--- SSLeay.xs.orig      2002-08-01 17:43:22.000000000 -0400
+++ SSLeay.xs   2003-01-29 21:41:17.000000000 -0500
@@ -109,6 +109,7 @@
+               SSL_library_init();
               bNotFirstTime = 1;
         RAND_seed(buf,sizeof buf);

And now it works, yay!

Tuesday July 25, 2006
11:14 AM


This article was posted to computer.risks recently.

Date: Tue, 04 Jul 2006 13:17:36 +0200
From: Peter B. Ladkin
Subject: B747 freighter crash

The Canadian TSB have issued the report on the 14 October 2004 crash of a Boeing B747 freighter on takeoff at Halifax airport, Nova Scotia.

According to a Flight International report by David Kaminski-Morrow (4-10 July 2006, p4), the TSB "says that the crew's misunderstanding of a laptop computer tool for calculating take-off performance led to the accidents. It concludes that the crew unwittingly transferred and used weight data from the aircraft's previous flight while calculating performance criteria for the next take-off. The obsolete data misled the crew to derive incorrect thrust settings and critical speeds for take-off."

The aircraft failed to lift off after rotation and overran the end of the runway by 250 meters, briefly lifting off but then striking an earth berm, severing the tail section and bringing the aircraft to earth again. All seven crew were killed.

I was deeply moved reading this. If it isn't already evident, piloting a 747 is not just a question of jockeying the thing down to the end of the runway and hitting the juice. So you put your faith in the numbers cranked out by a computer program since there are too many parameters for a person to take into account and deal with, and no-one has the numeracy skills any more to realise that things might be a little out of whack.

I wonder if the crew had a gut feeling of the unfolding events, based only on the note of the jet engines and feeling of acceleration. No doubt they knew something was amiss when the damned machine refused to haul itself into the sky at the expected time.

My heart goes out to the families left behind.