Just a Theory

Trans rights are human rights

Jon Stewart and the Future of Television

Jon Stewart and the Future of Television.

(Via gnat)

Looking for the comments? Try the old layout.

How Does DateTime Ignore CORE::GLOBAL::time?

For the life of me, I can’t figure out why this test fails. time returns my overridden time, and DateTime just calls scalar time, so I would expect it to work. But DateTime appears to be somehow getting the time for CORE::time, instead.

#!/usr/bin/perl -w

use strict;
use DateTime;
use Test::More tests => 1;

BEGIN {
    *CORE::GLOBAL::time = sub () { CORE::time() };
}

my $epoch = time;
sleep 1;
try();

sub try {
    no warnings qw(redefine);
    local *CORE::GLOBAL::time = sub () { $epoch };
    is( DateTime->now->epoch, time );
}

Anyone got any bright ideas? This is a reasonably well-known technique, so I’m sure that I must be overlooking something obvious.

Looking for the comments? Try the old layout.

My OSCON 2005 Presentation Slides Posted

Kineticode has posted PDF versions of my my OSCON 2005 presentation slides. Direct links:

Enjoy!

Looking for the comments? Try the old layout.

No UTF-8 Support on Windows?

This just blows. It will be a while before Bricolage runs on Windows, then. The PostgreSQL team is understandably reluctant to simply include the whole ICU library in PostgreSQL. Maybe it could be compiled into the binaries, though?

Looking for the comments? Try the old layout.

IE DOM Help

I got Test.Harness.Browser working with IE 6 SP 2 today, but decided to spend a bit of time trying to get it working with the DOM script inclusion approach instead of the XMLHttpRequest approach. The code that causes the problem is this (pre is a pre element generated with the DOM API):

el = doc.createElement("script");
el.type = "text/javascript";
// XXX IE chokes on this line.
el.appendChild(doc.createTextNode("window.onload(null, Test)"));
pre.appendChild(el);

This works great in Firefox, but IE 6 doesn’t like the call to appendChild(). It says, “Unexpected call to method or property access.” So I tried to replace that line with:

el.innerHTML = "window.onload(null, Test);";

Firefox is still happy, but now IE 6 says, “Unknown runtime error.” If I try to just append a script tag to pre.innerHTML, I get no error, but the code doesn’t seem to execute, either. In fact, pre.innerHTML appears to be empty!

Anyone have any idea how I can dynamically write to a script element that I’ve created via the DOM?

Looking for the comments? Try the old layout.

Windows Virus Hell

So to finish up development and testing of Test.Harness.Browser in IE 6 last week, I rebooted my Linux server (the one running justatheory.com) into Windows 98, got everything working, and rebooted back into Linux. I felt that the hour or two’s worth of downtime for my site was worth it to get the new version of Test.Simple out, and although I had ordered a new Dell, didn’t want to wait for it. And it worked great; I’m very pleased with Test.Simple 0.20.

But then, in unrelated news, I released Bricolage 1.9.0, the first development release towards Bricolage 1.10, which I expect to ship next month. One of the things I’m most excited about in this release is the new PHP templating support. So on George Schlossnagle’s advice, I sent an email to webmaster@php.net. It bounced. It was late on Friday, and I’m so used to bounces being problems on the receiving end, that I simply forwarded it to George with the comment, “What the?” and went to fix dinner for company.

Then this morning I asked George, via IM, if he’d received my email. He hadn’t. I sent it again; no dice. So he asked me to paste the bounce, and as I did so, looked at it more carefully. It had this important tidbit that I’d failed to notice before:

140.211.166.39 failed after I sent the message.
Remote host said: 550-5.7.1 reject content [xbl]
550 See http://master.php.net/mail/why.php?why=SURBL

“That’s curious,” I thought, and went to read the page in question. It said I likely had a domain name in my email associated with a blacklisted IP address. Well, there were only two domain names in that email, bricolage.cc and justatheory.com, and I couldn’t see how either one of them could have been identified as a virus host. But sure enough, a quick search of the CBL database revealed that the IP address for justatheory.com—and therefore my entire home LAN— had been blacklisted. I couldn’t imagine why; at first I thought maybe it was because of past instances of blog spam appearing here, but then George pointed out that the listing had been added on August 18. So I thought back…and realized that was just when I was engaging in my JavaScript debugging exercise.

Bloody Windows!

So I took steps to correct the problem:

  1. Update my router’s firmware. I’ve been meaning to do that for a while, anyway, and was hoping to get some new firewall features. Alas, no, but maybe I’ll be able to connect to a virtual PPTP network the next time I need to.

  2. Blocked all outgoing traffic from any computer on my LAN on port 25. I send email through my ISP, but use port 587 because I found in the last year that I couldn’t send mail on port 25 on some networks I’ve visited (such as in hotels). Now I know why: so that no network users inadvertently send out viruses from their Windows boxes! I’d rather just prevent certain hosts (my Windows boxen) from sending on port 25, but the router’s NAT is not that sophisticated. So I have to block them all.

  3. Rebooted the server back into Windows 98 and installed and ran Norton AntiVirus. This took forever, but found and fixed two instances of WIN32Mimail.l@mm and removed a spyware package.

  4. Rebooted back into Linux and cleared my IP address from the blacklist databases. I don’t expect to ever use that box for Windows again, now that I have the new Dimension.

