pemungkah's Journal pemungkah's use Perl Journal en-us use Perl; is Copyright 1998-2006, Chris Nandor. Stories, comments, journals, and other submissions posted on use Perl; are Copyright their respective owners. 2012-01-25T02:12:07+00:00 pudge Technology hourly 1 1970-01-01T00:00+00:00 pemungkah's Journal Quick-finding a leak <p>Symptom:<br><tt><br>Use of uninitialized value in subroutine entry at<nobr> <wbr></nobr>/home/y/lib/perl5/site_perl/5.8/Log/ line 132 during global destruction.<br></tt><br>I got this in the destruction in one of my objects when it tried to log its destruction.</p><p>Checking the <tt>Log4perl</tt> FAQ shows me that this means I have a circular reference somewhere in my code; <tt>Log4perl</tt>'s getting called during global destruction, when the <tt>Log4perl</tt> structures have already been destroyed themselves.</p><p>Trying the easy and obvious thing first, I used <tt>Devel::Cycle</tt> and tried running it on the object that was being destroyed<nobr> <wbr></nobr>... except that wasn't the object with the leak - it was simply indicating that something pointing to it had a problem. So how was I going to locate it? I tried using <tt>Devel::Leak</tt>, but I got a huge SV dump that looked like I would have to print out and then connect things together with arrows by hand.</p><p>I'm far too lazy to do that, so I thought about it a while. I had a small test case that duplicated the problem; how could I zero in on the point in the test case where I created the circular reference? The light came on: the debugger! I knew that <tt>Log4perl</tt> would throw its error during global destruction, so all I had to do was run through the code in the debugger, continuing to each point where I created more objects<nobr> <wbr></nobr>... and then simply do a <tt>q</tt> to exit the program and trigger global destruction at whatever point I liked. When I got to a line that caused <tt>Log4perl</tt> to throw the error, I'd have the piece of code had created the circular reference.</p><p>In just a few minutes, I was able to zero in on the method that was creating the circular reference, and in just a minute more, to find exactly the piece of code that had created the problem. Toss in a <tt>weaken()</tt>, problem solved. I could have done this by editing the code and moving a <tt>exit</tt> through it, but this was simple and easy, plus I didn't have to change the code to find the problem.</p> pemungkah 2009-04-27T19:49:05+00:00 journal Blogging about Perl again <p>So, back from the shadows again.</p><p>Haven't been blogging much because I've been hideously busy on stuff here at Yahoo!, but I figure I need to talk about stuff to keep my visibility up.<nobr> <wbr></nobr>:)</p><p>Anyway, my current project is part of our deployment system; since I don't know how much I can say about it, I'll be vague.</p><p>Essentially, we assemble machine contents from rules and then push these out to whatever hosts need the contents. We're getting into cloud stuff now, and it's getting even more interesting.</p><p>Last year was devoted to music; I participated in the Different Skies music festival at Arcosanti AZ last year; a wonderful experience. We arrived on Sunday and by Saturday we had composed all the music for the performance that evening.</p><p>Did a CD of the music: artwork, editing, and pressing. I'll probably put something together for an article on that later.</p><p>Anyway, nice to be back; hope to be here more frequently.</p> pemungkah 2008-10-29T23:55:58+00:00 journal Happy Hanukkah/Merry Christmas/Happy Kwanzaa/Merry Newtonmas <p>To all my friends in the Perl community: Happy Hanukkah, Merry Christmas, and Happy New Year!</p><p>Here's wishing you and yours a very happy holiday season. This is our second Christmas in Palo Alto. Our second year in California was a little less confusing than the first. Still some wonderful things -- the farmer's markets, the street festivals, of which there seemed to be one within five to ten miles each weekend day through the summer. It's also been a great place for concerts -- U2, and Sting, as well as really good local stuff. Some 100+ degree days, so N. Cal is not weather heaven, and some rains in the winter that were as heavy as monsoons in Asia, only the pervasively wetness that soaked through clothes was cold rather than hot.</p><p>I'm having a ball at Yahoo!, and Shymala has been very lucky in having the historical novelist, Beverly Swerling, decide to involve herself in the novel Shymala's been working on for the past several years. Beverly has been the perfect mentor, and a very good friend.</p><p>Shymala has had some medical problems recently that have got us both motivated to take care of some things that got postponed during all the busyness since we've been out here, so that will be part of our new year, along with getting ourselves back into a gym again.</p><p>Real estate around here, though slowing, is still ridiculous, so we are again figuring out where we might live when we grow up. Having done a cross-country relocation at an age when we should have had more sense, we want the next move to be final, but there's the difficulty that there are a lot of wonderful places out there, and who can guess what life will be like a couple of years down the road in any particular place?</p><p>We saw a lot of wonderful things over the past year - the SF skyline from Sausalito, surfers at Santa Cruz, some very happy ducks (and some very barbecued ones!), the San Jose Rose Garden, and sea otters in the ocean at Monterey. We've finally done some of he tourist stuff in SF - driving down Lombard Street (the crookedest street in San Francisco), checking out the sea lions at Pier 39, and driving across the Golden Gate, just to do it. Still haven't ridden a cable car, though. And we've had a chance to catch up with some very old friends, which was lovely.</p><p>Hope things have been good for everyone!</p><p>best wishes</p><p>Shymala &amp; Joe</p> pemungkah 2006-12-27T05:07:37+00:00 journal Perl catches a pedophile on Myspace. <p>Wired Magazine's Kevin Poulsen has shown that at least part of the problem of policing MySpace is a SMOP.</p><p><a href=",71948-0.html">,71948-0.html</a> </p><blockquote><div><p>My road to this New York police unit began in Perl.</p><p>In May, I began an automated search of MySpace's membership rolls for 385,932 registered sex offenders in 46 states, mined from the Department of Justice's National Sex Offender Registry website -- a gateway to the state-run Megan's Law websites around the country. I searched on first and last names, limiting results to a five mile radius of the offender's registered ZIP code.</p><p>Wired News will publish the code under an open-source license later this week.</p><p>The code swept in a vast number of false or unverifiable matches. Working part time for several months, I sifted the data and manually compared photographs, ages and other data, until enhanced privacy features MySpace launched in June began frustrating the analysis.</p><p>Excluding a handful of obvious fakes, I confirmed 744 sex offenders with MySpace profiles, after an examination of about a third of the data. Of those, 497 are registered for sex crimes against children. In this group, six of them are listed as repeat offenders, though Lubrano's previous convictions were not in the registry, so this number may be low. At least 243 of the 497 have convictions in 2000 or later.</p></div></blockquote> pemungkah 2006-10-17T00:10:55+00:00 journal I'm liking Jifty <p>Just lately, I ran across <a href=""></a>, an open-source audiobook project. These folks read public-domain books, upload the recordings as MP3s, and then release them in the public domain. Pretty cool.</p><p>The project has been running itself via the Librivox forum, and has come up with a pretty decent workflow to allow people all over the world to participate in reading books. Heck, they even did <a href="">The Importance of Being Earnest</a> this way, with individual folks from around the world reading lines, and an editor putting it all together to make the final "performance".</p><p>But they're starting to get to the point where it'd be better to have a separate application to handle the workflow and act as a search engine for completed works. I started looking at Jifty for this and it looks like it might be just the thing. Stealing some code from Wifty (the Jifty wiki) looks like I can bang together a basic application in a short while -- if an already-underway PHP/MySQL project isn't done first. That one has some of the more experienced Librivoxers behind it, so it may end up being the system of choice; it's more likely to have captured the workflow for sure, as I'm looking at it from the outside, as opposed to being experienced in the process.</p><p>Still, as a slightly-more difficult application, this should be a good vehicle for me to learn Jifty, and I'm going to go ahead anyway, even if they don't use mine.</p> pemungkah 2006-08-29T22:04:24+00:00 journal serious life simplification <p>Should you ever need to do dependency checking, just use instead of trying to do it yourself.</p><p>In my case, App::SimpleScan had a serious pessimization that I knew about: if you defined a variable, App::SimpleScan would try every possible value for it when subsituting, even if said variable did not appear in the test spec. This was because I needed to be able to have variable substitutions possibly contain other variable substitutions (though I drew the line at recursive definitions).</p><p>If you don't have some means of tracking dependencies, you must always check every possible combination of values. If you get a bunch of variables, this slows things WAY down, even if most of them only have a couple of different values, because you now have to check the cross-product of all possible values. Not good.</p><p> just makes all this go away. You add each variable as a node, with edges pointing to variables that this one might need to substitute. If you've defined all your variables right (i.e., no circular dependencies), then you've got what's called a directed acyclic graph (or DAG). It's essentially a forest of trees that may or may not share some nodes.</p><p>To figure out what all variables are dependent on a given one, you put the one(s) you're interested in an array, and then iterate over that, recording all the adjacent nodes. Repeat until you get no more new nodes (this could be optimized too, by pulling out nodes that have no successors, but this is fast enough for now). Ta-da: these, and only these, need to be substituted.</p><p>Oh, and detects cycles for you as well, so you just need to check whether any cycles got created as each variable is defined. Sweet.</p> pemungkah 2006-08-21T23:35:37+00:00 journal YAPC::NA 2006 part 2 <p>So on to specific items:</p><ul><li>Jeffrey Goff (DrForr)'s presentation on PPI was cool. There seemed to be some confusion in the audience about exactly how much PPI understood about perl, and some of the folks asking questions didn't quite seem to get that PPI knows how to tokenize Perl well; it doesn't claim to understand it. Quite interesting, and possibly of use to me in connection with Class::Pluggability.</li><li>Adam Kennedy (Alias)'s PITA presentation was very well done. The equation of the state of CPAN to London's sewers in the 1840's was actually spot on. Can't wait to see more from this project.</li><li>Perl::Critic was good. The idea of including a Perl::Critic test in modules is also an excellent idea - setting that up as a derivative of Module::Starter::PBP sounds like it might be worth doing.</li><li>Object::Trampoline looks like a great tool: I had some one-on-one time with Stephen Lembark after the session, and he has so many applications for this kind of thing it was amazing. Definitely looking for more stuff from him.</li><li>The Perl 6 Update showed a lot of well-thought-out and interesting stuff. Perl 6 is looking exciting again.</li><li>Luke Closs's Selenium testing stuff is great, and I intend to steal^Wadapt as much of it as possible for our testing.</li><li>Jos&eacute; Castro (cog)'s Acme presentation was great, and I've got some ideas for a few modules of my own now...</li><li>Jifty looks cool. I've installed it, and will be reading through it and through the docs of some of the more interesting-looking modules it loaded in the install process.</li><li>Steval Little's Moose talk was interesting; have to look at it a bit more to see if it's useful to me.</li></ul><p>Got a lot more time in the hall sessions this YAPC, mostly because I seemed to have given people ideas both about doing more testing and about plugins.</p><p>It was a great YAPC. Wish I could do it more often!<br> &nbsp;</p> pemungkah 2006-06-30T20:17:11+00:00 yapc YAPC::NA 2006 <p>This YAPC was far more intense than previous ones for me, both on the professional and the personal level - so much so that I've waited until getting home to try to blog about it.</p><p>I arrived Sunday evening - unfortunately too late for the arrival dinner. Or the anti-arrival dinner. In fact, I was so late that no one was willing to deliver food at all. The perils of routing oneself through O'Hare.</p><p>Chicago is an interesting town; a tad rough around the edges, and very much itself. I haven't stayed in doems since college, so I'd forgotten the dorm experience. As dorms go, the MSV dorms were quite okay. I gather that the SSV dorms were like living in concrete monk's cells. I was foresighted enough to take along a container of disinfecting wipes, which was nice to clean up around the shower and sink a little. I recommend it for anyone staying in a dorm.</p><p>The session were all very good this year, with some very cool stuff which I intend to start using and adapting as soon as possible:</p><ul><li>Object::Trampoline, which uses one of the most wonderful pieces of subtle Perl I've seen in a while: an object that exists only for the purpose of replacing itself with something else as soon as it's called.</li><li>Test::WWW::Selenium, which wraps up the Selenium web testing platform in a handy Test::More interface. I intend to try grafting this into simple_scan as soon as I possibly can.</li><li>The Goo, a development environment which features a way of deciding "what do I feel like doing" (a couple problems installing, but I can work those out and send back some patches).</li><li>Jifty, yet another web app development platform, but this one looks a little less esoteric - not trying do hard to be "Perl on Rails". It installed a lot of interesting-looking prereqs as well; I'm planning on firing up Pos::Webserver::Source and reading a lot next week.</li></ul><p>My presentations both went very well, though I think I may have been a little too high-energy in the Pluggability one, so I may have been off-camera a chunk of the time. Lots of interest in that; I'll need to finish off the final version and get it on CPAN soonest.</p><p>The simple_scan presentation went very well;. the jokes got laughs when they were supposed to, and the stories were well-recieved as well. I had someone come up to me and say that they'd come to my second talk because they'd been told that I was a good speaker, and that they were glad I did. Thanks <i>very</i> much, whoever you are!</p><p>I've spent more time on #perl this year, especially in the time leading up to the conference, and it was really great to meet the people that I did; I was also glad that I had good solid work to refer to this year. I feel like I've come a long way in the past two years.</p><p>Had a great time in the off-hours as well, with good conversation, and sharing MST3K with both old and new (hi, q!) friends.</p><p>More tomorrow. Time for bed.</p> pemungkah 2006-06-30T06:38:34+00:00 yapc Attribute::Handlers and pluggability <p>With chromatic's <a href=""> entry</a> yesterday and a fair amount of experimentation and glob madness, I've finally gotten an elegant way to handle getting rid of the monkey code in my pluggability framework, which will be part of the "Designing for Pluggability" talk at YAPC.</p><blockquote><div><p> <tt>package Vacuum::Plugin::Screamer;<br>use base qw(Plugin::Base);<br>no strict;<br> &nbsp; <br>sub foo<nobr> <wbr></nobr>:PluggedMethod {<br>&nbsp; print "RUNNING!!!!!\n";<br>}<br> &nbsp; <br>sub volume<nobr> <wbr></nobr>:Option(=i);<br>sub vocal_range<nobr> <wbr></nobr>:Slot;<br> &nbsp; <br>1;</tt></p></div> </blockquote><p>Here we have defined a plugin method that will automatically be accessible to the parent (Vacuum::Pluggable), a command-line option definition (with automatic creation of an accessor nethod for it), and a slot to be added to the parent object (with an automatically-generated accessor as well).</p><p>Still to go: prehooks and posthooks, and the generalization of the pluggable base class, but it's all going very well. This is sufficiently advanced technology with a vengeance. Thanks!</p> pemungkah 2006-05-16T22:47:37+00:00 journal Who'da thunk <p>... that this would work?</p><blockquote><div><p> <tt>SKIP: {<br>&nbsp; &nbsp;print "first\n";<br>&nbsp; &nbsp;SKIP: {<br>&nbsp; &nbsp; &nbsp;print "second\n";<br>&nbsp; &nbsp; &nbsp;SKIP: {<br>&nbsp; &nbsp; &nbsp;print "third\n";<br>&nbsp; &nbsp; &nbsp;last SKIP;<br>&nbsp; &nbsp; &nbsp;print "shouldn't print\n";<br>&nbsp; &nbsp; &nbsp;}<br>&nbsp; &nbsp; &nbsp;print "leaving second\n";<br>&nbsp; &nbsp;}<br>&nbsp; &nbsp;print "leaving first\n";<br>}</tt></p></div> </blockquote><p>with output</p><blockquote><div><p> <tt>first<br>second<br>third<br>leaving second<br>leaving first</tt></p></div> </blockquote><p>Not only does it compile, but it works as you'd expect: the <tt>last</tt> leaves only the innermost SKIP block. Or maybe I should say "it works the way I want it to".</p><p>This means that Test::More SKIP blocks can be nested and the Right Thing will happen. Why this matters will be made clear in a module I'll be releasing soon that wraps up Test::More-like retryable tests in a nice syntax.</p> pemungkah 2006-03-06T18:57:23+00:00 journal MakeMaker fun <p>Here at Yahoo! we have a very cool install system, <tt>yinst</tt>; handwaving all the details, it makes it really easy to manage a zillion servers and development machines.</p><p>To use it properly, you need to build packages according to its scheme, which doesn't match a standard CPAN distribution. I found myself repeatedly building the config files for the build, doing the build, transferring to our repository, and yesterday the idea hit me that I shouldn't be doing this; the build <i>process</i> should.</p><p>A quick look over the ExtUtils::MakeMaker docs showed me that it was actually trivial to add a section to the Makefile.PL to put my special build targets into the Makefile.</p><blockquote><div><p> <tt>sub MY::postamble {<br>&nbsp; return &lt;&lt;'MAKE_FRAG';<br>yman: *.3<br>&nbsp; &nbsp; &nbsp; &nbsp; cd build &amp;&amp; pod2man<nobr> <wbr></nobr>../&lt;MAIN PM FILE&gt; &gt; "../man/man3/&lt;MAIN MODULE&gt;.3"<br> &nbsp; <br>yinst: *.yicf<br>&nbsp; &nbsp; &nbsp; &nbsp; cd build &amp;&amp; yinst_create -t release *.yicf<br> &nbsp; <br>ydist: yman yinst *.tgz<br>&nbsp; &nbsp; &nbsp; &nbsp; cd build &amp;&amp; dist_install *.tgz<br> &nbsp; <br>MAKE_FRAG<br>}</tt></p></div> </blockquote><p>So now the Makefile has my targets in it. "Wait, wait," I hear you say. "What's all that stuff in the angle brackets?" That stuff is part 2 of my plan. In addition to the MakeMaker change, I put together a <tt>Module::Starter::Yahoo</tt> module that builds a base distribution modelled on the <tt>Module::Starter::PBP</tt> one, but with the added <tt>build</tt> directory and some extra mojo to build the Yahoo! build files.</p><p>So now I can do this to start up a new module:</p><blockquote><div><p> <tt>module-starter --module=My::New::Module<br>And when my module's ready to distribute, I do this:<br>&lt;ecode&gt;<br>make<br>make test<br>make ydist</tt></p></div> </blockquote><p>and poof, my module is built, tested, and distributed in proper format. And of course, if it's CPAN-able, I can just do a <tt>make dist</tt> instead and then upload to CPAN.</p><p>Since I based it on <tt>Module::Starter::PBP</tt>, I could also use the <tt>Perl -MModule::Starter::Yahoo=setup</tt> business to get this installed as my base <tt>Module::Starter</tt> config.</p><p>I did find that <tt>Module::Starter::PBP</tt> wasn't well set up to be subclassed, which meant I had to cut and paste the <tt>create_distro</tt> method into my code and modify it (it uses hard-coded path components in its <tt>File::Spec</tt> calls), but not a big deal.</p><p>Also, the templating philosohy used in this module is slanted toward "one module, one file" because it's used to build<nobr> <wbr></nobr><tt>.pm</tt> and<nobr> <wbr></nobr><tt>.t</tt> files. I needed to have <i>all</i> of the modules in the<nobr> <wbr></nobr><tt>.yicf</tt> file, so a little fiddling about was necessary there as well. All in all, though, I'm quite happy with the time spent to save time later.</p><p>I still have to edit the prereqs into the<nobr> <wbr></nobr><tt>.yicf</tt> file; possibly I should expand the <tt>make yinst</tt> target to parse <tt>Makefile.PL</tt> and pull the prereqs out automatically.</p> pemungkah 2006-01-26T19:45:26+00:00 journal CPANTS Weakness <p>It does suck when you add another module to CPAN, with everything in place just perfectly except "someone else is using this"<nobr> <wbr></nobr>... and this makes your score drop.</p><p>Sigh.</p> pemungkah 2005-11-21T22:31:25+00:00 journal *gasp* Surfacing <p>Okay, so what I've been doing lately at least a couple of people saw at YAPC:</p><ol> <li>Writing a class that uses <tt>Module::Pluggable</tt> to allow you to build command plugins for the debugger.</li><li>Writing a wrapper class for WWW::Mechanize that allows you to write plugins to add functions to <i>and</i> modify the operation of Mech</li></ol><p>The tricky bit here in both cases is doing it without touching the base code at all. If you're interested in the gory details, see <tt>Devel::Command</tt> and <tt>WWW::Mechanize::Pluggable</tt> on CPAN.</p><p>I'm currently looking at the possibility of extracting all the special-purpose code in <tt>WWW::Mechanize::Pluggable</tt> into a pair of base classes - <tt>Class::Pluggability</tt> and <tt>Class::Pluggability::Plugbase</tt>, so anybody can write a pluggable wrapper for <i>any module whatsoever</i>.</p><p>And this is actually part of my actual job - woo! I'm having fun.</p> pemungkah 2005-08-08T15:40:01+00:00 journal Today's Mech trick <p>There's a batch of really gorgeous images released under the Creative Commons license at; the following code fetches all of them (slowly) at their maximum resolution.</p><p>Max resolution is <b>big</b> - 2 to 8 MB each. These are seriously detailed pictures. I added a 5-minute pause between fetches to be polite.</p><blockquote><div><p> <tt> use strict;<br>use WWW::Mechanize;<br>my $mech = new WWW::Mechanize;<br>my $image_mech = new WWW::Mechanize;<br>my $base = ";file=acanthametra/big%20two%20spike%2<nobr>0<wbr></nobr> star%20copy.png&amp;zoom=0";<br> &nbsp; <br>my $current = $base;<br>$mech-&gt;get($current);<br> &nbsp; <br>while (1) {<br>&nbsp; my ($image) = (($mech-&gt;content) =~<nobr> <wbr></nobr>/img<nobr> <wbr></nobr>.* src="([^"]+)/s);<br>&nbsp; $image=~ s/<nobr> <wbr></nobr>/%20/g;<br>&nbsp; $image_mech-&gt;get("$image");<br>&nbsp; print $image,"\n";<br>&nbsp; my ($dir,$name) = ($image =~ m{^(.*/)(.*)$});<br>&nbsp; system "mkdir -p $dir";<br>&nbsp; open PIX, "&gt;$image" or die "Can't open $image: $!";<br>&nbsp; print PIX $image_mech-&gt;content;<br>&nbsp; close PIX;<br>&nbsp; sleep 300;<br>&nbsp; $mech-&gt;follow_link('text'=&gt;'next');<br>&nbsp; last unless $mech-&gt;success;<br>}</tt></p></div> </blockquote><p>Strictly utilitarian, but it gets the job done, and lets me have truly bizarro desktop graphics, thich is nice. I'm realizing that the 'next' link will probably crap out when it gets to the last page, but that's not a big deal since I want to stop at that point anyway.</p> pemungkah 2005-03-24T00:16:23+00:00 journal Underpinnings <p>Well, I've got a basic command-line peal ringer working. It's stolen shamelessly from the Apple example code; I just pass a peal in from the command line and the code "rings" it via the built-in MIDI synth.</p><p>Minor nits: no ambience. A little reverb would be very classy. Possible to do, but I have to investigate the shipped-with-the-system AudioUnits a bit more to see if there's a really simple way to handle it.</p><p>A few more tweaks and I'll put it together as a<nobr> <wbr></nobr>.pkg file and let people try it out.</p> pemungkah 2005-03-02T16:53:50+00:00 journal From both ends to the middle <p>I've taken a typical Perl programmer approach to the OS X Long Now Chimes program I'm working on: do all the easy stuff first and then do the hard part.</p><p>Deep in the gut the application of course has to make noises. Turns out that the synthesis stuff is actually pretty simple: I can use Apple's provided-with-the-OS sample-playing MIDI synthesis AudioUnit to make noises (and since it's a sample player, making up a new soundbank lets me get away from just plain old General MIDI). I got the sample code working with a (fixed) arbitrary permutation of the chimes with no troble at all. Okay, I had a devil of a time trying to spot why my initializer was bad (one missing comma), but otherwise very easy.</p><p>Switching over to the other end, the user interface, Xcode makes the interface coding and design remarkably simple. I've gotten a nice interface that's almost complete in just a couple of hours of point-and-click.</p><p>Now all I need to do is shake out the interface a bit, hook up a stubbed-out permutation generator to the application, then drive the synthesis with that; we're coming right along.</p><p>When it gets to the permutation generator, I think I'm going to package it up as a C library; that way I can build TAP tests to see if it works (and recycle the ones that Sean has for his LongNowChimes CGI).</p><p>OS X coding is <i>so</i> much simpler than OS 9 and earlier that it isn't funny. It's actually enjoyable.</p> pemungkah 2005-02-25T00:03:42+00:00 journal PerlObjCBridge fun fact <p>From James Duncan's blog:</p><blockquote><div><p>As I wrote before, PerlObjCBridge is available in Mac OS X's system perl to provide a calling bridge between Perl, and Objective-C. It ships also with Foundation, which is Apple's fundamental elements of Cocoa library.</p><p>However, having access to Foundation doesn't buy you very much, but luckily everything you need to be able to load other frameworks is present.</p><p>The trick is using NSBundle to load the frameworks at run time.</p><blockquote><div><p> <tt>&nbsp; my $frameworkPath = NSString-&gt;stringWithCString('/path/to/a/framework');<br>&nbsp; my $framework = NSBundle-&gt;alloc-&gt;init-&gt;initWithPath_($frameworkPath);<br>&nbsp; $framework-&gt;load();</tt></p></div> </blockquote><p>Once this has been done the classes in the framework are available to you, however, you need to perform one last bit of magic to really use them. You need to declare the class in Perl and have it inherit from PerlObjCBridge to have messages passed along.</p><blockquote><div><p> <tt>&nbsp; package NSWhatever;<br> &nbsp; <br>&nbsp; use base qw( PerlObjCBridge );</tt></p></div> </blockquote><p>And hey presto! You should have access to the class you want.</p></div></blockquote><p>I *think* this means I ought to be able to load the necessary Cocoa classes and CoreAudio into Perl, thereby getting a pretty GUI, the synthesis code, and being able to use Sean's chime code without having to change it.</p><p>Copied here so I don't have to look at the comment spam, which makes my eyes bleed.</p> pemungkah 2005-02-23T22:50:08+00:00 journal Descent into weirdness <p>So I've managed to avoid any real C programming until now. Then TorgoX dangles the carrot of "collaboration with Brian Eno" in front of me. Now I'm working on permutation code in C and busily learning Cocoa so I can put a pretty-pretty face on an app to play the Long Now chimes in OS X.</p><p>So far, I've adapted one of Apple's CoreAudio samples to play on particular permutation of the Long Now scale; now I need to translate the permutation algorithm into C.</p><p>Sometimes I can't decide if I'm a programmer who's obsessed with music or a musician who's obssessed with computers.</p> pemungkah 2005-02-23T21:51:51+00:00 journal open <p>I love OS X's <tt>open</tt> command, which FreeBSD doesn't have; it allows me to be lazy on an unprecedented scale.</p><p>So I found Scott Lawrence's version, which was okay as far as it went, but I wanted to add Firefox support for<nobr> <wbr></nobr><tt>.html</tt> files. Unfortunately Scott's version assumed that <tt>cmd args</tt> would work for anything, and <tt>firefox blah.html</tt> doesn't work as expected.</p><p>So the obvious right thing to do was fix his version so it would allow me to do arbitrary callbacks to generate the command string to execute. And since I was in there anyway, I decided to clean up the structure a little.</p><p>So here's a Perl version of <tt>open</tt>:</p><blockquote><div><p> <tt>#!/usr/bin/perl<br>#<br># ''&nbsp; v1.0<br>#<br>#&nbsp; &nbsp;Fri Jan&nbsp; 3 14:36:57 EST 2003<br>#<br>#&nbsp; &nbsp; a simple little script that makes migrating from OS X<br>#&nbsp; &nbsp; back to solaris a little easier.<br>#<br>#&nbsp; it checks each argument with the command "file" and then the<br>#&nbsp; file extension to see if it knows what to do with it.<br>#<br>#&nbsp; Version 1.1<br>#<br>#&nbsp; &nbsp;Mon Jan 24 14:00:00 PST 2005<br>#<br>#&nbsp; &nbsp; Extension to allow callbacks to return a command string.<br>#&nbsp; &nbsp; Tested on FreeBSD. Cleaned up style.<br> &nbsp; <br># the result from running 'file' on the file<br>%filehash =<br>(<br>&nbsp; &nbsp; 'ascii text'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =&gt; ["$ENV{PAGER}"],<br>&nbsp; &nbsp; 'JPEG file'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;=&gt; ['xv'],<br>&nbsp; &nbsp; 'JPG file'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =&gt; ['xv'],<br>&nbsp; &nbsp; 'tiff format image'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;=&gt; ['xv'],<br>&nbsp; &nbsp; 'PBM ascii file'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =&gt; ['xv'],<br>&nbsp; &nbsp; 'PGM ascii file'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =&gt; ['xv'],<br>&nbsp; &nbsp; 'PPM ascii file'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =&gt; ['xv'],<br>&nbsp; &nbsp; 'PBM raw file'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =&gt; ['xv'],<br>&nbsp; &nbsp; 'PGM raw file'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =&gt; ['xv'],<br>&nbsp; &nbsp; 'PPM raw file'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =&gt; ['xv'],<br>&nbsp; &nbsp; 'TIFF file, big-endian'&nbsp; &nbsp; &nbsp;=&gt; ['xv'],<br>&nbsp; &nbsp; 'TIFF file, little-endian'&nbsp; =&gt; ['xv'],<br>&nbsp; &nbsp; 'GIF file, v87'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;=&gt; ['xv'],<br>&nbsp; &nbsp; 'GIF file, v89'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;=&gt; ['xv'],<br>&nbsp; &nbsp; 'IFF ILBM file'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;=&gt; ['xv'],<br>&nbsp; &nbsp; 'PostScript document'&nbsp; &nbsp; &nbsp; &nbsp;=&gt; ['gs'],<br>&nbsp; &nbsp; 'Adobe Portable Document Format (PDF) v1.0'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;=&gt; ['acroread'],<br>&nbsp; &nbsp; 'Adobe Portable Document Format (PDF) v1.1'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;=&gt; ['acroread'],<br>&nbsp; &nbsp; 'Adobe Portable Document Format (PDF) v1.2'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;=&gt; ['acroread'],<br>&nbsp; &nbsp; 'HTML document text'&nbsp; =&gt;<br>&nbsp; &nbsp; &nbsp; &nbsp;['firefox',<br>&nbsp; &nbsp; &nbsp; &nbsp; sub {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;my ($cmd, $arg) = @_;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;my $do = "$cmd file://".<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;($arg =~ m{^/}<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;? ""<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;: `pwd`."/").<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"$arg";<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$do =~ s/\n//;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$do;<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;],<br>);<br> &nbsp; <br># for "text" or "data":<br>%exthash =<br>(<br>&nbsp; &nbsp; 'txt'&nbsp; &nbsp; &nbsp; &nbsp;=&gt; [$ENV{PAGER}],<br>&nbsp; &nbsp; 'pl'&nbsp; &nbsp; &nbsp; &nbsp; =&gt; [$ENV{PAGER}],<br>&nbsp; &nbsp; 'cgi'&nbsp; &nbsp; &nbsp; &nbsp;=&gt; [$ENV{PAGER}],<br>&nbsp; &nbsp; 'mp3'&nbsp; &nbsp; &nbsp; &nbsp;=&gt; ["mpg123"],<br>&nbsp; &nbsp; 'pdf'&nbsp; &nbsp; &nbsp; &nbsp;=&gt; ["acroread"],<br>&nbsp; &nbsp; 'ps'&nbsp; &nbsp; &nbsp; &nbsp; =&gt; ["gs"],<br>);<br> &nbsp; <br>$arg = "";<br>while(@ARG&nbsp; &nbsp; $arg = shift;<br> &nbsp; <br>&nbsp; &nbsp; next if (!-e $arg);<br>&nbsp; &nbsp; next if (-d $arg);<br> &nbsp; <br>&nbsp; &nbsp; # clean up 'file' type<br>&nbsp; &nbsp; $result = `file $arg`;&nbsp; &nbsp; &nbsp; # name:\ttype\n;<br>&nbsp; &nbsp; $type= (split<nobr> <wbr></nobr>/:/, $result)[-1];<br>&nbsp; &nbsp; $type =~ s/^\s+//g;<br>&nbsp; &nbsp; $type =~ s/\s+$//g;<br> &nbsp; <br>&nbsp; &nbsp; # check the file hash<br>&nbsp; &nbsp; if (defined $filehash{$type}) {<br>&nbsp; &nbsp; &nbsp; &nbsp; call(\%filehash, $type, $arg) or sys(\%filehash, $type, $arg);<br>&nbsp; &nbsp; &nbsp; &nbsp; next;<br>&nbsp; &nbsp; }<br> &nbsp; <br>&nbsp; &nbsp; # check the extension hash<br>&nbsp; &nbsp; $extension = (split<nobr> <wbr></nobr>/\./, $arg)[-1];<br>&nbsp; &nbsp; if ( defined $exthash{$extension} ) {<br>&nbsp; &nbsp; &nbsp; &nbsp; call(\%exthash, $type, $arg) or sys(\%filehash, $type, $arg);<br>&nbsp; &nbsp; &nbsp; &nbsp; next;<br>&nbsp; &nbsp; }<br> &nbsp; <br>&nbsp; &nbsp; # lose.<br>&nbsp; &nbsp; print "Unknown type: $arg\n";<br>}<br> &nbsp; <br>sub call {<br>&nbsp; my ($hash, $key, $arg) = @_;<br>&nbsp; my $callback = $hash-&gt;{$key}-&gt;[1];<br>&nbsp; $callback and (system $callback-&gt;($hash-&gt;{$key}-&gt;[0], $arg) or 1);<br>}<br> &nbsp; <br>sub sys {<br>&nbsp; my ($hash, $type, $arg) = @_;<br>&nbsp; system "$hash-&gt;{$type}-&gt;[0] $arg";<br>}</tt></p></div> </blockquote><p>Obviously it could be refactored even further, but this is good enough to work with. An external file holding the extension definitions, or using the system MIME types, is an obvious direction.</p> pemungkah 2005-01-24T22:35:51+00:00 journal <p>My <a href="">other</a> weblog is <a href="">Blosxom</a>-based. I find I don't update it as often as I could/should, mostly because it's a pain to update - log in to the remote server, write the entry, save it<nobr> <wbr></nobr>... it just loses the immediacy for me. I've tried a couple of the Bloxsom plugins to make it easier, but I haven't been happy with any of them.</p><p>I saw <a href=""></a> go by on <a href=""></a> today. It's a little Perl script that parses a mail message and posts it to your Blosxom weblog. Immediately alarms began to go off - the EMUSIC-L weblog isn't exactly <a href="">BoingBoing</a> in terms of traffic, but I could just see my poor little weblog getting spammed up the wazoo. Okay, so there's a password-protection feature. You put the password <i>in the mail</i> and send it. This didn't strike me as a whole lot better - I wanted something that would be easy to do, but hard enough to crack that it really wouldn't be worth it.</p><p>So the following code code does an MD5 hash of the body of the message with a secret string stored on the server. If the hashes match, the post is accepted. At the moment, it still takes a little more work than I'd like: I have to run the message text through an external script and then paste the resultant hash back into the message. What this really wants is a drag-and-drop applet (probably doable with Platypus) or a full-fledged OS X service.</p><p>Anyway, here's<br><i>Update:</i> After seeing <a href="">this</a> happen to someone, I separated the blosmail config directory from the Blosxom data directory. (Yes, I did drop them a note.)</p><blockquote><div><p> <tt>#!/usr/bin/perl -w<br> &nbsp; <br># blosmail<br># Allows you to post (and modify) blosxom entries via email<br># Version 0+1a<br># DJ Adams June 2002<br> &nbsp; <br># See<br># Changes<br># 0+1b fixed secret mechanism<br># 0+1a added -secret parameter<br># 0+1&nbsp; original version<br>#<br># Modified 8-Nov-2004 by Joe McMahon<br># - folded in Doug Alcorn's 'category and title from subject' extension<br># - added security via MD5 hash of content<br> &nbsp; <br>use strict;<br>use File::Path;<br>use File::Temp qw/ tempfile<nobr> <wbr></nobr>/;<br>use FileHandle;<br>use CGI qw/:standard<nobr> <wbr></nobr>:debug/;<br>use Digest::MD5;<br> &nbsp; <br># --- Configurable variables -----<br> &nbsp; <br># Where are my blog entries kept?<br>my $datadir = "/Users/joe/blosxomdata";<br>my $configdir = "/Users/joe/blosmail_config";<br> &nbsp; <br># --------------------------------<br> &nbsp; <br>$datadir = "$datadir/".param('-blog') if param('-blog');<br>my $fh = new FileHandle;<br> &nbsp; <br># Get the list of valid email addresses<br>my @validEmail = $fh-&gt;open("&lt; $configdir/blosmail.dat") ? (&lt;$fh&gt;) : ();<br>chomp @validEmail;<br> &nbsp; <br># Read in whole mail and split into headers and body<br>my ($headers, $body);<br>{<br>&nbsp; local $/ = undef;<br>&nbsp; ($headers, $body) = split("\n\n", &lt;STDIN&gt;, 2);<br>}<br> &nbsp; <br># Check MD5 sums: combine the local copy of the password and the post text<br># and sum them. Should match the sum that appears on the first line.<br>if (param('-sum')) {<br>&nbsp; (my $incoming_sum, $body) = split(/\n/, $body, 2);<br>&nbsp; chomp $incoming_sum;<br>&nbsp; $fh-&gt;open("&lt; $configdir/secret.dat") or die "No local secret\n";<br>&nbsp; my $local_secret = &lt;$fh&gt;;<br>&nbsp; chomp $local_secret;<br>&nbsp; my $ctx = Digest::MD5-&gt;new();<br>&nbsp; $ctx-&gt;add($local_secret.$body);<br>&nbsp; my $local_sum = $ctx-&gt;hexdigest;<br>&nbsp; die "Incorrect checksum" if $local_sum<br>&nbsp; &nbsp;ne $incoming_sum;<br>}<br> &nbsp; <br># Check it's from a valid email address<br>my ($from) = $headers =~<nobr> <wbr></nobr>/^From:\s.*?&lt;([^&gt;]+)&gt;.*?$/m;<br>die "Entry from invalid email address" unless grep(/$from/, @validEmail);<br> &nbsp; <br># Determine filename and write entry<br>my ($category, $title) =<br>&nbsp; &nbsp;($headers =~<nobr> <wbr></nobr>/^Subject:\s+BLOG\/([^\s]*)\s*(.*)$/m)<br>&nbsp; &nbsp; &nbsp; ? ($1, $2)<br>&nbsp; &nbsp; &nbsp; : "";<br>die "No title supplied\n" unless ($title);<br> &nbsp; <br>unless (-d "$datadir/$category") {<br>&nbsp; &nbsp; mkpath ("$datadir/$category", 0, 02775) or<br>&nbsp; &nbsp; &nbsp; &nbsp; die "Can't create '$category' directory, $!\n";<br>}<br>my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);<br>$year +=1900;<br>$mon += 1;<br>my $filename;<br>($fh, $filename) = tempfile("${year}${mon}${mday}XXXXXX", SUFFIX =&gt; ".txt", DIR =&gt; "$datadir/$category", UNLINK =&gt; 0);<br>print $fh $title, "\n";<br>foreach my $line (split<nobr> <wbr></nobr>/\n/, $body) {<br>&nbsp; &nbsp; last if ($line =~<nobr> <wbr></nobr>/^--/);<br>&nbsp; &nbsp; print $fh $line, "\n";<br>}<br>$fh-&gt;close;<br> &nbsp; <br>chmod 0644, "$datadir/$filename";</tt></p></div> </blockquote> pemungkah 2004-11-08T20:51:05+00:00 journal Devel::TestEmbed and S5 <p>I got a request last week to do a lunchtime seminar of Monday on something different related to testing. After a bit of thought, I came up with <a href="">Devel::TestEmbed</a>, which embeds <tt>Test::More</tt> into the debugger so you can dynamically built test suites while debugging.</p><p>That's not so cool by itself, but it also creates a new <tt>tdump</tt> command that lets you dump out the tests you ran during the debugger session as a proper <tt>Test::More</tt> test, with the proper plan. It was almost as interesting developing the tests for the new command as it was implementing it.</p><p>The topper is that this is all done without actually changing any of the debugger's code at all!</p><p>I used the Eric Meyer's new CSS and Javascript-based presentation software, S5. It's way cool. You can get beautiful presentations with everything under really precise control. I've tweaked the existing S5 themes so that they look good on a 12" iBook and they're more useful for someone who wants to do a code-heavy presentation. As soon as I have a little extra time, I'm going to write a pod2s5 converter; S5 makes most presentation tools look silly.</p> pemungkah 2004-10-25T05:38:12+00:00 journal ChucK <p>I've started playing around with <a href="">ChucK</a>, a new language for music composition and performance.</p><p>ChucK has a lot of the things I've always wanted in a music language: it does not require you to link up little boxes to write programs; it does not require you to effectively program in a horrible assembly language because that was good enough in 1968; it does not require you to jump though hoops to figure out how to get multiple intependent processes working.</p><p>It primarily uses a single operator, <tt>=&gt; </tt> (known as "chuck"), which does all of the heavy lifting re datatype conversions, etc.<br>Here's an example. Let's say you were going to pass a white noise source through an ADSR (attack-decay-sustain-release), filter it, and then output it through a digital-to-audio converter, all under MIDI control.</p><p>In C-like, code this would look something like</p><blockquote><div><p><nobr> <wbr></nobr><tt>/* Advance the time */<br>dacOut.tick(biQuad.tick(adsr.tick() * noise.tick()));<br>if( timeCount % 44 == 0 ) {<br>&nbsp; &nbsp;/* Time to look for a MIDI message */<br>&nbsp; &nbsp; if( midi.nextMessage() == __SK_NoteOn_ ) {<br>&nbsp; &nbsp; &nbsp; &nbsp;<nobr> <wbr></nobr>/* Byte 3 non-zero: note-on, zero: note off */<br>&nbsp; &nbsp; &nbsp; &nbsp; (midi.getByteThree() ? adsr.noteOn() : adsr.noteOff());<br>&nbsp; &nbsp; &nbsp; &nbsp;<nobr> <wbr></nobr>/* Set the filter from the velocity */<br>&nbsp; &nbsp; &nbsp; &nbsp; biQuad.setFreq( MD2Freq(midi.getByteTwo()) );<br>&nbsp; &nbsp; }<br>}</tt></p></div> </blockquote><p>In <a href="">csound</a>, you'd decide it wasn't worth the trouble. In ChucK, this is simply</p><blockquote><div><p> <tt>noise3 =&gt; ADSR =&gt; biquad1 =&gt; dac;<br>midi =&gt; (ADSR, biquad1);</tt></p></div> </blockquote><p>No messing with what byte does what in the MIDI message, no having to run the idle timing loop. It just works. The ChucK operator takes care of all the conversion and the individual units use whatever they can.</p><p>In the spirit of reasonable languages (like Perl), ChucK lets you decide waht you want to deal with. Durations and time are native datatypes: units run from <tt>samp</tt> (the length of a single sample, or 1/44K second) to <tt>week</tt>. Artihmetic is supported:</p><blockquote><div><p> <tt>3:second + 100:ms =&gt; dur quarter;</tt></p></div> </blockquote><p>This defines the duration of a quarter-note as 3.1 seconds. Time is dealt with by chucking a new duration into <tt>now</tt>; you can also (as shown above) allow external events, like incoming MIDI messages, to advance time for you.</p><p>These two aspects, dealing with time and setting up flows of data, are the things that are most problematic for me in trying to use so-called "music languages".</p><p>ChucK also has a built-in concurrency model called <i>shreds</i> which is possibly of interest to other programming languages. Shreds are unlike threads in that threads are not deterministic and have no timing guarantees; shreds are guaranteed to be deterministic and allow synchronization down to the sample.</p><p>Shreds work because the advancement of time happens when the <i>program</i> says time advances. This means that the ChucK core can always know when a shred is supposed to do whatever it is planning on doing and schedule it deterministically.</p><p>As if this wasn't all cool enough, the Chuck core can add and delete shreds dynamically; so you can do something like this:</p><blockquote><div><p> <tt>bash $ sudo nice -20 chuck --loop<br>bash $ chuck +<br>[chuck](VM): sporking incoming shred: 1 (<br>bash $ chuck +<br>[chuck](VM): sporking incoming shred: 2 (<br>... (add a pile more shreds)<br>bash $ chuck - 1<br>[chuck](VM): removing shred: 1 (<br>bash $</tt></p></div> </blockquote><p>You can start and kill shreds at will; If they're all advancing time at the same rate, the beat lines up and it sounds<nobr> <wbr></nobr>... pretty cool. Chuck calls this "on-the-fly" programming; very similar to the <a href="">Hacking Perl in Nightclubs</a> folks. It might be very interesting to try writing some Perl code that emitted ChucK code instead of MIDI directly. Heck, it sould even <tt>system</tt> the shreds randomly, letting the shreduler handle the synchronization.</p><p>Anyway, it's way cool. I have a little free-running ChucK program which simulates a Fender Rhodes noodling away in the background as I type this; it even runs nicely on my Powerbook G4 with a fair bit of other stuff going on.</p> pemungkah 2004-10-19T16:31:27+00:00 journal GraphViz::Data::Structure 0.10 - hacks away! <p>I've released yet another version of GraphViz::Data::Structure today.</p><p>This one looks for the problem that GraphViz 2.0 has and substitutes its own patched version of the code in question if the test fails.</p><p>Obviously, I'm going to need to check out Leon's new record support (which I already think has a similar bug) and write some tests to complete the patch I sent him.</p> pemungkah 2004-09-24T16:36:43+00:00 journal GraphViz::Data::Structure Two new versions in two days. Thanks to <a href="">Devel::Cover</a> pointing out where I hadn't tested adequately, I was able to find a number of bugs that my first set of tests missed. <p> The new version seems to work fine on OS X and on Linux, but there were some odd errors on Solaris. Anyone have a Solaris machine they'd be willing to try it out on and see if they can point out the bug? </p><p> <i>Update:</i> It's a bug in the 2.0 version of <a href="">GraphViz</a> itself; I'm still running with version 1.8, which doesn't have the bug. Patch appended for your dining and dancing pleasure:</p><blockquote><div><p> <tt>---<nobr> <wbr></nobr>/usr/local/lib/perl5/site_perl/5.8.3/; &nbsp; Wed Sep 22 15:56:22 2004<br>+++ Wed Sep 22 15:55:46 2004<br>@@ -408,7 +408,7 @@<br>&nbsp; &nbsp; &nbsp; &nbsp;$node-&gt;{label} = $node-&gt;{name};<br>&nbsp; &nbsp; &nbsp;}<br>&nbsp; &nbsp;} else {<br>-&nbsp; &nbsp; $node-&gt;{label} =~ s#([|&lt;&gt;\[\]{}"])#\\$1#g;<br>+&nbsp; &nbsp;$node-&gt;{label} =~ s#([|&lt;&gt;\[\]{}"])#\\$1#g unless $node-&gt;{shape} eq 'record';<br>&nbsp; &nbsp;}<br> <br>&nbsp; &nbsp;delete $node-&gt;{cluster}</tt></p></div> </blockquote><p>The patch turns off the newly-added escaping of characters that <tt>dot</tt> treats as special. Since record shapes need these special characters, escapling them gives you nice oval nodes with names like <tt>&lt;port1&gt;1|&lt;port2&gt;2</tt>, and of course edges that are supposed to hook to those ports can't find them.</p> pemungkah 2004-09-22T14:25:48+00:00 journal Brain. Hurts. <p><a href="">COBOLScript</a>.</p><p>Just when you thought it couldn't get any worse than Visual BASIC...</p> pemungkah 2004-08-19T18:14:56+00:00 journal iFire+Pro Speakers = cheap stereo bliss <p>I really like the <a href="">Apple Pro Speakers</a>. For a pair of small, portable speakers they're hard to beat in terms of clear, clean reproduction. And they're cheap. You can <a href="">find a demo set</a> for $29! Okay, the bass response is so-so, but they beat the heck out of most 2.0 speakers, and they really are cheap. For me, they beat the <a href="">Bose Mediamates</a> in a head-to-head comparison, and the Boses cost $100.</p><p>"But, Joe," you say. "I don't have a flat screen iMac or a G4 or G5 tower with the funny plug and built-in amp to drive these. I can't use these speakers." Enter the <a href="">Griffin iFire</a>. This little beastie incorporates the small (10-watt) amp needed to drive the Apple Pro Speakers. it just needs Firewire power. So you can hook it up to any Firewire-equipped Mac or PC: plug the iFire into the headphone jack, and the Apple Pro speakers in to the iFire and voila - you're golden.</p><p>"But, Joe," you say."I don't even have a Firewire port." Okay, then get yourself an iPod power supply ($45). Add the portable music source of your choice, and you've got an impressive little setup that takes up <i>very</i> little space. I'm currently using one set of speakers plus the iFire and iPod charger with my old portable CD player to provide a nice little system in the room where we do yoga.</p><p>We'll probably pick up another one of these for the other room because they really are a good deal for the price. And before all the audiophiles pronounce me tin-eared, we use the Creative Labs <a href=";subcategory=27&amp;product=139">I-Trigue 3300s</a> for the primary system when we really want to listen to the music.</p> pemungkah 2004-07-25T04:40:04+00:00 journal "What's Wrong With Perl" <p></p><p>I read this and started to write a pissed-off journal article about it. Then I thought for a bit and realized that <i>it doesn't matter</i>.</p><p>I don't need to fight for Perl. I need to write it. Python isn't better. Perl isn't better. Perl is better <i>for me personally</i> because I can think in it. I can do things in it that can't easily be done in Python - as far as I know.</p><p>I have a job to do. It's writing code. It isn't to crab at people who don't like Perl. They can waste their energy on saying it sucks. They're not writing code while doing that.</p><p>Who is spending time better?</p> pemungkah 2004-04-06T16:15:52+00:00 journal Sting <p>I attended the Sting concert Thursday night. Third row seat, in a small theater. Maybe ten feet to the band.</p><p>God in Heaven, what a concert. If you've got a chance to see him this tour, do it.</p><p>The first half hour was a solid, heartfelt performance, but then the energy suddenly swung up and <i>up</i> and <i>UP</i>... Two hours later, and two encores it was over; possibly the most intense musical experience I've ever witnessed. The band was on <i>fire</i>.</p><p>And, to bring it back to computers, I noticed the 17" Powerbook that was a prominent part of the setup - not only the select tool of alpha geeks, but of alpha musicians...</p> pemungkah 2004-03-15T18:53:28+00:00 journal Not enough Jerkcity? Write your own <p></p><p>Enjoy.</p> pemungkah 2004-02-18T14:18:06+00:00 journal "I think it should be bright orange." <p>Today's <a href="">Goats</a> reminded me <i>so</i> of the infamous orange auction.</p> pemungkah 2003-08-27T16:10:17+00:00 journal