samtregar's Journal samtregar'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:03:40+00:00 pudge Technology hourly 1 1970-01-01T00:00+00:00 samtregar's Journal Making Maps with Math::Geometry::Voronoi I've been working with generating overlays for google maps lately at my day job. Without going into too much detail, the data set I need to display is a set of points, each assigned to a given set. In the real world these sets form contiguous regions which I need to translate into shapes to draw over the map. The rub is that these regions come in really complex shapes - drawing convex hulls isn't an option. <p> My first attempt at the problem once I realized I couldn't draw a hull was to divide the world into a grid and color each box according to what I found inside, subdividing until each box contained only a single set's point(s). The results were blocky (duh) and not all that appealing. But as long as the data was dense enough (i.e. urban areas) it did a decent job of expressing the shapes. Unfortunately in rural areas where points are more spread out it looked terrible. </p><p> For my second attempt I decided to actually learn some computational geometry - I read a book and quite a few sites around the web. This lead me to <a href="">Voronoi diagrams</a>. There's a wide variety of Voronoi diagram producing code out there on the web - everything from highly-templated C++ monsters to Java to some excellent 20-year old C code. I chose the latter of course (Perl and old-school C go together like chocolate and peanut butter), and after some serious debugging I give you <a href="">Math::Geometry::Voronoi</a>. </p><p> <b>You can see a demo of it in action here: <a href=""></a>.</b> This is essentially what I'm doing with Google maps, except that I'm coloring multiple regions the same color and drawing a line around the border rather than each cell. </p><p> The speed of the diagramming code is really good. Don't let the demo fool you - that code is running in CGI mode on a shared server. Put it on a fast mod_perl server and it's definitely not going to be the bottleneck in a mapping application. That prize goes to Google Maps. Sweet app, but it sure is slow! </p><p> -sam</p> samtregar 2008-06-22T19:22:07+00:00 journal VMWare's Jerky Mouse This isn't the least bit Perl related, but I figured this was an easy way to get some useful info out to Google. I searched in vain for a solution and managed to hit it only by accident. Maybe I can save someone else the trouble. <p> In short, I installed Fedora 8 as a guest in VMWare running on Windows XP. Everything was fine but the mouse movement was jerky. Not jerky like a video performance problem, but more like wiggly and jittery. It looked a little like my hand was shaking on the mouse, but I was calm as can be. </p><p> Reading through the logs, I realized that X had somehow detected my mouse twice. I guess it was getting conficting signals from each movement. I fixed it by opening<nobr> <wbr></nobr>/etc/X11/xorg.conf and commenting out the entire mouse configuration section and the reference to the mouse config in the screen section. I restart X and my mouse was auto-detected fine. </p><p> Most of the advice I could find on the topic of funky mouse movement in VMWare advises you to install VMWare tools. Don't bother - it won't work under Fedora 8 and you'll waste a lot of time trying. You don't need it anyway - Fedora 8 comes with working VMWare display and mouse drivers. </p><p> -sam</p> samtregar 2008-04-23T23:15:04+00:00 journal Sharing a DBI handle between Class::DBI and Rose::DB::Object At my current job we've got a large existing code-base built on Class::DBI. For my current project I decided to experiment with using Rose::DB::Object instead, hoping to see less need for hand-written SQL. So far it's been a success, but one issue was quite difficult to get right - getting the two systems to share a DBI handle. If I didn't do this then I was going to see a doubling of total DBI connections when I deployed my new app to the web cluster, which is unacceptable. <p> I started with the most obvious solution, an over-ridden init_db() in my Rose::DB::Object subclass: </p><blockquote><div><p> <tt>sub init_db {<br>&nbsp; &nbsp; my ($pkg, @args) = @_;<br> <br>&nbsp; &nbsp; My::Rose::DB-&gt;new_or_cached(dbh =&gt; My::Class::DBI-&gt;db_Main(), @args);<br>}</tt></p></div> </blockquote><p> That worked great at first - when Rose needs a DB connection it gets one pre-loaded with my Class::DBI handle. (And as a side-note, the fact that the Class::DBI handle uses DBIx::ContextualFetch doesn't cause Rose problems.) </p><p> However, sometimes for unknown reasons Rose will decide it needs to reconnect after the initial connection is established. To intercept these calls I added an overridden dbh() method to my Rose::DB sub-class: </p><blockquote><div><p> <tt>sub dbh {<br>&nbsp; &nbsp; my $self = shift;<br>&nbsp; &nbsp; unless (@_) {<br>&nbsp; &nbsp; &nbsp; &nbsp; $self-&gt;{dbh} ||= My::Class::DBI-&gt;db_Main();<br>&nbsp; &nbsp; }<br>&nbsp; &nbsp; return $self-&gt;SUPER::dbh(@_);<br>}</tt></p></div> </blockquote><p> Another useful hint which helped me notice very quickly when Rose decided to reconnect - I gave Rose::DB an invalid password in my call to register_db. That way Rose would have all the correct information about the connection, but wouldn't be able to initiate new connections. </p><p> I hope this helps other suffering Class::DBI users to give Rose a try! </p><p> -sam</p> samtregar 2008-04-03T20:12:31+00:00 journal HTML::FIllInForm patch to mark invalid fields I've been working on producing yet another form validation system, this time for MasonX::WebApp. I modeled my work on the very nice CGI::Application::Plugin::ValidateRM, with a bit of the Krang::Message system thrown in to help get errors out to the user. <p> One thing I wanted to do this time that I'd never done before was automate marking invalid form fields. I'd done this in the past using manual template changes, but that's a lot of grunt work. </p><p> Instead, my coworker Perrin Harkins suggested we use HTML::FillInForm to do the job. We're already using it to re-fill forms with errors, so why not use it to setup a CSS class on invalid fields too. It turns out HTML::FillInForm has a very similar facility already to disable selected fields, so adding an invalid fields feature was pretty simple. </p><p> I've already sent along the patch to the maintainer, but if you want to get it now here it is: </p><blockquote><div><p> <a href="">fillinform_invalid2.diff</a></p></div> </blockquote><p> -sam</p> samtregar 2007-12-03T19:57:21+00:00 journal Get your Geo::Coder::US DB file here! <p> I've put up a freshly built <a href="">Geo::Coder::US</a> DB file for download here: </p><blockquote><div><p> <a href=""></a></p></div> </blockquote><p> It's 384MB compressed (845MB uncompressed), but believe me, you'd much rather download this than download the 6.6GB of <a href="">TIGER/Line source files</a> needed to build it! </p><p> Supposedly I've got 6TB of downstream bandwidth each month at my ISP (<a href="">Dreamhost</a>). I guess we'll see if they meant it! I should hook up something to take down the file automatically if I go over my limit... </p><p> -sam </p> samtregar 2007-07-06T20:19:53+00:00 journal Review of Programming Erlang, the short version <p> In short, <a href="">fantastic book</a>, absolutely recommended to any progammer interested in learning about a fascinating and very novel progamming language. It's very well written and I was engaged from start to finish. </p><p> I think it may be of particular interest to Perl programmers because Erlang offers a great solution to a problem which is very hard to tackle in Perl - reliable, simple paralell processing. I'm definitely excited to use Erlang in the future - I've already got ideas for more projects than I could possibly find time to complete. I think its utility will only grow as processors continue to add more cores. </p><p> As a side note, I read the book as a beta PDF, which I enjoyed a lot more than I thought I would. It was very convenient to be able to cut-and-paste code from the book into a running Erlang interpreter to see it work. I got several updated versions of the book as I was reading, but the changes weren't too disruptive. </p><p> I may write a longer review, perhaps after I've written a moderate amount of Erlang so I can get a sense for what was left out. But don't wait for that - buy it now and thank me later! </p><p> -sam</p> samtregar 2007-04-26T18:46:01+00:00 journal Article about Data Warehousing with MySQL and Perl An article I wrote about building a data warehouse with Perl and MySQL just went up on O'Reilly's database site:<blockquote><div><p> <a href=""><nobr>w<wbr></nobr> ith-mysql-and-perl.html</a></p></div> </blockquote><p> I'd intended it for <a href=""></a>, but as the editor correctly pointed out it doesn't have a lot of Perl content. Take a look and let me know what you think (|grep -v 'mysql hate'). </p><p> -sam</p> samtregar 2007-04-20T19:18:52+00:00 journal Decoding another bash error <p> Again I've been confused by a bash error message. And again, Google was little help, so I figured I'd post it here so perhaps others won't search in vain. </p><p> Here's the error, encountered trying to run a Perl script on a USB drive from my Fedora Core 5 machine: </p><blockquote><div><p> <tt>$ bin/krang_ctl restart<br>-bash: bin/krang_ctl:<nobr> <wbr></nobr>/usr/bin/perl: bad interpreter: Permission denied</tt></p></div> </blockquote><p> The "bad interpreter" part led me on a mission to make sure Perl was installed ok. It was, and scripts in other locations ran fine. Then I spent some time investigating the "Permission defined" angle, but I couldn't find a permissions problem anywhere. </p><p> Finally I looked at how the USB disk was mounted and there it was: </p><blockquote><div><p> <tt># grep Cube<nobr> <wbr></nobr>/etc/mtab<br>/dev/sda1<nobr> <wbr></nobr>/media/Cube ext3 rw,nosuid,noexec,nodev 0 0</tt></p></div> </blockquote><p> Note the "noexec" there! Fedora auto-mounted this disk with "noexec" turned on. I still don't know how to tell Fedora not to do that, but I do know how to fix it after the fact: </p><blockquote><div><p> <tt># mount<nobr> <wbr></nobr>/media/Cube/ -o remount,exec</tt></p></div> </blockquote><p> After that the problem went away. How the heck having "noexec" on a mounted filesystem triggers a "bad interpreter" error in bash, I have no idea... </p><p> Hope that helps someone! </p><p> -sam</p> samtregar 2006-12-08T18:52:36+00:00 journal Mac line-endings and Text::CSV_XS <p> To say that <a href="">Text::CSV_XS</a> has trouble with Mac line-endings (\015) is somewhat of an understatement. Not only will it not parse a file that uses them to end lines, it won't even allow them inside a field in binary-mode. Binary-mode is advertised as allowing any character as long as it's in a quoted string, so this is clearly (in my opinion) a bug. </p><p> I dug into the code intending to solve both problems, but only managed to fix the latter. Actually supporting \015 as a line-ending character looks like it would be hard. For my purposes it wouldn't help unless it was automatic - if I have to tell Text::CSV_XS that a file has Mac line-endings then I might as well just translate them. That's the way Unix and Windows line-endings work now - you don't have to tell the module what to expect and you can even mix them in a single file. The way it accomplishes this feat doesn't extend well though, at least as far as I can tell. </p><p> In any case, here's the bug fix: <a href="">mac.diff</a>. After you apply it you should find that stray \015 characters work just fine in binary mode. I also sent it to the maintainer, but since the module hasn't had a release in 5 years I'm not exactly holding my breath! </p><p> I came very close to going on an optimization mission while I was in the code. The state machine looks like it could benefit from some tweaking and the way lines are read looks like it could be improved. This would be pretty foolish though - Text::CSV_XS is already so fast that I've never seen it show up in a profile on a serious app. Usually I'm reading CSVs so I can load data into a database via DBI, by which point Text::CSV_XS is unlikely to be a bottleneck. </p><p> -sam</p> samtregar 2006-10-29T22:44:29+00:00 journal Safely timeout DBI with DBIx::Timeout Recently I needed to find a way to timeout a DBI request. I found the state of the art less than satisfying, involving unsafe signals and a chance of memory corruption deep in Perl's guts:<blockquote><div><p> <a href=""><nobr>s<wbr></nobr> </a></p></div> </blockquote><p> This led me to create <a href="">DBIx::Timeout</a> which instead of using unsafe signals: </p><blockquote><div><p> <tt>&nbsp; - Forks a child process which sleeps for $timeout seconds.<br> <br>&nbsp; - Runs your long-running query in the parent process.<br> <br>&nbsp; - If the parent process finishes first it kills the child and<br>&nbsp; &nbsp; returns.<br> <br>&nbsp; - If the child process wakes up it kills the parent's DB thread and<br>&nbsp; &nbsp; exits with a code so the parent knows it was timed out.</tt></p></div> </blockquote><p> Tim Bunce suggested a possible optimization - fork just one child process and have it watch any number of slow queries simultaneously. It would accept assignments via a pipe interface. Seems like a good idea, although it's likely overkill for my usage. The queries I need to timeout are very likely to be long-running, and when they're not don't need to be very fast. The overhead of forking a process that exits almost immediately won't cause any problems, I'm betting. </p><p> So, please give it a try! And if you're not a MySQL user, please port it to your DB and send me a patch. It should be an easy job - all you have to do is implement a call to kill another process in the DB (MySQL does it with "KILL $thread_id"). (<b>UPDATE:</b> actually, it's a little more work - you also need to write new tests. The tests I wrote for MySQL use GET_LOCK() to test timeouts - you'll need to do something analgous for your DB.) </p><p> -sam </p><p> PS: I should note that the mechanism this module uses was suggested by my co-worker <a href="">Perrin Harkins</a>. I'll add that to the module's POD for the next release.</p> samtregar 2006-09-17T19:28:29+00:00 journal Using Perltidy with Emacs I noticed this on the CPAN radar today:<blockquote><div><p> <a href="">perl-tidy-mode</a></p></div> </blockquote><p> From the docs it sounds like it runs perltidy when you save your file. That doesn't sound terrible, but I like my solution better. I have bindings so I can run perltidy on-demand, either on the whole file or on a particular region. Check it: </p><blockquote><div><p> <tt>(defun perltidy-region ()<br>&nbsp; &nbsp; "Run perltidy on the current region."<br>&nbsp; &nbsp; (interactive)<br>&nbsp; &nbsp; (save-excursion<br>&nbsp; &nbsp; &nbsp; (shell-command-on-region (point) (mark) "perltidy -q" nil t)<br>&nbsp; &nbsp; &nbsp; (cperl-mode)))<br> <br>(defun perltidy-all ()<br>&nbsp; &nbsp; "Run perltidy on the current region."<br>&nbsp; &nbsp; (interactive)<br>&nbsp; &nbsp; (let ((p (point)))<br>&nbsp; &nbsp; &nbsp; (save-excursion<br>&nbsp; &nbsp; &nbsp; &nbsp; (shell-command-on-region (point-min) (point-max) "perltidy -q" nil t)<br>&nbsp; &nbsp; &nbsp; &nbsp; )<br>&nbsp; &nbsp; &nbsp; (goto-char p)<br>&nbsp; &nbsp; &nbsp; (cperl-mode)))<br> <br>(global-set-key "\M-t" `perltidy-region)<br>(global-set-key "\M-T" `perltidy-all)</tt></p></div> </blockquote><p> -sam</p> samtregar 2006-07-05T20:48:18+00:00 journal Procmail has a strange way of saying "file not found" When I'm faced with a bizarre error message the first thing I do is search for it on the web. Chances are I'm not the first one to see it and someone else has probably already taken the time to explain it. That didn't work today with this one, offered up by procmail as an excuse for not running SpamAssassin:<blockquote><div><p><nobr> <wbr></nobr><tt>/home/stregar/bin/spamc: Transport endpoint is not connected<br>procmail: Program failure (126) of "/home/stregar/bin/spamc"</tt></p></div> </blockquote><p> That's coming from a call to SpamAssassin's spamc client program, but the same error happened with any pipe call in my<nobr> <wbr></nobr>.procmailrc. I spent a long time distracted by the "Transport endpoint" business. It just sounds so authoritative and networky. But as far as I could tell the network was completely normal. </p><p> Finally I turned to the next line with it's enigmatic magic number 126. Turns out that's a return code from the shell call to run the pipe. And 126 is bash for "file not found." It all came together when I realized that $HOME on the mail-recieving host was no longer<nobr> <wbr></nobr>/home/stregar! As soon as I switched to using $HOME instead of hard-coding the path everything started working. </p><p> So, google, if you would be so kind, please index this report so that others may not have to stumble around for quite so long. </p><p> -sam</p> samtregar 2006-04-11T04:09:34+00:00 journal DateTime-&gt;now() versus localtime() What's wrong with this picture:<blockquote><div><p> <tt>&nbsp; &nbsp;$ perl -MDateTime -e 'print DateTime-&gt;now()'<br>&nbsp; &nbsp;2006-04-04T23:08:37<br> <br>&nbsp; &nbsp;$ perl -e 'print scalar localtime'<br>&nbsp; &nbsp;Tue Apr&nbsp; 4 19:09:10 2006</tt></p></div> </blockquote><p> It seems that DateTime-&gt;now() doesn't do what I thought it did. I thought it returned the current date and time at this point on the planet. What it actually does is return the current date and time in UTC! (And please don't tell me that DateTime can't reliably figure out my timezone. Perl's localtime() manages just fine!) (You can, however, lambaste me for not reading the DateTime docs, since it's quite clear that now() doesn't return local time.) </p><p> Unfortunately I discovered this only in the late stages of testing version 3 of a large application that makes moderately extensive use of Datetime. That means the "easy" way to fix this, namely: </p><blockquote><div><p> <tt>&nbsp; &nbsp; $ perl -MDateTime -e 'print DateTime-&gt;now(time_zone =&gt; "local")'<br>&nbsp; &nbsp; 2006-04-04T19:12:03</tt></p></div> </blockquote><p> Isn't so easy, as it would mean touching a lot of files. </p><p> As far as I can tell I don't have a lot of good options here. I'm going to make a sub-class of DateTime which defaults to "local" for now(), new() and from_epoch(), but that will still mean touching lots of files. I did find <a href=";r=1&amp;w=2">discussion of this problem on the DateTime lists</a>, but I don't think a solution made it into the module. </p><p> I did discover that <a href=";m=108877037725879&amp;w=2">Tim Bunce considers my chosen solution "trivial"</a>, whatever that means! </p><p> -sam</p> samtregar 2006-04-04T23:18:07+00:00 journal Why your code might break on Fedora Core 5 I'm sure there are other reasons, but this one struck me as rather aggregious:<blockquote><div><p> <tt>&nbsp; &nbsp;$ export FOO=bar<br>&nbsp; &nbsp;$ echo $FOO<br>&nbsp; &nbsp;bar<br>&nbsp; &nbsp;$ sudo bash -c 'echo $FOO'<br> <br>&nbsp; &nbsp;$</tt></p></div> </blockquote><p> That's right, sudo no longer passes through environment variables by default. I don't know about you, but this seems quite likely to bite lots of code I write. I often do environment setup (PERL5LIB, PATH, directory roots, etc) and then run a sub-process as another user via sudo. I'm expecting a flood of reports of problems from DBD::Oracle users as they find that ORA_HOME mysteriously stopped working when the upgrade to FC5. </p><p> The fix is easy, just undo the change discussed here: </p><blockquote><div><p> <a href=""></a></p></div> </blockquote><p> I like Josh Bresser's comment about this change: </p><blockquote><div><p> <i>as long as there is a release note about it, it will only surprise the people who don't read the release notes</i></p></div> </blockquote><p> I guess that's true. Only problem is, it wasn't put in the release notes! </p><p> -sam </p><p> PS: Shout out to <a href="">Michael Peters</a> for tracking this one down.</p> samtregar 2006-03-23T22:39:41+00:00 journal Putting MIME::Lite on a diet <p> There's nothing quite like some justified optimization to get the heart pumping. I've been working on a system which needs to produce multipart MIME messages very quickly. It's using <a href="">MIME::Lite</a>, which, it turns out, isn't actually all that lite. After solving the other bottlenecks in my code I was left with around 30% of my processing time locked-up in MIME::Lite's code. </p><p> My first stop was <a href="">MIME::Fast</a>. It certainly is fast, but unfortunately it also has some large memory leaks. Running at full speed it was losing around 5MB per second! I spent a few hours confirming that the leaks are somewhere in the huge XS codebase of MIME::Fast and not in the underlying gmime library. I gave up and filed a bug with the author. </p><p> That left me back with MIME::Lite, so I decided to see if I could speed it up. After a few hours of work I've come up with a patch which offers a 50% speedup for my use-case (creating two-part messages from parts in memory). For the curious, here's my work-log: </p><ul> <li>Starting work =&gt; MIME::Lite is building messages at 750/s</li><li>Use direct hash access for Attrs =&gt; 900/s</li><li>Change how Attrs are stored, moved sub-attrs into a separate structure. This avoids the {''} access for the vastly more common case of attribs without sub-attribs. =&gt; 980/s</li><li>Did some work optimizing fields() which is a hot method. =&gt; 1046/s</li><li>Tightened-up fields_as_string a bit. Might be worth making the pretty-printing optional if the spec doesn't require it. =&gt; 1057/s</li><li> Started testing with more realistic part sizes, new base =&gt; 910/s</li><li> inlined the popular routine known_types() =&gt; 930/s</li><li>Played with speeding up IO_* to little effect. Removing the wrap() indirection entirely would no-doubt help but it's a big project.</li></ul><p> I sent the patch to the MIME::Lite maintainer, so hopefully this code will be available to all someday soon. </p><p> -sam</p> samtregar 2005-12-03T22:35:58+00:00 journal AJAX comes to HTML::PopupTreeSelect <p> I released <a href="">HTML::PopupTreeSelect::Dynamic</a> yesterday, a dynamic AJAXified version of <a href="">HTML::PopupTreeSelect</a>. Instead of sending the entire tree to the client when the page loads, the new dynamic version renders the tree on-demand, retrieving nodes via AJAX requests. The result is a widget that can browse arbitrarily large trees without imposing long initial page-load times. </p><p> This was a learning experience for me - I'd never used <a href="">the Prototype library</a> before. Now I'm wishing I'd encountered it earlier - it would have made a number of Javascript-intensive projects much easier. I also got a chance to play with <a href="">HTML::Prototype</a>, which makes using the Prototype library from Perl a breeze. </p><p> All this learning will hopefully help me in the near future. I'm planning a much more involved DHTML/AJAX application as part of the continued development of <a href="">Arcos</a> at <a href="">Plus Three</a>. </p><p>-sam</p> samtregar 2005-08-30T17:39:07+00:00 journal It's all about the names <p> Working on <a href="">MKDoc</a> can be hard. It's a great system in many ways but every so often I get completely lost. I'm starting to think that fundamentally it's a naming problem. For example, consider the word "editor." MKDoc uses "editor" to mean four different things: </p><ol> <li>The table which holds all users is called Editor.</li><li>A user is considered an "editor" if they have editing rights to at least one document.</li><li>The code that controls the part of the UI where users edit content is called an "editor." The base class is flo::Component but all the sub-classes live in flo/editor.</li><li>The code that allows a document to be loaded and saved to the database lives in flo::Editor. This one is the hardest to characterize - it's probably implementing a design-pattern I don't know. Maybe the "editor" pattern? God, I hope so.</li></ol><p> All this means that when you see a variables called $editor in MKDoc you really have no idea what you're dealing with. It could be a user, a specific type of user, a UI editor or an abstract encapsulation of the act of editing a document. That's hard. </p><p> So please, people, get your names right from the start. And if you can't get them right at least be consistent and careful. Having even two things named the same is bad. Having four is like declaring war on maintainance programmers. </p><p> -sam</p> samtregar 2005-08-07T22:40:50+00:00 journal Progress on CGI::Application::Plugin::DBIProfiler I've made some progress on a new module this weekend - CGI::Application::Plugin::DBIProfiler. Check it out:<blockquote><div><p> <a href=""></a></p></div> </blockquote><p> That's the screen that pops up when you access a runmode of a CGI::App using the module. It shows profiling data for all DBI usage triggered by the request. </p><p> Of course, if it was done I'd be releasing it. I need to figure out why I'm getting bogus statement-less profile nodes (might be the fault of my test app rather than DBI::Profile). I also need to test it with a persistent DB handle between requests. I think I might need to make a patch to DBI::ProfileDumper to get that working right. </p><p> I'll also need to wait for CGI::Application v4.0 to release the module since it uses the new callback interface. </p><p> -sam</p> samtregar 2005-06-06T04:16:00+00:00 journal Data::Phrasebook::Loader::ApacheFormat v1.00 Released A few days ago I released the first version of Data::Phrasebook::Loader::ApacheFormat. If it's not completely obvious, this module will let you use phrasebooks in Config::ApacheFormat syntax.<blockquote><div><p> <a href=""></a></p></div> </blockquote><p> I'm in the design stages for another module which will leverage this one - basically a CPAN version of the Krang::Message user-alerting system. More on that later. </p><p> -sam</p> samtregar 2005-06-02T15:12:12+00:00 journal Let's work together We're looking for an elite Perl coder in New York to join our team at Plus Three. Check it out:<blockquote><div><p> <a href=""></a></p></div> </blockquote><p> Speaking personally, I highly recommend you apply for this job immediately if you live in New York, love coding in Perl and would like to see the Democrats regain control of America. I've been loving my time at Plus Three and I'm sure you will too. </p><p> -sam</p> samtregar 2005-06-02T00:04:41+00:00 journal Don't forget to test your tests I ported a couple tests from <a href="">Krang</a> to my latest project today and it occurred to me to share them. The tests go by the ugly names 'aaa_dbcount.t' and 'zzz_dbcount.t'. Their job is to make sure that none of the other tests in our test suite are leaking data in the database. <p> The first script, 'aaa_dbcount.t' is roughly: </p><blockquote><div><p> <tt>&nbsp; &nbsp;foreach database<br>&nbsp; &nbsp; &nbsp; open "$dbname.count.txt"<br>&nbsp; &nbsp; &nbsp; foreach table<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;print count(*) into "$dbname.count.txt"</tt></p></div> </blockquote><p> And 'zzz_dbcount.t' is roughly: </p><blockquote><div><p> <tt>&nbsp; &nbsp;foreach database<br>&nbsp; &nbsp; &nbsp; open "$dbname.count.txt"<br>&nbsp; &nbsp; &nbsp; foreach line<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;get count(*) for the table<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;is($old_count, $new_count)</tt></p></div> </blockquote><p> The tests in zzz_dbcount.t fail when a test that runs after aaa_dbcount.t doesn't clean up after itself. This prevents one run from affecting the next one which can be a very difficult bug to catch otherwise. </p><p> When a failure happens I can use the tests to narrow it down. I pick a suspect and run: </p><blockquote><div><p> <tt>&nbsp; &nbsp;make test TEST_FILES="t/aaa_dbcount.t t/suspect.t t/zzz_dbcount.t"</tt></p></div> </blockquote><p> I've thought about doing something that looks at the writable areas of the filesystem too. I bet that would have caught a nasty bug in Krang that I noticed by accident recently - deleting a story deletes the published files (good) but leaves behind empty directories (bad). </p><p> So why not wrap this up as a Test:: module? I might but it's a very small amount of code and abstracting "foreach database" and "foreach table" so it'll work across DBD drivers seems hard. </p><p> -sam</p> samtregar 2005-06-01T20:31:46+00:00 journal Greasing the Meerkat I while back <a href="">I wrote about wanting a better use.perl link display in Meerkat.</a> My solution at the time was Middleman, a configurable HTTP proxy. I ended up ditching it after it caused some extremely difficult to debug problems developing a web-app. Instead I created a little chunk of Javascript which accomplished the same thing. I attached it to a link on my tool-bar which I click every time I visit Meerkat. It works, but it's hardly ideal. <p> Enter <a href="">Greasemonkey</a>, a plugin for Firefox which allows you to add Javascript to a page based on a URL match. I took the Javascript I already had in my link, converted it to a Greasemonkey user-script and now I see author names in Meerkat without any effort on my part. Fantastic! </p><p> For the record, here's my user-script: </p><blockquote><div><p><nobr> <wbr></nobr><tt>// ==UserScript==<br>// @name&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Meerket User Names<br>// @namespace&nbsp; &nbsp; &nbsp;<br>// @include&nbsp; &nbsp; &nbsp; &nbsp;*<br>// ==/UserScript==<br> <br>(function() {<br>&nbsp; &nbsp; for (var x = 0; x &lt; document.links.length; x++) {<br>&nbsp; &nbsp; &nbsp; &nbsp; var l = document.links[x];<br>&nbsp; &nbsp; &nbsp; &nbsp; if (l.href.indexOf('~') != -1) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var name = l.href.substring(l.href.indexOf('~'));<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name = name.substring(1, name.indexOf('/'));<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; l.innerHTML = '[' + name + '] ' + l.innerHTML;<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; }<br>})();</tt></p></div> </blockquote><p> -sam</p> samtregar 2005-04-15T16:50:12+00:00 journal Industrial Strength Add-Ons Coming Soon to Krang My reinvention of the Krang add-on system is well under way. The previous system was little more than convenient way to package source code that could be copied into Krang. It had upgrades and dependencies, but that was it. <p> The new system will allow Krang to mature into a true application development platform. Addons will be installed into their own space under addons/. This has two important advantages: 1) it will keep addons from accidently or purposefully overwriting Krang source files (and vice-versa) and 2) addons can be developed in-place under version control. </p><p> Fixing these two issues should make developing add-ons a lot more pleasant. But the new design doesn't stop there - it also brings Krangs build system to addons so they can come with their own dependencies. A new class factory system will allow add-ons to selectively extend core Krang classes without needing to alter Krang's code. Finally, Krang's left-nav area will be modularized so add-ons can register new entries without having to completely override the navigation templates. </p><p> The new system should land in Krang v1.103 sometime later this week. I'm off on a branch for now so v1.102 can get out the door without more QA. </p><p> -sam</p> samtregar 2005-04-04T23:18:37+00:00 journal Binding keys to raise windows by name I generally program with three windows open - Emacs, Firefox and Gnome-Terminal. I also like huge fonts so there's no way I can see the contents of all three windows simultaneously. I've gotten used to using alt-tab to cycle through them, but it's a pain. I know which one I want but I always have to look for it. <p> To solve this problem I wrote a script which uses <a href="">wmctrl</a> to raise a window on the current desktop by name. Here it is: </p><blockquote><div><p> <tt>#!/usr/bin/perl<br>use strict;<br>use warnings;<br> <br>my $what = shift;<br>die "Missing what arg." unless $what;<br> <br>my $desktops = `/usr/local/bin/wmctrl -d`;<br>my ($active_desktop) = $desktops =~<nobr> <wbr></nobr>/^(\d+)\s+\*/m;<br>die "Unable to determine active desktop!" unless defined $active_desktop;<br> <br>my $windows = `/usr/local/bin/wmctrl -l`;<br>my ($id) = $windows =~<nobr> <wbr></nobr>/^(0x\w+)\s+\Q$active_desktop\E\s+\w+.*\Q$what\E/m;<br>die "Unable to find $what on $active_desktop!" unless $id;<br> <br>system('/usr/local/bin/wmctrl', '-i', '-a', $id);</tt></p></div> </blockquote><p> I called it and call it like: </p><blockquote><div><p> <tt>$ emacs</tt></p></div> </blockquote><p> Then to finish the job I edited the Metacity configuration to bind Alt-e to raise Emacs, Alt-f to raise Firefox and Alt-s to raise the terminal (shell). Mission accomplished! </p><p> (Of course, all this would be much easier if Metacity supported a scripting language like Sawfish did. I miss Sawfish...) </p><p> -sam</p> samtregar 2005-03-24T19:57:16+00:00 journal Emacs mode for Test::Harness output? I've been playing with <a href="">ECB</a> (Emacs Code Browser) today. So far I'm very impressed. It gives me three panes stacked up next to the edit windows: a project browser, a file browser and a buffer list. It will also do method browsing but I'm not ready for that yet. <p> The thing is, it's missing something: tests. I still have to switch to a terminal every time I run my tests. Ideally I'd like to bind a key to run 'make test' on the project and see the results in a buffer. Syntax highlighting would be icing on the cake. </p><p> Anyone know of something I can use for this? I tried M-x compile but the Test::Harness output looks horrible in it. Googling around and looking in the <a href="">Emacs Wiki</a> didn't turn up much. </p><p> -sam</p> samtregar 2005-03-11T22:27:51+00:00 journal My book is now free! My book, <a href="">Writing Perl Modules for CPAN</a>, is now available as <a href="">a free download from Apress</a>. Enjoy! <p> -sam</p> samtregar 2005-03-04T00:59:30+00:00 journal The Rock Moved I got out from under my rock briefly last night, attending my second <a href="">New York Perl Monger's</a> meeting. I went to one last year to hear Geoff Young talk about mod_perl 2 (I think). <p> The big draw last night was a chance to meet <a href="">David Wheeler</a>. I worked with David on a nearly daily basis for over a year on the Bricolage project without ever meeting face-to-face. Aside from our running MySQL vs PostgreSQL "conversation," the meeting was a pleasant one. Things got a bit ugly when someone asked David for a "three sentence description of Krang" but I can't honestly say I would have handled a similar question about Bricolage with any greater sensitivity! </p><p> I also got a chance to talk to a couple guys working on <a href="">Phalanxing</a> HTML::Template. I'm looking forward to their contributions with a mixture of embarrassment and hopefullness. I'm sure better testing can only help, but that's some very old code and more than a little gross. Oh HTML::Template version 3, when will I write you? </p><p> -sam</p> samtregar 2005-03-02T17:07:26+00:00 journal New versions of HTML::PopupTreeSelect and onchange I released <a href="">HTML::PopupTreeSelect v1.5</a> today (<a href="">demo here</a>). This release adds a 'resizable' option and fixes some HTML and CSS standards violations. Thanks to Zac Shepard, Peter Leonard and Don Brodale for all the new code! <p> I also updated my <a href="">onchange</a> script to do a recursive walk when passed a directory. I don't know if anyone else uses this script but I find it terribly useful. </p><p> -sam</p> samtregar 2005-02-24T20:53:45+00:00 journal Narcissism, Thy Name is Homepage I've updated <a href="">my homepage</a>. It's now mostly correct and contains pointers to nearly all my public work. <p> Now, for a second act, I think I'll go post my picture on <a href="">Am I Hot or Not</a>. </p><p> -sam</p> samtregar 2005-02-14T01:07:57+00:00 journal New Job It's finally public where I work, so I can feel free to tell you all the good news. I've taken a job at <a href="">Plus Three</a>. I start next Tuesday. <p> I honestly couldn't be more excited about this for many reasons. To name just a few: </p><ul> <li>I'll be working for the good guys, rather than the usual money guys. Plus Three does work for non-profits and organizations like the Democratic National Committee and the United Federation of Teachers.</li><li>I'll be working on <a href="">Krang</a> again. Krang will likely play a big role in Plus Three's upcoming ARCOS product.</li><li>I'll be working with a good friend of mine, <a href="">Perrin Harkins</a>. We worked next to each other on different projects at Primedia for a short while and I think we're going to be a great team.</li><li>Everyone I've met at Plus Three seems happy to be there and excited about the work. That's a big change from my current job!</li><li>I'll be programming full-time, unlike my current 90/10 management/programming split which is making me into a bitter, unhappy man.</li></ul><p> -sam</p> samtregar 2005-02-09T18:33:02+00:00 journal