The new box comes with Windows XP SP 2 and the Symantec tools, so I don’t expect it to be a problem, especially since it can’t use port 25. But this is a PITA, and I really feel for the IT departments that have to deal with this shit day in and day out.

What I don’t understand is how I got this virus, since I haven’t used Windows 98 in this computer in a long time. How long? Here’s a clue: When I clicked the link in Norton AntiVirus to see more information on WIN32Mimail.l@mm, Windows launched my default browser: Netscape Communicator! In addition, I don’t think I’ve used this box to check email since around 2000, and I never click on attachments from unknown senders, and never .exe or .scr files at all (my mail server automatically rejects incoming mail with such attachments, and has for at least a year).

But anyway, it’s all cleaned up now, and I’ve un-blacklisted my IP, so my emails should be deliverable again. But I’m left wondering what can be done about this problem. It’s easy for me to feel safe using my Mac, Linux, and FreeBSD boxes, but, really, what keeps the Virus and worm writers from targeting them? Nothing, right? Furthermore, what’s to stop the virus and worm writers from using port 587 to send their emails? Nothing, right? Once they do start using 587—and I’m sure they will—how will anyone be able to send mail to an SMTP server on one network from another network? Because you know that once 587 becomes a problem, network admins will shut down that port, too.

So what’s to be done about this? How can one successfully send mail to a server not on your local network? How will business people be able to send email through their corporate servers from hotel networks? I can see only a few options:

  • Require them to use a mail server on the local network. They’ll have to reconfigure their mail client to use it, and then change it back when they get back to the office. What a PITA. This might work out all right if there was some sort of DNS-like service for SMTP servers, but then there would then be nothing to prevent the virus software from using it, either.
  • You can’t. You have to authenticate onto the other network using a VPN. Lots of companies rely on this approach already, but smaller companies that don’t have the IT resources to set up a VPN are SOL. And folks just using their ISPs are screwed, too.
  • Create a new email protocol that’s inherently secure. This would require a different port, some sort of negotiation and authentication process, and a way for the hosting network to know that it’s cool to use. But this probably wouldn’t work, either, because then the virus software can also connect via such a protocol to a server that’s friendly to it, right?

None of these answers is satisfactory. I guess I’ll have to set up an authenticating SMTP server and a VPN for Kineticode once port 587 starts getting blocked. Anyone else got any brilliant solutions to this problem?

Looking for the comments? Try the old layout.

Bricolage Now has PHP 5 Templating

Well, I’ve finally gone and done it. I’ve released Bricolage 1.9.0, the first development release towards 1.10.0, which I plan to get out sometime next month. Among the new features in this release that I’m most excited about are a revamped UI, LDAP authentication, and PHP 5 templating support.

