<?xml version="1.0" encoding="utf-8" ?>

<rss version="2.0" 
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:admin="http://webns.net/mvcb/"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
   xmlns:wfw="http://wellformedweb.org/CommentAPI/"
   xmlns:content="http://purl.org/rss/1.0/modules/content/"
   >
<channel>
    
    <title>Coffee|Code : Dan Scott - Programming languages</title>
    <link>http://coffeecode.net/</link>
    <description>Caffeinated Librarian Geek</description>
    <dc:language>en</dc:language>
    <generator>Serendipity 1.6.2 - http://www.s9y.org/</generator>
    
    

<item>
    <title>Triumph of the tiny brain: Dan vs. Drupal / Panels</title>
    <link>http://coffeecode.net/archives/261-Triumph-of-the-tiny-brain-Dan-vs.-Drupal-Panels.html</link>
            <category>Coding</category>
            <category>Perl</category>
            <category>PostgreSQL</category>
    
    <comments>http://coffeecode.net/archives/261-Triumph-of-the-tiny-brain-Dan-vs.-Drupal-Panels.html#comments</comments>
    <wfw:comment>http://coffeecode.net/wfwcomment.php?cid=261</wfw:comment>

    <slash:comments>2</slash:comments>
    <wfw:commentRss>http://coffeecode.net/rss.php?version=2.0&amp;type=comments&amp;cid=261</wfw:commentRss>
    

    <author>dan@coffeecode.net (Dan Scott)</author>
    <content:encoded>
    &lt;p&gt;A while ago I inherited responsibility for a Drupal 6 instance and a rather out-of-date server. (You know it&#039;s not good when your production operating system is so old that it is no longer getting security updates).&lt;/p&gt;
&lt;p&gt;I&#039;m not a Drupal person. I dabbled with Drupal years and years ago when I was heavily into PHP, but it never stuck with me. Every time I poked around at the database schema, with serialized objects stuck inside columns, I found something else that I wanted to work on instead. Thus, inheriting a Drupal instance wasn&#039;t something I had been looking forward to. As this production server was running a number of different services that were in use by our library, I went through a number of trial runs to ensure that the base packages wouldn&#039;t introduce regressions or outages. Fast-forward past a reasonably successful early-morning upgrade from Debian Lenny to Squeeze and I was able to start looking at addressing the Drupal instance that was also approximately 18 months out of date.&lt;/p&gt;
&lt;p&gt;Initially, after I worked out the how-to of Drupal upgrades (in short: upgrade just Drupal core, then upgrade the modules), I thought all was well. I even got over the hump of realizing that our instance had had all of the modules dumped into Drupal&#039;s core directory, rather than &lt;tt&gt;sites/all/modules&lt;/tt&gt;, and (even more impressively) got over the problem that the core &lt;em&gt;bluemarine&lt;/em&gt; them had been hacked directly rather than having been separated out into a new custom theme. After working through those learning pains, I realized that somewhere in all of the Drupal and module upgrades, that something got &quot;more secure&quot; and started truncating IMG links to files with spaces in them at the first space. So &quot;foo%20bar.jpg&quot; was becoming &quot;foo.jpg&quot; and we were getting 404s everywhere.&lt;/p&gt;
&lt;p&gt;Did I mention that I didn&#039;t notice this until I upgraded our production instance? Oh yes, I went through iteration after iteration of upgrades on the test server, and dutifully fixed up the problems that I found in the subset of content that I was testing against. I discovered and fixed problems like the production server content linking directly to the test server (slight copy-and-paste errors on the part of the content creators, I suppose). But I didn&#039;t notice all of the 404s, because who uploads images with spaces in their filename?&lt;/p&gt;
&lt;p&gt;Turns out, everyone else in my library does that. Of course! And from what I was able to piece together via Google and browsing drupal.org, there was supposed to be some sanitization of the incoming filenames so that spaces would be normalized, etc. But either that wasn&#039;t introduced until well after our content had been created, or my predecessor had lightly hacked one of the modules, or Drupal itself, and hadn&#039;t bothered to use a source code repository to track those customizations. So, realizing that I needed to make some bulk changes, I went at it with a two-step plan:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create symbolic links for both the truncated filename and the spaces-normalized-to-underscores filenames. Creating symlinks for the truncated filenames would fix the 404s immediately, at the cost of some clash in the intended targets; there were plenty of &lt;tt&gt;Foo illustration.JPG&lt;/tt&gt; and &lt;tt&gt;Foo info.JPG&lt;/tt&gt; pairs of files, but like the Highlander, there can be only on &lt;tt&gt;Foo.JPG&lt;/tt&gt;.&lt;/li&gt;
&lt;li&gt;Munge the database entries so that all of those now apparently insecure %20-containing filenames would become underscores.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you&#039;re a Drupal user or a Drupal with Panels module user, you might know that the database schema suffers from some fairly horrible tricks being played on it. In this case, the Panels module creates a &lt;tt&gt;panels_pane&lt;/tt&gt; table with a &lt;tt&gt;configuration&lt;/tt&gt; TEXT column. Based on the name alone, it might seem odd that column is used to store the HTML content of the corresponding panel. Even odder to me is that this is not just a TEXT column, it&#039;s a column that expects a very particular structure - something like:&lt;/p&gt;
&lt;pre&gt;a:5:{s:11:&quot;admin_title&quot;;s:5:&quot;RACER&quot;;s:5:&quot;title&quot;;s:0:&quot;&quot;;s:4:&quot;body&quot;;s:639:&quot;&amp;lt;p&gt;&amp;lt;img width=&quot;225&quot; height [...]}&lt;/pre&gt;
&lt;p&gt;Ah, nothing like storing an object within a single database column. Of particular interest was the result that I had when I tested updating the column value with a basic &quot;replace(configuration, &#039;%20&#039;, &#039;_&#039;)&quot; - the panel showed only &lt;b&gt;n/a&lt;/b&gt;, presumably because the size (defined by the &lt;tt&gt;s&lt;/tt&gt; properties in the object) for the &quot;body&quot; text property was no longer a match. That would be an instance of http://drupal.org/node/926448 - so okay, clearly I had to change tactics and update the entire object.&lt;/p&gt;
&lt;p&gt;I tried quickly finding the Drupal way to do this: clearly there&#039;s an API and there must be some simple way to retrieve an object, change it&#039;s values, and update it so that the serialized object gets stored in the database and Drupal is happy. However, I couldn&#039;t find a simple tutorial, and trying #drupal on Freenode was unfortunately fruitless as well (although some people did try to suggest running REPLACE() at the database level, that was nice but they didn&#039;t recognize that that would actually damage things significantly).&lt;/p&gt;
&lt;p&gt;So... out came the Perl, and here&#039;s what I hacked together:&lt;/p&gt;
&lt;pre&gt;
#!/bin/perl
use strict;
use warnings;

foreach (&amp;lt;DATA&gt;) {
    chomp();
    my $i = 0;
    my $body = 0;
    my @fixed;
    my @row = split /\t/;
    my $pid = $row[1];
    my $configuration = $row[0];
    my @chunks = split /&quot;;s:/, $configuration;
    foreach my $chunk (@chunks) {
        if (!$i++) {
            push @fixed, $chunk;
            next;
        }
        if ($chunk =~ m/&quot;body/) {
            $body = 1;
            push @fixed, $chunk;
            next;
        }
        if ($body) {
            my ($length, $content) = $chunk =~ m/^(\d+):&quot;(.+)$/;
			for (my $j = 0; $j &lt; 50; $j++) {
            $content =~ s{(/pictures/[^\./]+?)%20}{$1_}g;
			}
            $content =~ s{%20}{+}g;
            $length = length($content);
            $chunk = &quot;$length:\&quot;$content&quot;;
            $body = 0;
        }
        push @fixed, $chunk;
    }
    print &#039;UPDATE panels_pane SET configuration = $ashes$&#039; . 
        join(&#039;&quot;;s:&#039;, @fixed) . &#039;$ashes$&#039; . &quot; WHERE pid = $pid;\n&quot;;
}
__DATA__
&lt;/pre&gt;
&lt;p&gt;Against the trusty database (I ? PostgreSQL!), I ran &lt;tt&gt;COPY (SELECT configuration, pid FROM panels_pane WHERE configuration ~ &#039;%20&#039;) TO &#039;conf_pids.out&#039;;&lt;/tt&gt;, then slapped the Perl code on top and generated a load of UPDATE statements. It&#039;s far from my best Perl code, but it worked and once I gave up on doing things the Drupal way I was able to put it together in a handful of minutes. I now have a functional Drupal 6 instance again, updated such that there are no known security vulnerabilities with either core or the modules we&#039;re using, and there are no broken image links.&lt;/p&gt;
&lt;p&gt;And now I need to begin working towards either grokking Drupal, or finding a content management system that my tiny brain can comprehend, because I don&#039;t want to have to go through these kinds of contortions again with future upgrades... Suggestions welcome!&lt;/p&gt; 
    </content:encoded>

    <pubDate>Thu, 18 Oct 2012 17:48:31 -0400</pubDate>
    <guid isPermaLink="false">http://coffeecode.net/archives/261-guid.html</guid>
    <category>coding</category>
<category>perl</category>
<category>postgresql</category>

</item>
<item>
    <title>File_MARC 0.6.0 - now offering two tasty flavours of MARC-as-JSON output</title>
    <link>http://coffeecode.net/archives/231-File_MARC-0.6.0-now-offering-two-tasty-flavours-of-MARC-as-JSON-output.html</link>
            <category>Coding</category>
            <category>PHP</category>
    
    <comments>http://coffeecode.net/archives/231-File_MARC-0.6.0-now-offering-two-tasty-flavours-of-MARC-as-JSON-output.html#comments</comments>
    <wfw:comment>http://coffeecode.net/wfwcomment.php?cid=231</wfw:comment>

    <slash:comments>1</slash:comments>
    <wfw:commentRss>http://coffeecode.net/rss.php?version=2.0&amp;type=comments&amp;cid=231</wfw:commentRss>
    

    <author>dan@coffeecode.net (Dan Scott)</author>
    <content:encoded>
    &lt;p&gt;I&#039;ve just released the PHP PEAR library &lt;a href=&quot;http://pear.php.net/File_MARC&quot;&gt;File_MARC&lt;/a&gt; 0.6.0. This release brings two JSON serialization output methods for MARC to the table:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;toJSONHash() returns JSON that adheres to Bill Dueber&#039;s proposal for the array-oriented MARC-HASH JSON format at &lt;a href=&quot;http://robotlibrarian.billdueber.com/new-interest-in-marc-hash-json/&quot;&gt;New interest in MARC-HASH JSON&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;toJSON() returns JSON that adheres to Ross Singer&#039;s proposal for an object-oriented JSON format (I could only find a sample at &lt;a href=&quot;http://gist.github.com/511752&quot;&gt;this paste&lt;/a&gt; - not sure if there&#039;s a broader description anywhere, but really -- who needs it?)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
The JSON formats should be useful for developers who don&#039;t want to have to deal with the overhead and sluggishness of a MARC parsing library (yes, File_MARC, I&#039;m looking at you) just to deal with MARC data. Both formats are round-trippable and compact, which is why I chose to support them.
&lt;/p&gt;
&lt;p&gt;
The use of the &lt;a href=&quot;http://php.net/json_encode&quot;&gt;json_encode()&lt;/a&gt; function bumps the minimum PHP version requirement for File_MARC up to 5.2.x from 5.1.x, which kind of sucks, but given that PHP 5.2.0 was &lt;a href=&quot;http://php.net/releases/&quot;&gt;released in 2006&lt;/a&gt;, I think it&#039;s worth it.
&lt;/p&gt;
&lt;p&gt;
You can install File_MARC using the &#039;pear&#039; command on most environments as follows:
&lt;/p&gt;
&lt;p&gt;&lt;tt&gt;pear install File_MARC-beta&lt;/tt&gt;&lt;/p&gt; 
    </content:encoded>

    <pubDate>Sat, 14 Aug 2010 15:10:38 -0400</pubDate>
    <guid isPermaLink="false">http://coffeecode.net/archives/231-guid.html</guid>
    
</item>
<item>
    <title>Moving from Figaro's Password Manager (FPM) to KeePassX</title>
    <link>http://coffeecode.net/archives/224-Moving-from-Figaros-Password-Manager-FPM-to-KeePassX.html</link>
            <category>Android</category>
            <category>Python</category>
    
    <comments>http://coffeecode.net/archives/224-Moving-from-Figaros-Password-Manager-FPM-to-KeePassX.html#comments</comments>
    <wfw:comment>http://coffeecode.net/wfwcomment.php?cid=224</wfw:comment>

    <slash:comments>6</slash:comments>
    <wfw:commentRss>http://coffeecode.net/rss.php?version=2.0&amp;type=comments&amp;cid=224</wfw:commentRss>
    

    <author>dan@coffeecode.net (Dan Scott)</author>
    <content:encoded>
    &lt;p&gt;I&#039;m one of those people who actually keeps different passwords for every site and service I use. So far I&#039;m up to over 400 passwords, so I&#039;m dependent on a password manager. For a long, long time I have used &lt;a href=&quot;http://fpm.sourceforge.net&quot;&gt;Figaro&#039;s Password Manager (FPM)&lt;/a&gt; (and &lt;a href=&quot;http://kedpm.sourceforge.net/&quot;&gt;KedPM&lt;/a&gt; and most recently &lt;a href=&quot;http://als.regnet.cz/fpm2/&quot;&gt;FPM2&lt;/a&gt; as continuations of FPM), but now that I have an Android smartphone on which I can browse without wanting to die, I&#039;ve been itching to get access to my passwords on that. I noticed that &lt;a href=&quot;http://www.keepassdroid.com/&quot;&gt;KeePassDroid&lt;/a&gt; was available, and that &lt;a href=&quot;http://www.keepassx.org&quot;&gt;KeePassX&lt;/a&gt; would work on my desktop. I just had to get from FPM&#039;s password export format to one of KeePass&#039;s import formats. It turns out that nobody had made that particular leap before (or hadn&#039;t shared their conversion script).&lt;/p&gt;
&lt;p&gt;Thus... I bring you the &lt;a href=&quot;http://gitorious.net/fpm-to-keepass-converter&quot;&gt;FPM to KeePass converter&lt;/a&gt;. A straightfoward Python script licensed under the GPL v3 that does a passable job of converting an FPM XML export to a KeePass 1.x or 2.x XML import file. It worked for me, and that&#039;s all that I needed; but maybe it will work for you, too.&lt;/p&gt; 
    </content:encoded>

    <pubDate>Fri, 28 May 2010 15:14:07 -0400</pubDate>
    <guid isPermaLink="false">http://coffeecode.net/archives/224-guid.html</guid>
    
</item>
<item>
    <title>Seven things</title>
    <link>http://coffeecode.net/archives/185-Seven-things.html</link>
            <category>Personal</category>
            <category>PHP</category>
    
    <comments>http://coffeecode.net/archives/185-Seven-things.html#comments</comments>
    <wfw:comment>http://coffeecode.net/wfwcomment.php?cid=185</wfw:comment>

    <slash:comments>5</slash:comments>
    <wfw:commentRss>http://coffeecode.net/rss.php?version=2.0&amp;type=comments&amp;cid=185</wfw:commentRss>
    

    <author>dan@coffeecode.net (Dan Scott)</author>
    <content:encoded>
    &lt;p&gt;I was tagged by &lt;a href=&quot;http://pooteeweet.org/blog/1402&quot;&gt;Lukas&lt;/a&gt; for the &quot;7 things&quot; meme, and meant to do something about it, but I&#039;ve been kind of preoccupied with the new baby and the sprinting toddler and work. Anyway, it seems like a heck of a lot more reasonable than the evil Facebook&#039;s &quot;25 things&quot; meme, so I&#039;m going to take a few minutes to try to play along.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I was an early riser until I was around 15 or 16 years old and discovered the surrealists. At that point, I began experimenting with sleep deprivation as a means of stimulating my prose and poetry. This is also when I began drinking coffee. After about a month, I was no longer capable of being an early riser--and the fruit of writing experiments was, uh, not too impressive.&lt;/li&gt;
&lt;li&gt;Rather than going directly to university after high school, I elected to take what is now termed a &lt;em&gt;gap year&lt;/em&gt;. No trips to Europe for me, though; the goal was to refine my bass-playing and music-reading skills and head to a post-secondary music program. I recorded a few prog-rock tracks in a studio with a fantastic couple of guys (hey Pete and Mike!), but ultimately didn&#039;t put enough effort into my bass to carry out the plan. Let me assure you that a year of working night shifts at a convenience store in the entertainment district of a small city is &lt;u&gt;not&lt;/u&gt; a waste of time; I can&#039;t count the number of experiences that I&#039;m thankful for having had during that time.&lt;/li&gt;
&lt;li&gt;Although I roast and grind my own coffee, I&#039;m not a coffee snob. In fact, I possess almost no sense of smell and I suspect that my sense of taste is limited in comparison to most people, and I&#039;m quite happy to drink diner coffee. I cannot stand the taste of Starbucks coffee, however.&lt;/li&gt;
&lt;li&gt;The first time I was able to run a full kilometre without walking was when I was eighteen. Since then I&#039;ve run a couple of 5K races and and a &lt;a href=&quot;http://www.coffeecode.net/archives/79-Im-not-as-sore-as-I-thought-I-would-be.html&quot;&gt;sprint duathlon&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I&#039;m pretty sure I was destined to become a systems librarian. When I was 10, I used to hang out at the local college&#039;s computer room until the students would log me onto a completely restricted Gandalf mainframe account so I could pretend to be Matthew Broderick in WarGames. My first real job, when I was 14, was as a &quot;computer page&quot; at the Barrie Public Library Children&#039;s Annex. It was my responsibility to oversee the use of the bank of Commodore 64s that the library made available to children, luring them in with games but requiring them to complete their allotment of educational software first. Oh the power.&lt;/li&gt;
&lt;li&gt;I occasionally wrote reviews for random CDs that came into the campus newspaper office. Nobody else wanted to review this orange CD called &lt;em&gt;Tragic Kingdom&lt;/em&gt; by some West-coast band, so I took it on. I gave it a savage review; I wasn&#039;t impressed with faux-ska and couldn&#039;t stand the lead singer&#039;s voice. Six months later No Doubt&#039;s &quot;SpiderWebs&quot; was in high rotation on every radio station in North America (look, folks, that song is repetitive enough without being played twice an hour!). I&#039;m sure that my negative review still gnaws at Gwen Stefani today as she weeps bitterly in her platinum mansion.&lt;/li&gt;
&lt;li&gt;In grade one, my report card read &lt;em&gt;Dan is too critical of his classmates.&lt;/em&gt; In my defence, if they weren&#039;t so stupid--come on, sound it out buddy--I wouldn&#039;t have been critical. Okay, not much of a defence.&lt;/li&gt;
&lt;li&gt;I am not a very demanding friend. I (almost) never call, (almost) never write, and (almost) never visit. Okay, scratch that: I&#039;m a crappy friend. Most of my close friends found out that we were expecting a second child only through Lynn&#039;s Facebook account. I called one couple shortly after Arik was born and his quasi-namesake (one of the Eric&#039;s in our life who bring honour to the noble name) asked me after a few minutes: &quot;So, uhh... did we &lt;em&gt;know&lt;/em&gt; that you were expecting a baby?&quot;. No, no you didn&#039;t, and that&#039;s not your fault. Man I suck.&lt;/li&gt;
&lt;li&gt;I&#039;m really good at arithmetic.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
Link your original tagger(s), and list these rules on your blog.
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Share seven facts about yourself in the post — some random, some weird.&lt;/li&gt;
&lt;li&gt;Tag seven people at the end of your post by leaving their names and the links to their blogs.&lt;/li&gt;
&lt;li&gt;Let them know they’ve been tagged by leaving a comment on their blogs and/or Twitter.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Wow, that was fun. Lemme see, I&#039;m going to break the rules and just tag two people: &lt;a href=&quot;http://blog.evermeet.cx&quot;&gt;Helmut&lt;/a&gt;, because he&#039;s one of the only other people who worked on the ibm_db2 PHP driver out of passion rather than as a job assignment. And &lt;a href=&quot;http://rc98.net&quot;&gt;Gabriel&lt;/a&gt; because I like his style.&lt;/p&gt;
 
    </content:encoded>

    <pubDate>Mon, 09 Feb 2009 00:56:35 -0500</pubDate>
    <guid isPermaLink="false">http://coffeecode.net/archives/185-guid.html</guid>
    
</item>
<item>
    <title>Oooh... looks like I've got (even more) work cut out for me</title>
    <link>http://coffeecode.net/archives/148-Oooh...-looks-like-Ive-got-even-more-work-cut-out-for-me.html</link>
            <category>Coding</category>
            <category>PHP</category>
    
    <comments>http://coffeecode.net/archives/148-Oooh...-looks-like-Ive-got-even-more-work-cut-out-for-me.html#comments</comments>
    <wfw:comment>http://coffeecode.net/wfwcomment.php?cid=148</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://coffeecode.net/rss.php?version=2.0&amp;type=comments&amp;cid=148</wfw:commentRss>
    

    <author>dan@coffeecode.net (Dan Scott)</author>
    <content:encoded>
    &lt;p&gt;
PHP is getting a &lt;a href=&quot;http://www.colder.ch/news/01-16-2008/30/new-datastructures-in-spl.html&quot;&gt;native doubly-linked list structure&lt;/a&gt;. This is fabulous news; when I wrote the &lt;a href=&quot;http://pear.php.net/File_MARC&quot;&gt;File_MARC&lt;/a&gt; PEAR package, I ended up having to implement a &lt;a href=&quot;http://pear.php.net/Structures_LinkedList&quot;&gt;linked list class&lt;/a&gt; in PEAR to support it. File_MARC does its job today (even though I haven&#039;t taken it out of alpha yet), but due to its reliance on userspace data structures it&#039;s an order of magnitude slower than packages like &lt;a href=&quot;http://marc4j.tigris.org&quot;&gt;marc4j&lt;/a&gt; so it&#039;s not the best choice for processing hundreds of thousands of MARC records... today. It hurts a little that the &lt;a href=&quot;http://vufind.org&quot;&gt;VuFind&lt;/a&gt; project has to use a non-PHP solution for populating its Solr indices - although I&#039;m delighted that they have started using File_MARC for some on-demand processing.
&lt;/p&gt;
&lt;p&gt;
Now, when I get a chance (insert raucous mocking laughter here), I hope to be able to make File_MARC use splDoublyLinkedList  and see how it fares with 500K records. Should be good fun! After that, it just needs to be taught how to convert MARC8 to UTF-8, and we&#039;ll have ourselves a fully featured standard MARC package for PHP.
&lt;/p&gt; 
    </content:encoded>

    <pubDate>Wed, 16 Jan 2008 22:30:14 -0500</pubDate>
    <guid isPermaLink="false">http://coffeecode.net/archives/148-guid.html</guid>
    
</item>

</channel>
</rss>