Computers: April 2004 Archives


| | Comments (0)
I wonder if there is anyone else out there, besides me, who actually finds both South Park and Mark Russell funny.


| | Comments (0)
I wanted to tap out a beat and find out how many beats per minute it is, and a quick glance turned up nothing too good for Mac OS X (though I am sure I'd seen something like it before); so, as I am wont to do, I wrote my own. Just run it in the terminal, tap out your rhythm. It only calculates for the last five beats (modify to your pleasure ...).

use warnings;
use strict;
use Time::HiRes 'time';
print "Hit '.' for each beat.  Hit '.' to start, and <enter> or ^C to end.\n";
print "Keep going until you reach about 10 beats, and are satisfied with the result.\n";
$| = 1;
my @times;
1 until getc();
push @times, time();
while (my $c = getc()) {
    push @times, time();
    printf "\rBPM: %d\n", ($#times * 60) / ($times[-1] - $times[0]);
    shift @times while @times > 4;
    last if $c eq "\n";
    system 'stty', '-icanon', 'eol', "\cA";
    system 'stty', 'icanon', 'eol', "\c@";

Apple Lossless Encoding

| | Comments (0)
This is WAY too slow to stream over my AirPort network, even with AirPort Extreme (although I don't have a lot of signal strength, and the non-Extreme computer on the network slows it down further).

I had been thinking about maybe using it to rip all my CDs. I still might, but it's just too big to use for streaming, and too new to rely on it for archives.


| | Comments (0)
In Mac OS, one would get the data out of an Apple event AEDesc object by merely returning the dataHandle portion of the struct. It's a Handle object.

In Mac OS X, however, one must copy the data to a new Handle object.

So when porting Mac::Carbon to Mac OS X, I made the change, and didn't think about the fact that in Mac OS X, the caller would now be responsible for disposing the Handle object that was returned. Yikes. Memory leaks abound.

Most Mac::Carbon programs I use don't really stick around. Even when they do, such as with my happening script that sets my iChat status, the amount of data that was being leaked was pretty small. The name and artist of the current track, etc.

But then I added functionality to the script so it would change my iChat account icon to the album cover of the track I am listening to. So instead of 100 bytes or so, I was now leaking as much as 250K or so, every 10 seconds. That adds up pretty quick.

I have a temporary fix (manually disposing of the Handle object), but I need a more permanent solution. Matthias (original author of Mac::AppleEvents, MacPerl, etc.) gave me some good ideas, and I'll be working on it soon.

I think I'll use some XS tricks to make a new data type, XAEDesc, which will contain both the AEDesc and a Handle, so instead of creating a Handle each time, the data is transferred to and from the Handle in the XAEDesc. When the AEDesc is destroyed, its corresponding Handle will be disposed of automatically, like it was previously (by modifying AEDisposeDesc to also call DisposeHandle).
I wanted to create a bunch of windows, tabs, etc. and do things in them. So, I wrote this script. I run it when I am doing maintenance and refresh on useperl, and for some other sites.

It opens one window (terminal) in iTerm, then five separate tabs (sessions), preparing each one to do various things (ssh to a host, preparing to tail a log, etc.) and setting the name of the tab.

I normally set my session title with PROMPT_COMMAND in my environment, so I unset that env var and then set the name of the session with Mac::Glue.

It sleeps because it sometimes takes a few seconds for the unset to take, and if I set the name of the session too quickly, then it will get overwritten again. Another possibility would be to go through everything, then go back and set the session names on a separate pass.

waitforit() prints out a command and then waits for me to hit return, to execute it. I couldn't find a good way to tell iTerm to print the text and not execute it, so I execute perl on the host to do it for me. :-)

use warnings;
use strict;
use Mac::Glue ':all';
my $iterm = new Mac::Glue 'iTerm';
my $prj = 'useperl' || shift;  # different for each project
my $nfs = "$prj-nfs-1";
my $db  = "$prj-db-1";
my $watchneg = ' | egrep -v "File does not exist"';
# first arrayref happens before the unset, second after
my %sessions = my @sessions = (
    Main    => [["ssh $nfs"], []],
    DB    => [["ssh $db"], ['mysql']],
    Ctrl    => [[], [waitforit(qq'$prj-control -d; $prj-control -p 5')]],
    HTTP    => [[], [waitforit(qq'$prj-watch $watchneg')]],
    slashd    => [["ssh $nfs"], [
        'cd /usr/local/slash/site/*/logs',
        waitforit('tail -f slashd.log')
@sessions = grep !ref, @sessions;
my $term = $iterm->make(new => 'terminal');
for my $num (1 .. @sessions) {
    my $name = $sessions[$num - 1];
    my $sess = $term->obj(session => $num);
    $term->Launch(session => 'Default Session');
    $sess->write(text => 'ssh osdn');
    for my $cmd (@{$sessions{$name}[0]}) {
        $sess->write(text => $cmd);
    $sess->write(text => "unset PROMPT_COMMAND");
    for my $cmd (@{$sessions{$name}[1]}) {
        $sess->write(text => $cmd);
    sleep 5;
    $sess->prop('name')->set(to => $name);
sub waitforit {
    my($cmd) = shift;
    $cmd =~ s/'/'\\''/g;
    return "perl -e '\$c = shift; print qq(\$c: ); <>; system(\$c)' '$cmd'";

More Music

| | Comments (0)
I'm working on my music room; I've recently rebuilt an old guitar (see before and after), adding all new pickups and electronics; I got a Yamaha digital piano; and now it's time to start actually recording music.

So far I've done a couple of new demos, Crossroads (to hear the guitar before and after, together) and a Randy Newman song, Political Science (so I could practice recording the piano and vocals).

I think I might re-record KLB (Known Lazy Bastard) next.

Die Die

| | Comments (0)
I signed up, for $15, to listen to all the Major League Baseball games online, back on March 4. Shortly after this, on March 24, announced a deal with Microsoft where they would make most content available only through Windows Media Player.

The short of it is that after I signed up, changed the deal, and made it so I could only listen to the archived games -- that I paid for -- if I used Windows Media Player, instead of Real Player, as I had been doing.

This is called "customer service," where the customer is, of course, Microsoft, and not me. I am demanding my money back, of course. I hope many more people do the same.

Best Tech Article Ever

| | Comments (0)
You can only drag one bookmark (or favorite) at a time from Internet Explorer to Safari.

Drag one bookmark at a time from Explorer to Safari.

Now you know!

Bundle-Slash-2.34 Released

| | Comments (0)
Bundle-Slash-2.34 has been released. Download it from the CPAN or

(Note: it may take time for the release to propagate to the various download mirrors.)
Posted using release by brian d foy.

Wake Up

| | Comments (0)
I don't know if there exists something better, but I couldn't find it, and I was curious anyway, and so I wrote my own.

I need to wake my computer at 3 a.m. to run nightly backups (using from, but if the computer is asleep, it doesn't work. IOPMSchedulePowerEvent() can wake the computer at a given time, but I had no existing Perl interface to it. I could have added it to a Mac:: module, but in this case, I didn't have the time, and I currently have no use for it other than this one script. Therefore, Inline.

One especially interesting thing about the code -- to me -- is that it uses the CFAbsoluteTime data type, which -- for reasons unknown to me -- is in seconds since January 1, 2001, GMT. So the C code keeps a constant to calculate the difference from perl's time().

# i use this to make sure my computer wakes up by 3 a.m. every morning,
# so my backups can run
# i run it from cron every 15 minutes (the computer is set to sleep
# after 15 minutes of inactivity)
# */15 * * * * /Users/pudge/bin/wake.plx
# 2004-04-01
use strict;
use warnings;
use Time::Local;
use Inline  C => 'DATA',
    LDDLFLAGS => '-bundle -flat_namespace -undefined suppress -framework Carbon',
    INC       => '-I/Developer/Headers/FlatCarbon';
my $now = time();
my @today = localtime($now);
@today[0, 1, 2] = (0, 55, 2);
my $then = timelocal(@today);
$then += 86400 if $now > $then;
schedule_event($then, 'wake');
#undef Move
#undef I_POLL
#undef DEBUG
#include <Carbon.h>
#include <mach/error.h>
// "type" defines here
// can be sleep, wake, shutdown, poweron, and wakepoweron
//#include <IOKit/pwr_mgt/IOPMKeys.h>
// difference between Unix epoch and CFAbsoluteTime epoch
#define EPOCH_DIFF 978307200
long schedule_event(long seconds_time_to_wake, const char * event_name)
    CFDateRef time_to_wake;
    CFStringRef type;
    IOReturn io_error;
    seconds_time_to_wake -= EPOCH_DIFF;
    time_to_wake = CFDateCreate(kCFAllocatorDefault, (CFAbsoluteTime)seconds_time_to_wake);
    type = CFStringCreateWithCString(kCFAllocatorDefault, event_name, NULL);
    io_error = IOPMSchedulePowerEvent(time_to_wake, NULL, type);
    if (io_error != 0) {
        printf("system: 0x%x, subsystem: 0x%x, code: 0x%x\n",
    return io_error;
<pudge/*> (pronounced "PudgeGlob") is thousands of posts over many years by Pudge.

"It is the common fate of the indolent to see their rights become a prey to the active. The condition upon which God hath given liberty to man is eternal vigilance; which condition if he break, servitude is at once the consequence of his crime and the punishment of his guilt."

About this Archive

This page is a archive of entries in the Computers category from April 2004.

Computers: March 2004 is the previous archive.

Computers: May 2004 is the next archive.

Find recent content on the main index or look in the archives to find all content.