The new UI is really nice. Marshall Roch ported it all to XHTML 1.0 strict plus CSS. All the layout is done with CSS now, instead of the old 1999-era table layouts we had before. The result is much smaller page loads, sometimes up to 70% smaller, Marshall tells me, and therefore much faster loads. Playing around with the new version (now powering the Kineticode and Bricolage Web sites, I do indeed find it to be a lot zippier. Couple the new UI with the new mod_gzip support and static Mason components, and things just perk right along! Oh, and the expandable interfaces for both lists of objects and for editing interfaces is very nice, indeed. Thank you Marshall for the great work!

Kineticode added the LDAP authentication support. We’ve been using a patch for it against 1.8.x for our internal version of Bricolage and it works great. Now we authenticate off of an OpenLDAP server, using the same usernames and passwords we use for our email, Subversion, and RT servers. The configuration is simple, via bricolage.conf directives, and you can even limit users who authenticate to members of a particular LDAP group. Users must exist in Bricolage, and if LDAP authentication fails, you can fall back on Bricolage’s internal authentication. I’m hoping that the LDAP support goes a long way towards attracting more enterprise customers with single sign-on requirements.

And finally—yes, you heard right—Bricolage now supports PHP 5 templating in addition to the existing Perl-based templating architectures (Mason, Template Toolkit, and HTML::Template). So how did we add PHP 5 templating to a mod_perl application? Easy: we hired George Schlossnagle of Omni TI to write PHP::Interpreter, an embedded PHP 5 interpreter. Now anyone can natively execute PHP 5 code from a Perl application. Not only that, but the PHP 5 code can reach back into the Perl interpreter to use Perl modules and objects! Here’s an example that I like to show off to the PHP crowd:

<?php
    $perl = Perl::getInstance();
    $perl->eval("use DBI");
    $perl->eval("use DateTime");
    $dbh = $perl->call("DBI::connect", "DBI", "dbi:SQLite:dbname=dbfile");
    $dbh->do("CREATE TABLE foo (bar TEXT, time DATETIME)");
    $now = $perl->call("DateTime::now", "DateTime");
    $ins = $dbh->prepare("INSERT INTO foo VALUES (?, ?)");
    $ins->execute("This is a test", $now);
    $sel = $dbh->prepare("SELECT bar, time FROM foo");
    $sel->execute();
    $a = array("foo", "bar");
    foreach ($sel->fetch() as $val) {
        echo "$val\n";
    }
    $sel->finish();
    $dbh->do("DROP TABLE foo");
    $dbh->disconnect();
?>

Note that George plans to add convenience methods to load Perl modules and call Perl class methods. Now, to execute this code from Perl, all you have to do is write a little script, call it pphp, like so:

use strict;
use PHP::Interpreter;
my $php = PHP::Interpreter->new;
$php->include(shift);

Then just execute your PHP code with the script: pphp try.php. Yes, this does work! For years, when I’ve run across a PHP coder who wanted to try to tell me that PHP was better than Perl, I always had a one-word reply that left him cursing and conceding defeat: “CPAN.” Well no more. Now PHP hackers can use any module on CPAN, too!

And as for Bricolage, the integration of PHP 5 templating is completely transparent. Users just write PHP 5 templates instead of Mason templates and that’s it! For example, this is a fairly common style Bricolage Mason template:

<%perl>;
for my $e ($element->get_elements(qw(header para _pull_quote_))) {
    my $kn = $e->get_key_name;
    if ($kn eq "para") {
        $m->print("<p>", $e->get_data, "</p>\n");
    } elsif ($kn eq "header") {
        # Test sdisplay_element() on a field.
        $m->print("<h3>", $burner->sdisplay_element($e), "</h3>\n");
    } elsif ($kn eq "_pull_quote_" && $e->get_object_order > 1) {
        # Test sdisplay_element() on a container.
        $m->print($burner->sdisplay_element($e));
    } else {
        # Test display_element().
        $burner->display_element($e);
    }
}
$burner->display_pages("_page_");
</%perl>

The same template in PHP 5 looks like this:

<?php
    # Convenience variables.
    $story   = $BRIC["story"];
    $element = $BRIC["element"];
    $burner  = $BRIC["burner"];
    foreach ($element->get_elements("header", "para", "_pull_quote_") as $e) {
        $kn = $e->get_key_name();
        if ($kn == "para") {
            echo "<p>", $e->get_data(), "</p>\n";
        } else if ($kn == "header") {
            # Test sdisplay_element() on a field.
            echo "<h3>", $burner->sdisplay_element($e), "</h3>\n";
        } else if ($kn == "_pull_quote_" && $e->get_object_order() > 1) {
            # Test sdisplay_element() on a container.
            echo $burner->sdisplay_element($e);
        } else {
            # Test display_element().
            $burner->display_element($e);
        }
    }
    $burner->display_pages("_page_");
?>

Yes, you are seeing virtually the same thing. But this is just a simple template from Bricolage’s test suite. The advantage is that PHP 5 coders who are familiar with all the ins and outs of PHP 5 can just jump in an get started writing Bricolage templates without having to learn any Perl! The Bricolage objects have exactly the same API as they do in Perl, because they are exactly the same objects! So everyone uses the same API documentation for the same tasks. The only issue I’ve noticed so far is that PHP 5 does not yet have proper Unicode support. Since all content in Bricolage is stored as UTF-8, this means that the PHP 5 templates must treat it as binary data. But this is okay as long as templaters use the mb_* PHP 5 functions to parse text.

Overall I’m very excited about this, and hope that it helps Bricolage to reach a whole new community of users. I’d like to thank Portugal Telecom—SAPO.pt for sponsoring the development of PHP::Interpreter and its integration into Bricolage. I believe that they’ve really done the Bricolage community a great service, and I hope that the Perl and PHP communities likewise benefit from the integration possible with PHP::Interpreter.

And just so that the other templating architectures don’t feel left out, here is how the above template looks in Template Toolkit:

[% FOREACH e = element.get_elements("header", "para", "_pull_quote_") %]
    [% kn = e.get_key_name %]
    [% IF kn == "para" %]
<p>[% e.get_data %]</p>
    [% ELSIF kn == "header" %]
        [% # display_element() should just return a value. %]
<h3>[% burner.display_element(e) %]</h3>
    [% ELSIF kn == "_pull_quote_" && e.get_object_order > 1 %]
        [% PERL %]
          # There is no sdisplay_element() in the TT burner, but we"ll just
          # Play with it, anyway.
          print $stash->get("burner")->display_element($stash->get("e"));
        [% END %]
    [% ELSE %]
        [% # Test display_element(). %]
        [% burner.display_element(e) %]
    [% END %]
[% END %]
[% burner.display_pages("_page_") %]

And here it is in HTML::Template:

<tmpl_if _page__loop>
<tmpl_loop _page__loop>
<tmpl_include name="testing/sub/util.tmpl">
<tmpl_var _page_>
<tmpl_var page_break>
</tmpl_loop>
<tmpl_else>
<tmpl_include name="testing/sub/util.tmpl">
</tmpl_if>

I had to use the utility template with HTML::Template to get it to work right, don’t ask why. It looks like this:

<tmpl_loop element_loop>
<tmpl_if is_para>
<p><tmpl_var para></p>
</tmpl_if>
<tmpl_if is_header>
<h3><tmpl_var header></h3>
</tmpl_if>
<tmpl_if is__pull_quote_>
<tmpl_var _pull_quote_>
</tmpl_if>
</tmpl_loop>

These templates come from the Bricolage test suite, where until this release, there were never any template tests before. So you can see that the PHP 5 templating initiative has had major benefits for the stability of Bricolage, too. Now that I’ve really worked with all four templating architectures in Bricolage, I can now say that my preference for which to do goes in this order:

  1. Mason, because of its killer autohandler and inheritance architecture
  2. PHP 5 or Template Toolkit are tied for second place
  3. HTML::Template

In truth, all four are capable and have access to the entire Bricolage API so that they can output anything. So what are you waiting for? Download Bricolage and give it a try!

Looking for the comments? Try the old layout.

Test.Simple 0.20 Released

It gives me great pleasure, not to mention a significant amount of pride, to announce the release of Test.Simple 0.20. There are quite a few changes in this release, including a few that break backwards compatibility—but only you’re writing your own Test.Builder-based test libraries (and I don’t think anyone has done so yet) or if you’re subclassing Test.Harness (and there’s only one of those, that I know of).

The biggest change is that Test.Harness.Browser now supports pure .js script files in addition to the original .html files. This works best in Firefox, of course, but with a lot of help from Pawel Chmielowski (“prefiks” on #jsan), it also works in Safari, Opera, and IE 6 (though not in XP Service Pack 2; I’ll work on that after I get my new PC in the next few days). The trick with Firefox (and hopefully other browsers in the future, since it feels lest hackish to me), is that it uses the DOM to create a new HTML document in a hidden iframe, and that document loads the .js. Essentially, it just uses the DOM to mimic the structure of a typical .html test file. For the other browsers, the hidden iframe uses XMLHttpRequest to load and eval the .js test file. Check it out (verbosely)!

I think that this will greatly enhance the benefits of Test.Simple, as it makes writing tests really simple. All you have to do is create a single .html file that looks something like this:

<html>
<head>
    <script type="text/javascript" src="./lib/JSAN.js"></script>
</head>
<body>
<script type="text/javascript">
    new JSAN("../lib").use("Test.Harness.Browser");
    new Test.Harness.Browser('./lib/JSAN.js').encoding('utf-8').runTests(
        'foo.js',
        'bar.js'
    );
</script>
</body>
</html>

In fact, that’s pretty much exactly what Test.Simple’s new harness looks like, now that I’ve moved all of the old tests into .js files (although there is still a simpl.html test file to ensure that .html test files still work!). Here I’m using JSAN to dynamically load the libraries I need. I use it to load Test.Harness.Browser (which then uses it to load Test.Harness), and then I tell the Test.Harness.Browser object where it is so that it can load it for each .js script. The test script itself can then look something like this:

new JSAN('../lib').use('Test.Simple');
plan({tests: 3});
ok(1, 'compile');
ok(1);
ok(1, 'foo');

And that’s it! Just use JSAN to load the appropriate test library or libraries and go! I know that JSAN is already loaded because Test.Harness.Browser loads it for me before it loads and runs my .js test script. Nice, eh?

Of course, you don’t have to use JSAN to run pure .js tests, although it can be convenient. Instead, you can just pass a list of files to the harness to have it load them for each test:

<html>
<head>
    <script type="text/javascript" src="./lib/Test/Harness.js"></script>
    <script type="text/javascript" src="./lib/Test/Harness/Browser.js"></script>
</head>
<body>
<script type="text/javascript">
    new Test.Harness.Browser(
        'lib/Test/Builder.js',
        'lib/Test/More.js',
        '../lib/MY/Library.js'
    ).runTests(
        'foo.js',
        'bar.js'
    );
</script>
</body>
</html>

This example tells Test.Harness.Browser to load Test.Builder and Test.More, and then to run the tests in foo.js and bar.js. No need for JSAN if you don’t want it. The test script is exactly the same as the above, only without the line with JSAN loading your test library.

Now, as I’ve said, this is imperfect. It’s surprisingly difficult to get browsers to do this properly, and it’s likely that it won’t work at all in many browsers. I’m sure that I broke the Directory harness, too. Nevertheless, I’m pleased that I got as many to work as I did (again, with great thanks to Pawel Chmielowski for all the great hacks), but at this point, I’ll probably only focus on adding support for Windows XP Service Pack 2. But as you might imagine, I’d welcome patches from anyone who wants to add support for other browsers.

There are a lot of other changes in this release. Here’s the complete list:

  • Fixed verbose test output to be complete in the harness in Safari and IE.
  • Fixed plan() so that it doesn’t die if the object is passed with an unknown attribute. This can happen when JS code has altered Object.prototype (shame on it!). Reported by Rob Kinyon.
  • Fixed some errors in the POD documentation.
  • Updated JSAN to 0.10.
  • Added documentation for Test.Harness.Director, complements of Gordon McCreight.
  • Fixed line endings in Konqueror and Opera and any other browser other than MSIE that supports document.all. Reported by Rob Kinyon.
  • Added support to Test.Harness.Browser for .js test files in addition to .html test files. Thanks to Pawel Chmielowski for helping me to overcome the final obstacles to actually getting this feature to work.
  • Added missing variable declarations. Patch from Pawel Chmielowski.
  • More portable fetching of the body element in Test.Builder. Based on patch from Pawel Chmielowski.
  • Added an encoding attribute to Test.Harness. This is largely to support pure JS tests, so that the browser harness can set up the proper encoding for the script elements it creates.
  • Added support for Opera, with thanks to Pawel Chmielowski.
  • Fixed the output from skipAll in the test harness.
  • Fixed display of summary of failed tests after all tests have been run by the browser harness. They are now displayed in a nicely formatted table without a NaN stuck where it doesn’t belong.
  • COMPATIBILITY CHANGE: The browser harness now outputs failure information bold-faced and red. This required changing the output argument to the outputResults() method to an object with two methods, pass() and fail(). Anyone using Test.Harness.outputResults() will want to make any changes accordingly.
  • COMPATIBILITY CHANGE: new Test.Builder() now always returns a new Test.Builder object instead of a singleton. If you want the singleton, call Test.Builder.instance(). Test.Builder.create() has been deprecated and will be removed in a future release. This is different from how Perl’s Test::Builder works, but is more JavaScript-like and sensible, so we felt it was best to break things early on rather than later. Suggested by Bob Ippolito.
  • Added beginAsync() and endAsync() functions to Test.More. Suggested by Bob Ippolito.

As always, feedback/comments/suggestions/winges welcome. Enjoy!

Looking for the comments? Try the old layout.

Plea for Help from JavaScript Geniuses

I’ve been working for some time to get pure .js test files working with Test.Simple. In principal, it’s simple: The Browser harness simply constructs a hidden iframe, and if the test script ends in .js, it uses document.write() for that iframe to write out a new HTML document that includes the test script via a script tag. It can also load other scripts specified by the user in the index.html file that runs the harness.

I got it working, and then converted all of Test.Simple’s own tests over to .js files, at which point it got all weird. The tests were dying after the third test file was loaded and run. After weeks of on and off debugging, I’ve reduced the problem enough to find the following:

  • I’m using JSAN to load dependencies in the test scripts themselves. The browser harness loads it by writing a script tag into the head section of the iframe.
  • The tests always use JSAN to load Test.Builder, either directly or by loading a library that depends on it (like Test.More.
  • Test.Builder detects when it’s being run in a browser and sets an onload event handler to end the execution of tests.
  • For the first two test files, Test.Builder loads and runs, and sets up the onload event handler, and it properly executes when the test finish.
  • But in the third test, the onload event handler seems to run before Test.Builder has finished execution or even loading! As such, it cannot get access to the Test.Builder class to finish the tests, and throws an exception: “Error: this.Test has no properties”, where this is the iframe window object.

The only thing I can guess is that it’s retaining the onload event handler for the previous test file, even if I put delete buffer.onload before writing out the HTML to load the test file! (Note that “buffer” is the name of the variable that is holding the contentWindow attribute of the iframe object.) You can observe this behavior for yourself by running the tests now. They don’t work in Safari at all (I code to Firefox and then port to the other browsers), but Firefox demonstrates the issue. I have alert()s that run just before Test.Builder sets up the onload event handler, and then inside the event handler, either when its run or when it catches an exception (but before it rethrows it). The order of execution, you’ll note, is as follows:

  • “async.js……….” output to browser
  • alert("Setup: buffer") during the execution of Test.Builder for async.js, where “buffer” is the name of the iframe element.
  • alert("Onload: buffer") for async.js, during the execution of the onload event
  • “bad_plan.js…….” output to browser
  • alert("Setup: buffer") during the execution of Test.Builder for bad_plan.js
  • alert("Onload: buffer") for bad_plan.js, during the execution of the onload event
  • “buffer.js……..” output to browser
  • alert("Catch: buffer") output from catching the exception in the onload handler for buffer.js, which, of course, Test.builder hasn’t set up yet!

If I don’t rethrow the exception, it then runs the code in Test.Builder that sets up the onload handler. In other words, the onload handler runs before it has been created. Huh?

The nearest to a workaround that I’ve found is to delete the iframe element after each test and create a new one. The errors are still thrown, but all tests seem to pass anyway. It doesn’t seem to like the old-style .html test files, though; it hangs on them without throwing any error at all. Grrrr.

So, are you a JavaScript genius? Do you know how the browser, DOM, and frames work and interact better than you know your own family? If so, please, please give me a hint as to what I can do to fix this problem so that I can get a new version of Test.Simple out ASAP. Thanks!

Update: I forgot to mention that the in-progress source code for Test.Simple with support for .js test files can be downloaded here, so that you can play with it on your own system. Thanks!

Looking for the comments? Try the old layout.

Has Google Forgotten its on Tagline?

My friend Chad Dickerson, the exiting CTO of Infoworld, has blogged about a recent move by Google to patent advertising in RSS!

Incorporating targeted ads into information in a syndicated, e.g., RSS, presentation format in an automated manner is described. Syndicated material e.g., corresponding to a news feed, search results or web logs, are combined with the output of an automated ad server. An automated ad server is used to provide keyword or content based targeted ads. The ads are incorporated directly into a syndicated feed, e.g., with individual ads becoming items within a particular channel of the feed.

This despite the fact that InfoWorld was itself sending targeted ads out in is RSS feeds before Google filed for its patent! Is this another one-click debacle in the making? Does it really make any sense to patent delivering targeted ads over HTTP just because they’re in XML instead of HTML?

What do you think?

Looking for the comments? Try the old layout.

Bricolage 1.8.6 Released

The Bricolage development team is pleased to announce the release of Bricolage 1.8.6. This maintenance release addresses numerous minor issues in Bricolage 1.8.5 and adds a number of improvements, including SOAP, document expiration, and bric_queued fixes. The most important changes include:

Improvements

  • Added JavaScript code to validate that the username in the user profile does not have leading or trailing spaces. [David]
  • Events in the event log are now returned (and displayed) in reverse chronological order. [David]
  • The SOAP server now uses a user’s template sandbox when executing previews (such as with bric_soap --to-preview workflow publish). Reported by Marshall. [David]
  • Bric::Biz::Workflow now caches calls to allowed_desks(). This will allow desks to render much Faster, since most assets on a desk will list the same desks in the “Move to” select lists. [David]
  • When the PUBLISH_RELATED_ASSETS bricolage.conf directive is enabled, aliases are now also republished. Only aliases that have previously been published will be republished, and only the last published version will be republished, rather than any versions created since the last publish. Suggested by Serge Sozonoff. [David]
  • A story or media document published with an expire date earlier than the scheduled publish time no longer bothers with the publish but just expires the story or media document. [David]
  • Media documents without an associated media file will no longer be displayed in the search results when attempting to relate a media document to an element. Reported by Adam Rinehart. [David]

Bug Fixes

  • Form validation and group management now properly work in the user profile. [David]
  • The SFTP mover now works with bric_queued. [David]
  • Cloned stories now properly set the published_version attribute to undef rather than the value of the original story, thus preventing the clone from having a published version number greater than its current version number. Reported by Nate Perry-Thistle and Joshua Edelstein. [David and Nate Perry-Thistle]
  • When a category is added to a story that creates a URI conflict, the new category does not remain associated with the story in the story profile after the conflict error has been thrown. Reported by Paul Orrock. [David]
  • Contributor groups created in the contributor profile are no longer missing from the contributor manager search interface. Reported by Rachel Murray and Scott. [David]
  • The favicon.ico works again. [David]
  • Stories are now properly expired when the BRIC_QUEUED bricolage.conf directive is enabled. Reported by Scott. [David]
  • When a template is checked out of the library and then the checkout is canceled, it is no longer left on the desk it was moved into upon the checkout, but properly reshelved. Reported by Marshall. [David]
  • Super Bulk Edit now works for media as well as stories. Reported by Scott. [David]
  • When a template is moved to a new category, the old version of the template is undeployed when the new version is deployed to the new category. The versions in the sandbox are properly synced, as well.

For a complete list of the changes, see the changes. For the complete history of ongoing changes in Bricolage, see Bric::Changes.

Download Bricolage 1.8.6 now from the Bricolage Web site Downloads page, from the SourceForge download page, and from the Kineticode download page.

About Bricolage

Bricolage is a full-featured, enterprise-class content management and publishing system. It offers a browser-based interface for ease-of use, a full-fledged templating system with complete HTML::Mason, HTML::Template, and Template Toolkit support for flexibility, and many other features. It operates in an Apache/mod_perl environment and uses the PostgreSQL RDBMS for its repository. A comprehensive, actively-developed open source CMS, Bricolage has been hailed as “quite possibly the most capable enterprise-class open-source application available” by eWEEK.

Looking for the comments? Try the old layout.

Bricolage 1.8.6 Released

The Bricolage development team is pleased to announce the release of Bricolage 1.8.6. This maintenance release addresses numerous minor issues in Bricolage 1.8.5 and adds a number of improvements, including SOAP, document expiration, and bric_queued fixes. The most important changes include:

Improvements

  • Added JavaScript code to validate that the username in the user profile does not have leading or trailing spaces. [David]

  • Events in the event log are now returned (and displayed) in reverse chronological order. [David]

  • The SOAP server now uses a user’s template sandbox when executing previews (such as with bric_soap --to-preview workflow publish). Reported by Marshall. [David]

  • Bric::Biz::Workflow now caches calls to allowed_desks(). This will allow desks to render much Faster, since most assets on a desk will list the same desks in the “Move to” select lists. [David]

  • When the PUBLISH_RELATED_ASSETS bricolage.conf directive is enabled, aliases are now also republished. Only aliases that have previously been published will be republished, and only the last published version will be republished, rather than any versions created since the last publish. Suggested by Serge Sozonoff. [David]

  • A story or media document published with an expire date earlier than the scheduled publish time no longer bothers with the publish but just expires the story or media document. [David]

  • Media documents without an associated media file will no longer be displayed in the search results when attempting to relate a media document to an element. Reported by Adam Rinehart. [David]

Bug Fixes

  • Form validation and group management now properly work in the user profile. [David]

  • The SFTP mover now works with bric_queued. [David]

  • Cloned stories now properly set the published_version attribute to undef rather than the value of the original story, thus preventing the clone from having a published version number greater than its current version number. Reported by Nate Perry-Thistle and Joshua Edelstein. [David and Nate Perry-Thistle]

  • When a category is added to a story that creates a URI conflict, the new category does not remain associated with the story in the story profile after the conflict error has been thrown. Reported by Paul Orrock. [David]

  • Contributor groups created in the contributor profile are no longer missing from the contributor manager search interface. Reported by Rachel Murray and Scott. [David]

  • The favicon.ico works again. [David]

  • Stories are now properly expired when the BRIC_QUEUED bricolage.conf directive is enabled. Reported by Scott. [David]

  • When a template is checked out of the library and then the checkout is canceled, it is no longer left on the desk it was moved into upon the checkout, but properly re-shelved. Reported by Marshall. [David]

  • Super Bulk Edit now works for media as well as stories. Reported by Scott. [David]

  • When a template is moved to a new category, the old version of the template is un-deployed when the new version is deployed to the new category. The versions in the sandbox are properly synced, as well.

For a complete list of the changes, see the changes. For the complete history of ongoing changes in Bricolage, see Bric::Changes.

Download Bricolage 1.8.6 now from the Bricolage Web site Downloads page, from the SourceForge download page, and from the Kineticode download page.

About Bricolage

Bricolage is a full-featured, enterprise-class content management and publishing system. It offers a browser-based interface for ease-of use, a full-fledged templating system with complete HTML::Mason, HTML::Template, and Template Toolkit support for flexibility, and many other features. It operates in an Apache/mod_perl environment and uses the PostgreSQL RDBMS for its repository. A comprehensive, actively-developed open source CMS, Bricolage has been hailed as “quite possibly the most capable enterprise-class open-source application available” by eWEEK.

Originally published on use Perl;

Test.Simple 0.11 Released

I’m pleased to announce the release of Test.Simple 0.11. This release fixes a number of bugs in the framework’s IE and Safari support, adds JSAN support, and includes an experimental harness for Macromedia^Adobe Director. You can download it from JSAN, and all future releases will be available on JSAN. See the harness in action here (or verbosely!). This release has the following changes:

  • The browser harness now works more reliably in IE and Safari.
  • Fixed syntax errors in tests/harness.html that IE and Safari care about.
  • Various tweaks for Director compatibility from Gordon McCreight.
  • Removed debugging output from Test.More.canOK().
  • Fixed default output so that it doesn’t re-open a closed browser document when there is a “test” element.
  • Added experimental Test.Harness.Director, complements of Gordon McCreight. This harness is subject to change.
  • Added Test.PLATFORM, containing a string defining the platform. At the moment, the only platforms listed are “browser” or “director”.
  • Added support for Casey West’s JSAN. All releases of Test.Simple will be available on JSAN from now on.
  • The iframe in the browser harness is no longer visible in IE. Thanks to Marshall Roch for the patch.
  • Noted addition of Test.Harness and Test.Harness.Browser in the README.

I’ve been getting more and more excited about Casey West’s work on JSAN. It gets better every day, and I hope that it attracts a lot of hackers who want to distribute open source JavaScript modules. You should check it out! I’ve been working on a Perl module to simplify the creation of JSAN distributions. Look for it on CPAN soonish.

Looking for the comments? Try the old layout.

How the Bricolage Summer of Code Projects were Selected

As you may have read, we got quite a number of applications from students wishing to contribute to Bricolage as part of Google’s Summer of Code initiative. Quite a few of them were very good. There were eight projects I wanted to accept, but, Bricolage was allocated only four projects. Of course, this is four more than we would have had otherwise, and I’m really excited to be working with them this summer.

The four winning projects are:

  • Add Input Channels, by Marshall Roch
  • New Sample Document types and templates, by Scott Loyd
  • Port Bricolage to Apache 2/mod_perl 2 and Windows, by Sam Strasser
  • Port Bricolage to MySQL, by Tamas Mezei

The other projects I wanted to get but could not were:

  • Add Bulk Edit, Bulk Media Upload, and Site Tags, by Andreas Hofmeister
  • Element Occurrence Specification, by Christian James Muise
  • Add JSP Templating, by Adrian Fernandez
  • Update and Modernize the Installer, by Yiannis Valassakis

I am hoping that some of these students might want to work on their projects, anyway. I’ve even found other developers to help with the mentoring of JSP templating (Patrick LeBoutillier with Perl/Java voodo) and the installer modernization (Sam Tregar of Matchstick fame). Unfortunately, I’ve not heard back from any of them after sending them an invite to participate in the project. C’est la vie, I guess

The hardest part of the proposal evaluation process was selecting from the 20 proposals to port Bricolage to MySQL. Ultimate, there were four excellent proposals for this project. Reading the proposals over and over, I couldn’t decide between them. Ultimately, I sent an email to the four top contenders with the following items for them to reply to:

  1. Please describe in a line or two your Perl knowledge or experience (if any).
  2. Please describe in a line or two your MySQL and PostgreSQL knowledge or experience (if any).
  3. Please describe any previous Bricolage usage experience.
  4. Please describe any previous Bricolage development experience.
  5. Please describe any previous Open Source development experience.
  6. What school do you attend?
  7. What is your specialty at the school?
  8. How many years have you attended there?
  9. How much time do you expect to have for this project?
  10. Have you applied for any other Summer of Code projects? If so, which ones?
  11. Your personal or professional web page URL (if any).
  12. Would you be willing to collaborate with another developer who might be working on a SQLite port to ensure that your changes can fully inter-operate?
  13. Please outline your project plan for porting Bricolage to MySQL, including a description of what parts of the Bricolage API, DDLs, installer, and upgrader would need to be modified to complete the project.

For better or for worse, all four applicants responded with detailed answers to my questions. They were all great, and that made it even harder to select just one of them. At this point, there were only a few hours left to rank applicants in Google’s SoC Admin Web app, so I figured I had to get more objective—or at least fool myself into thinking I was.

So I decided to rank each applicant from one to five for each question, and then add up all of the results and see who came out on top. So now I was comparing answers to a single question between applicants, and filling in scores for them in a spreadsheet. As it was, things were still really close; yes, all of the students where that good! Tamas came out on top with a score of 30, two others were tied at 28, and the fourth applicant scored 26. They were close enough that I wanted to review them all one more time, this time paying specific attention to the last item in my questionnaire, the project plan.

Each of the four applicants had taken the time to read the mail lists and had looked at the existing Bricolage code. But there were varying levels of detail and demonstration of knowledge for how to implement the MySQL port, but Tamas did come out slightly ahead on this item, so I gave his proposal the green light.

But in truth, I would have been happy with any one of those four applicants. I was only sorry I had to choose only one! If Google does this again, I think I’ll list many more project ideas on the Bricolage Web site, and try to steer people to the mail lists to discuss their ideas before sending them in. Then I might end up with 11 great applications!

Looking for the comments? Try the old layout.

Test.Simple 0.10 Released

I’m pleased to announce the first beta release of Test.Simple, the port of Test::Builder, Test::Simple, Test::More, and Test::Harness to JavaScript. You can download it here. See the harness in action here (or verbosely!). This release has the following changes:

  • Changed the signature of functions passed to output() and friends to accept a single argument rather than a list of arguments. This allows custom functions to be much simpler.
  • Added support for Macromedia Director. Patch from Gordon McCreight.
  • Backwards Incompatibility change: moved all “modules” into Test “namespace” by using an object for the Test namespace and assigning the Build() constructor to it. See http://xrl.us/fy4h for a description of this approach.
  • Fixed the typeOf() class method in Test.Builder to just return the value returned by the typeof operator if the class constructor is an anonymous function.
  • Changed for (var in in someArray) to for (var i = 0; i < someArray.length; i++) for iterating through arrays, since the former method will break if someone has changed the prototype for arrays. Thanks to Bob Ippolito for the spot!
  • The default output in browsers is now to append to an element with the ID “test” or, failing that, to use document.write. The use of the “test” element allows output to continue to be written to the browser window even after the document has been closed. Reported by Adam Kennedy.
  • Changed the default endOutput() method to be the same as the other outputs.
  • Backwards incompatibility change: Changed semantics of plan() so that it takes an object for an argument. This allows multiple commands to be passed, where the object attribute keys are the command and their values are the arguments.
  • Backwards incompatibility change: Changed the “no_plan”, “skip_all”, and “no_diag” (in Test.More only) options to plan() to their studlyCap alternatives, “noPlan”, “skipAll”, and “noDiag”. This makes them consistent with JavaScript attribute naming convention.
  • Added beginAsync() and endAsync() methods to Test.Builder to allow users to put off the ending of a script until after asynchronous tests have been run. Suggested by Adam Kennedy.
  • Backwards incompatibility change: Changed the signature for the output() method and friends to take only a single anonymous function as its argument. If you still need to call a method, pass an anonymous function that calls it appropriately.
  • Changed handling of line-endings to be browser-specific. That is, if the current environment is Internet Explorer, we use “\r” for line endings. Otherwise we use “\n”. Although IE properly interprets \n as a line ending when it’s passed to document.write(), it doesn’t when passed to a DOM text node. No idea why not.
  • Added a browser harness. Now you can run all of your tests in a single browser window and get a summary at the end, including a list of failed tests and the time spent running the tests.
  • Fixed calls to warn() in Test.More.
  • Output to the browser now causes the window to scroll when the length of the output is greater than the height of the window.
  • Backwards incompatibility change: Changed all instances of “Ok” to “OK”. So this means that the new Test.More function names are canOK(), isaOK(), and cmpOK(). Sorry ‘bout that, won’t happen again.
  • Ported to Safari (though there are issues–see the “Bugs” section of the Test.Harness.Browser docs for details).

Obviously this is a big release. I bumped up the version number because there are a fair number of backwards incompatibilities. But I’m reasonably confident that they wont’ change so much in the future. And with the addition of the harness, it’s getting ready for prime time!

Next up, I’ll finish porting the test from Test::Harness (really!) and add support for JSAN (look for a JSAN announcement soon). But in the meantime, feedback, bug reports, kudos, complaints, etc.warmly welcomed!

Looking for the comments? Try the old layout.

Bricolage Summer of Code Application Summary

Total Applications48
Gibberish Applications2
Duplicates4
Wrong Project2
Students with 2 Applications3
Students with 4 Applications1

Google has finally launched the WebApp for the project administrators for its Summer of Code initiative. I logged in, thinking that Bricolage might get five or ten applications.

No, there were 48! I’ve just started going through them, but the table to the left contains a quick summary of what came in.

That leaves 42 applications! (Huh, and 42 happens to be the answer. Imagine that.) After a quick survey, the table below summarizes how they break down in terms of the projects and number of proposals. There are more than 42 here because quite a few applications group together a number of tasks.

MySQL Port20
SQLite Port10
Apache 2/mod_perl 2/Windows Port4
Modernize the Installer3
JSP Templating2
Hierarchical Bulk Editing2
Category Permission Inheritance2
Site Tagging and Rollback2
ASP.NET Templating1
Bulk Media Uploading1
Apache 2/mod_perl 2 port1
Rewrite Bricolage in PHP1
Element Occurrence Specification1
I can improve Bricolage1
Input Channels1
Concurrent Checkouts & Conflict Resolution1
Subversion Integration1
New Sample Templates1
Add Middle Initials to Contributors1

I am stunned and amazed by the sheer number of proposals the project received. There are quite a few good ones, too. I’ve told Google that I can handle five or six projects, but it might end up being a lot! I’ll have to really pare them down this weekend. So fare I’ve eliminated a dozen or so that are simple one-liners (such as, “Port Bricolage to mySQL[sic]”), but now the real work of comparing and contrasting begins—especially for all of those MySQL proposals!

Looking for the comments? Try the old layout.