krang_body.jpg Krang is an OSS Perl CMS that doesn't get a lot of attention (in the Perl world is mostly Moveable Type and sometimes Bricolage). We use it at work and for the most part I'm pretty happy with it. So after being inspired by this post I thought I'd write a similar post about Krang just to get the word out there.

1 - Flexible

Love

Krang was initially developed for a large magazine company that had lots of magazines that they needed to bring online. Each magazine had their own look and feel, their own editors, their own workflow and their own style of composing articles. Krang needed to support all of these magazines in a single install.

Everything about a story in Krang is defined by an "element library". These element libraries can be created for each site you run or they can be shared between multiple sites. You can also inherit from other libraries to have some sites become even more specialized.

Krang also has the concept of different story types, so in your element library you could define blog posts, petitions, image galleries, surveys, etc. Every industry can be different in the kinds of things they want on their site. With the right element library you can easily turn Krang from a generic CMS into an industry specific one. That's why I like to think of Krang as a CMS platform rather than just a CMS.

Krang also divorces the creation and editting of content from the serving of that content. By default Krang publishes out static HTML documents and media files which can then be served by any old webserver. But for the more power hungry among us, we use Krang to publish out more interesting things. XML, PHP, generated Perl scripts, HTML::Template templates, .htaccess files, you name it. We then customize our front-end web servers to take those generated files and turn them into the tasty goodness that our clients see.

edit_story-thumb.png

Krang also has an extensive addon system that allows any addon to override and extend any internal Krang class, template or media file. This means we can easily add extra screens, extra reports or even add fields to existing screens. All of these enhancements can exist with very little worry about upgrades breaking our addons (if we're careful).

At my job we manage over 70 distinct sites using just a handful of element libraries. Each one is very distinct in it's layout and different in what they do. Some are basically, static HTML sites. Others have complicated forms tied together and still others are flash apps that consume XML data files.

Hate

This flexibility comes at a cost. Setting up Krang is not a simple task. It does come with a very basic Default element library, but I see that more as an example of how to write your own element library rather than something that's useful for basic sites.

You also need to write you own templates, stylesheets, etc. Nothing like the nice pre-packaged skins you can get for Wordpress or Moveable Type.

We've talked about making this easier with a better default element library and even writing other more specific element libraries for common types of sites. We also talked about creating a kind of Krang-Forge where people could share and collaborate on addons. Unfortunately no one has found the time to do any of these ideas.

Krang's documentation is pretty good and thorough, but to get started you need to have skills as a sys-admin, Perl developer and front-end web designer. So it's hard to justify for smaller projects if you don't already have all that talent on hand.

2 - Everything is an Element

Love

Story elements (and even elements on media objects, and categories) are defined by the story's type and element library being used. When you create a story you add the elements you need and ignore the ones you don't. For an article this could be headings, subheadings, paragraphs, quotes, images, tags, etc. Elements can even be nested so that you can add things like images where you put in an alignment value, a caption, an attribution, etc and have it all be treated like a single entity when publishing.

find_story_adv-thumb.png

Each element can have it's own template and publishing works by cascading upward: first publish the image's caption with it's template (if it has one) then the image with it's optional template and then the article the image is in. This gives a lot of power in deciding how similar things can look on different parts of the site.

The element library defines not only how the element is published, but also how it looks when the editor enters the data. An Event story's date element could be a fancy pop up calendar. A paragraph could be a little WYSIWYG editor and a section-heading could be simple text input.

Hate

Because everything is an element, they aren't just simple text items. Elements are complex Perl objects that are serialized and stored in the database. This makes it hard to examine them on the outside. You almost always have to write Perl code to manipulate the data in story. And because things can be nested to arbitary levels it's not always easy to find what you want in a flat database table.

Debugging serialized story data can sometimes be a royal pain. Dumping out a story's elements using Data::Dumper for more complicated stories can fill up many terminal screens.

Having our Stories in structured data has lots of benefits, but simplicity isn't one of them. Sometimes users just want a simple large WYSIWYG editor on the page so they can pretend they are using Microsoft Word and not have to think about composition or consistency. "I want this sentence to be red and blinking!".

3 - Small Community

Love

krang_grafitti.jpg

Since we have a lot clients who want lots of different things, often we've found ourselves wanting to make Krang do something different than what it does by default. It already has lots of customization hooks, but sometimes we've wanted just a few more.

Since it's OSS community is small it's pretty easy to get SVN access and commit the changes we've needed. Also, when we need to have something rolled out into production we can influence (and sometimes even outright control) the release schedule so that we have a version with the features and bug fixes we need for our clients. And it's not just our company that has this weight. All of the other companies that contribute heavily to Krang take advantage of this too.

Hate

A smaller community means less diversity and less structure. We don't have a project leader or even a project roadmap. We've done in-person meetings a couple of times that have always given blasts of energy to Krang development, but it's hard to sustain when the few core people have other things they need to do.

A smaller community also means there's less of a Krang eco-system. On larger projects beginners can get help from intermediate users who in turn can get help from experts. When you need to hire someone, you can put Wordpress, or Drupal experience on the job requirements because you know there's a large user base out there. There are even books written about using and developing for some of these Content Management Systems. While I hope this post brings more users into the Krang community, I'm realistic and know that I'm using a pretty obscure technology. I do sometimes ask myself whether it will come back to bite me down the road.

4 - All-in-One Installation

Love

Perl doesn't have a standard packaging system for deployment. Krang came into the OSS world in 2004 when projects like PAR were just getting started, so the developers at that time created their own custom way of packaging it. Krang comes bundled with it's own Apache, mod_perl, mod_ssl and a copy of every CPAN module it uses. This means deploying Krang is not a hunting expedition trying to round up all the dependencies nor digging through your Apache config to squeeze Krang in. Everything is built and installed together and doesn't affect anything else on your system.

This means we always have control over which versions of which Perl libraries a given install is using. We have complete control over the Apache/mod_perl configuration so we know that someone's custom setup isn't going to cause us problems. Every install of Krang is identical to every other install of that same version (minus any addons they have installed). This makes troubleshooting much easier than it would be otherwise. It also makes it easy for non sys-admins to install because you don't have to teach them about rpm or their OS's package manager, you just give them a simple ./bin/krang_install command to run and that's it.

Hate

A custom packaging system by definition means it's non-standard. You can't release Krang to CPAN, you can't turn it into an .rpm or .deb package (at least no easily). Any real sys-admin is going to give you the stink-eye when you tell them to install this application in a way that ignores all the other tools they use for managing their systems.

It also means that you have to learn and work around all of the platform specific problems that comes with building software. Krang does a pretty good job of this, but if we didn't have to worry about it we could definitely save developer time.

Another problem with a custom packaging system is that it's one more step for a new contributor to overcome. One more quirk to learn about our system before they can start submitting useful, tested patches.

5 - Simple Templating

Love

By default Krang uses HTML::Template (HTML::Template::Expr actually) both internally and for the publishing of stories. Users can control and edit these story templates for their sites and HTML::Template is pretty easy for them to learn. One of our addons provides some extra template functions to make things like number and date formatting easier.

Most people who can understand HTML can understand HTML::Template's syntax so we don't need too much training to get them up to speed. And most of the built-in operators and functions are simple enough to not cause the non-technical brain too much damage. Plus it's really fast.

Hate

Because of it's simplicity, HTML::Template lacks some constructs that would make life much easier. There's no C, no way to set/override variables, and no way to pass in container objects without making them into a loop. None of these are too painful, but they can make your templates more verbose and messier than you'd like.

Addon's are free to override the templating system and use their own if they'd like, but I'm not sure anyone really does this.

Conclusion

Even given it's warts, I really do like Krang. It lets my small team manage some really complicated sites and give a lot of power to our users that they couldn't get in another system. It also let's us split up the responsibilities nicely. Non-technical people can create and edit dynamic forms on their web sites, view reports on the activities on those forms and make adjustments. And the most important thing is that when they are doing it, they don't have to bother me to do it for them :)

clones.jpgI've recently been working on a fairly large project that that has contact information for almost 2 million people. These records contain details for both online and offline actions. Since the data can come from multiple sources there exist many duplicate records. Duplicate records mean more processing for our code, more storage space and more hassle for our clients who have to deal with these duplicates. All in all, bad things to leave lying around.

In this article we'll look at some strategies that I used to identify and remove these duplicates. All code in this article are samples, and we'll leave the task of assembling them into a final working program up to the reader.

CPAN is your Friend

Like all good Perl projects, we will make heavy use of the CPAN. It makes our lives so much easier and every day I'm more in awe at the quality and bredth of solutions I find there. For this project we'll be using Text::LevenshteinXS, Lingua::EN::Nickname and Parallel::ForkManager.

What is a Duplicate?

For our project we didn't want to automatically merge duplicates but rather flag them as being potential duplicates and then let our client choose to do the actual merge. Not only does this force a human to make the final decision but it also allows the client to determine which values for which conflicting fields are chosen for the final merged record.

To mark a pair of records as being potential duplicates we want to give them a score and then remember any pair that scored over a certain threshold. In our case the scores go from 0 to 100 and our threshold is 75. Each organization is different in what fields it has and what they consider to be a duplicate. Since some fields are more important than others (having the same state is not as important as having the same last name) we need to give our fields some weight. For this project we'll use the following fields and weights:

    my %field_weight = (
        last_name  => 25,
        first_name => 25,
        address1   => 20,
        address2   => 10,
        city       => 20,
    );


If the fields from 2 different records don't match (we ignore case for all matches because "peters" is the same thing as "PETERS") for a given field we subtract the given weight. You will of course have to play with these numbers for your own data.

Catching Typos

What if 2 people who are living at the same address have first names of "Michael" and "Michal"? They are most likely the same person and someone somewhere made a typo. One of the easiest ways to catch typos or strings that are almost identical is with an algorithm called a "Levenshtein Distance". You can read more about it if you want the specifics, but basically this algorithm calculates the number of changes needed to transform one string into another. In the case of "Michael" vs "Michal" the Levenshtein Distance is 1. The distance between "Michael" and "Michelle" is 3 and the distance between "Michael" and "Peters" is a whopping 7.

    use Text::LevenshteinXS qw(distance);
    my $distance = distance("Michael", "Michelle");


We're using Text::LevenshteinXS because it's simple and written in C (the "XS" part of the name means it's written in Perl's C API which is called XS).

More Weights

Since typos are usually 1 or 2 characters we don't really want anything with a distance of more than 3. But 1 is more likely to be a duplicate than is 3. So once again we'll use weighted values. For this project we'll use the following weights modifiers:

    my @distance_modifiers = (.10, .30, .45, .60, .90);


So if we're comparing our first_name fields and they have a Levenshtein Distance of 2, then we'll subtract 7.5 points (25 x .30). If that's the only difference between our two records then we'll have a total score of 92.5 which is a pretty good score.

    my $distance = distance($val1, $val2);
    $score -= $distance ? $field_weight{$field} * $distance_modifiers[$distance -1] : 0;


Nicknames

Nicknames are another problem we want to deal with. If we encounter 2 records that are similar but one has a first name of "Michael" and the other is "Mike" that won't score very well because it has a Levenshtein Distance of 4. It gets even worse when you look at examples like "Charles" and "Chuck". Our specific problem is made easier by the fact that almost all our our data is in English. CPAN comes to the rescue with Lingua::EN::Nickname. You can give it 2 names and it will give you a score that lets you know whether one is probably the nickname of the other.

    nickname_eq("Robert", "Bob"); # gives a score of 98


Having played with our data set more, we find that if the score is above 90 we are almost certain that it's a nickname and we treat it as if the names had matched exactly. If the score is between 80 and 90 we use the score as another modifier to the weight.

    my $nick_score = nickname_eq($val1, $val2);
    if( $nick_score < 90 && $nick_score > 80 ) {
        $score -= $field_weight{$field} * (1 - ($nick_score / 100));
    }


Abbreviations

We love to use abbreviations to make things shorter and easier to type. I can't remember the last time I entered my full street name in a web form. But to better find duplicates in our data we need to be able to consider "Drive" and "Dr." to be the same thing. You could use something like Geo::PostalAddress to normalize() the different addresses, but that was a little more processing than I wanted for this project.

So I just used a simple lookup hash based on the data I pulled from the US Postal Service (http://www.usps.com/ncsc/lookups/abbr_suffix.txt). I just took the abbreviations that were most common and our resulting address normalization looks something like this:

    my %ADDR_ABBR = (
        avenue     => 'ave',
        avn        => 'ave',
        boulevard  => 'blvd',
        circle     => 'cir',
        circ       => 'cir',
        court      => 'ct',
        crt        => 'ct',
        drive      => 'dr',
        driv       => 'dr',
        drv        => 'dr',
        ...
    );

    my @parts = split(/\s+/, $address);
    for(my $i=0; $i<=$#parts; $i++) {
        if( exists $ADDR_ABBR{$parts[$i]} ) {
            $parts[$i] = $ADDR_ABBR{$parts[$i]};
        }
    }

    $address = join(' ', @parts);


And now we can compare 2 addresses to get the Levenshtein distance without having to worry about common abbreviations throwing it off.

Multiple Cores and Multiple CPUS

Since this process will be running on a machine with multiple CPUs we want to take advantage of that. We are comparing each record to every other record so it's basically an N-squared algorithm. With millions of records this means the number of record comparisons will be in the trillions and would take way too long if we didn't take advantage of the extra CPUs on this machine. To split the work up I decided to take all of the data for a single US state and work on that as a group and then move on to the next state one by one.

This approach is trivially parallelizable so we should simply be able to fork off multiple processes and have them work on their own portion of the data. Duplicate scores will be recorded in the database so we don't even need any communication between the processes (in reality I used IPC::Shareable to communicate with the main process so that we could show a progress indicator of sorts when used from the command line, but this isn't necessary).

Using fork() under Unix isn't really that hard especially if you follow the canonical example in the Camel Book. But that's no reason it can't be made even simpler. I like Parallel::ForkManager because it makes it brain-dead simple to fork off a bunch of processes up to a some limit (for me this seemed to be the number of CPUs + 1). Then every time a child process finishes it takes care of forking another one to take it's place to do more work.

    my $fork_manager = Parallel::ForkManager->new($num_cpus + 1);
    while(my ($state) = get_next_state()) {
        # fork off and let a child handle this state
        my $pid = $fork_manager->start and next;

        process_state_records($state);
        $fork_manager->finish();
    }
    $fork_manager->wait_all_children;


Conclusions

While there are many ways to tackle this problem (and mine is far from the most optimal) I hope that this helps you to see the power of the CPAN when tackling big problems. It's hard to find a problem that someone else hasn't already faced and with the size and generosity of the Perl community, they've probably put at least some of the solution on to the CPAN.

At work, one of our latest projects is to offer a PDF download of some of our printed content, but before we do that, we want to ask for some contact information and then after that, we want to email the requesting user download information.

Amazon S3 offers a great way for us to offload the bandwidth consumption and at the same time, protect the content from (most) unauthorized downloads. There are a lot of steps I'm going to gloss over, in terms of how to set it up. The important (Perl) part I want to share with you is once you get a file up on Amazon S3, how can you generate one-off URL's to download the file?

The first thing is you'll need these 3 modules: Digest::HMAC_SHA1, MIME::Base64 and URI::Escape.

Then you'll also need your account identifiers, which you can find here. Grab your "Access Key ID" and your "Secret Access Key" ( it's the 40 character string you gotta slick on 'Show' to unhide). Let me strongly urge you or remind you that those account pieces are confidential and should not be shared. People can rack up some serious charges on your credit card or obtain illegal access to your data.

Ok, back to code. You'll first create your Digest::HMAC_SHA1 instance with your Amazon S3 "Secret Access Key":

my $hmac = Digest::HMAC_SHA1->new( <KEY> );
Then you need to figure out how long you want the URL to be available for - you'll need to figure out an epoch from which any request for the URL afterwards will no longer be available. Unfortunately, the epoch depends on whichever Amazon server is handling the request, so there's no really good way to get granular on the expiration. Or there might be, but I wasn't realy all-that-concerned. I just created an epoch 86400 seconds (1 day) in the future:

my $time = time() + 86400;
Now the last piece is a string of data that you have to put together to pass into the Digest::HMAC_SHA1 object. The string looks something like this:

my $string_to_sign = "GET\n\n\n$time\n/$bucket/$key"
Where $bucket is the bucket name and $key is the object name within the bucket. If you don't know what buckets and keys/objects are, check out Amazon's documentation.

Now you have everything you need ... add the $string_to_sign to the Digest::HMAC_SHA1 object, encode it, escape it:

$hmac->add( $string_to_sign );
my $digest = encode_base64( $hmac->digest, '' );
$digest = uri_escape_utf8( $digest, '^A-Za-z0-9_-' );
Then you just put together the URL:

my $url = "http://s3.amazonaws.com/$bucket/$key?AWSAccessKeyId=XXX&Expires=$time&Signature=$digest";
By the way, did you know that you can make your bucket name a domain name and then assign its CNAME to amazon so that the URL looks even more proprietary? Then the URL would look something like this:

my $url = "http://$bucket/$key?AWSAccessKeyId=XXX&Expires=$time&Signature=$digest";
There are some great-looking CPAN modules (Amazon::S3 and Net::Amazon::S3) that may already do this, but seeing how I didn't want to install Moose (for Net::Amazon::S3) for 10 lines of code, I opt'd to go my own route. There are many other way-more complicated things you can do w/ Amazon S3 and if you are doing more complex things, then the CPAN modules may be up your alley.

Cheers,

Jason

PS: I will be speaking at webinale in Berlin this May, so if anyone's in the area, come and check it out.
I know this is probably done a million times elsewhere, but I thought this approach was pretty neat. At work, we worry about spam harvesters collecting our addresses, so we want to hide them.

So today at work, I whipped this up pretty quickly, using Google's AJAX API Library + Prototype.

<html>
<head><title>Dynamic/Obfuscated Email Link Example</title></head>
<body>
<div>
<span class="add_email_link" id="jason">This should become an email link to me!</span>
</div>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
    google.load("prototype", "1.6.0.3");
    google.setOnLoadCallback( function() {
        // gather all .add_email_link's and add mailto links around their children
        $$('span.add_email_link').each( function( span ) {
            span.update( '<a href="mailto:' + span.id + '@example.com">' +
                span.innerHTML + '</a>' );
        } );
    } );
</script>
</body>
</html>

So ... guess this doesn't have anything to do w/ Perl, per se, but couldn't resist sharing. What about you? What technique do you use?

Peace,

Jason

Today I want to talk about how Perl helped the Human Genome Project.

The legend tells that somewhere in early February 1996, in Cambridge, England, in the largest DNA Sequencing centre in Europe, a meeting between scientists from Cambridge and from the largest DNA sequencing centre in the United States of America tried to solve a disconcerting problem: despite both DNA sequencing centres being using mainly the most laboratory techniques, databases, and data analysis tools, it was not possible to interchange data or meaningfully compare results between them.

The dimension of the Genome Project is respectable and would make an average DBA run for cover: estimates go up to 10 terabytes of information at the project completion, divided in complex and not so intuitive parts that make a lot of sense for molecular biologists, but not as much for a computer scientist.

From the software engineering point of view, managing the laboratory activity is a complex, ever-changing problem that drove a lot of development teams out of the road at the initial, monolithic implementations attempted. After a while, groups learned that modular, loosely-coupled systems that specialize on parts of the process and can be swapped around as the laboratory protocols and techniques used improve and change were a better implementation solution for the problem.

The utilization of those modular systems to analyse the DNA data was similar to a pipeline, and unix pipes were largely utilized to pass data between small processing programs.

A data interchange format was developed by the Whitehead Institute and the MIT Centre for Genome Research in order to easy the communication between those small pipelined analytic utilities. It's named Boulder. It eventually became the data interchange format used by all the DNA Sequencing Centres around the world.

The format itself is designed to be easily implemented using Perl strengths, and the implementation provided is, of course, Perl-based. Nowadays, implementations for other languages are also available.

The basic principle of the Boulder API is that all data is associated with tags. The API allows easy access to the tags the programmer is interested in from the standard input, and allows the programmer to add more tags to be passed along with all the data to the next program in the pipeline through the standard out.

The use of the Boulder library, the cooperation of many other Perl developers, and many other tools, the Genome Project succeeded. I am proud to say this would be all much difficult without Perl.

Today I will talk about music. Well, not exactly about music, but about all the hassle I used to go through whenever I wanted to tag the MPeg Layer 3 files I want to listen on my computer.

I used to do this labour-intensive, time-consuming, manual, repetitive task by hand, and commited a lot of mistakes in the past. I longed for a tool that would be able to automate this process and make my life simpler, being at the same time less time-consuming, fully automated, and leaving the repetitive stuff for my desktop computer do handle.

Probably all the noble readers of this Blog at least once in their lives had a thought like this before.

After some search and lots of talking with the Drunken Librarian, the solution finally came to me. And, guess what? It was implemented as a Perl-based meta information database about music, named MusicBrainz

As I presume that not all my noble readers know about this useful tool.

MusicBrainz describes himself as

(...) a user-maintained community music metadatabase. Music metadata is information such as the artist name, the release title, and the list of tracks that appear on a release. MusicBrainz collects this information about recordings and makes it available to the public. The web site is the interface which allows the creation and maintenance of the data. All of the data in MusicBrainz is user contributed and user maintained.

Well, definitions apart, MusicBrainz also have some impressive numbers associated with them: they hold information about 420,000 artists, and information about more than 630,000 releases of more than 250,000 albums. The community maintained by the service have thousands of active users, and hold a total of almost 7,000,000 editions since 2003 and answers to more than 500,000 queries a day from all over the world.

I use the service for about one year, and it usually surprises me, knowing about all unexpected and rare music and authors that I would have a hard time identifying by myself. It's a great service, quite reliable, running for more or less 10 years, and one that I say proudly that uses Perl.

About Steve Marvell

My name's Steve Marvell and I'm Proud to Use Perl.

I remember a day in the final term of University, some 13 years ago, when I asked a good friend of mine what I should learn next. He said "Learn Perl Steve" and so I did. This would have been around the time that Perl 5 came out. I learnt it with a pocket guide, at work and did some quite exciting things with next to no code. I was hooked.

Since then, I've worked pretty much exclusively with Perl for all manner of projects including Information Retrieval, Fraud Detection and Statistical Genetics. I presently run a small software engineering company which works almost exclusively with Perl.

I have been an on and off user of Perl Monks and started the Devon and Cornwall Perl Mongers user group which is pretty tiny, to say the least.

I've done quite a bit of book reviewing for O'Reilly and Manning and have an extra special mention in O'Reilly's Perl Graphics Programming, which I'm very proud of.


¡Hola!

Let me introduce myself as Yet-Another-Author of PTUP. I'm Michael Peters (mpeters on irc and use.perl, wonko on CPAN).

my $work == 'Plus Three';
my @interests = qw(
    qa-and-testing
    scaling-and-performance
    ui-design
);
my @tools = qw(
    CGI::Application
    mod_perl
    vim
    linux
    MySQL
    Prototype
    jQuery
    swish-e
    spread
);

my @projects = qw(
    Smolder
    Krang
);


I've lived and worked in Tennesee, Maryland (DC suburbs) and am now living with my family in Raleigh, NC. I've spoken at lots of YAPC::NAs (2008, 2007, 2006, 2005), a couple of ApacheCon's (US 2006, EU 2006) an OSCON (2007) and a PPW (2006). At my current job I do a little bit of management, technical planning, programming and system design.

The name of this blog gives the impression that it might be all about Perl evangelism. I'm not a good evangelist (even though I spent 2 years as a missionary) so I probably won't be providing a lot zingers to convince your coworkers to use Perl. I'm just planning on writing about how I'm using Perl: module reviews, Perl related tools and other things happening in the Perl community that make me excited.

Perl's not the coolest language around right now, but I've always been more of a fan of the underdog. I'm also an optimist which means that I'm really excited about the potential of Perl 6 and Parrot, so I'll probably be talking about those too.

Perl & JavaScript

While I didn't promise frequent posts, I want to keep the chatter alive on the site. Unfortunately, this post has very little to do w/ Perl, but it's not an anti-Perl post, either. I'm furiously at work on a paper for the Ajax in Action conference next week, where I'll be presenting selection criteria for JavaScript frameworks/libraries.

When you're a Perl Web developer, there comes a time when you have to start developing parts of your web application for the client. Unfortunately, PerlScript never really took off and so we walk down the road to JavaScript. Thus, a dichotomy is formed for our development work. Libraries make that easy, safe and reliable ... and not to mention, save us a ton of work. This keeps the percentage of your head attuned to things Perl at a majority, too.

When I return, I'll share slides and more thoughts. ;)

Peace,

Jason
When Dave Cross asked me to write for the Proud to Use Perl, I was unsure if I  would be able to. I'm not a native English speaker, and I couldn't think about what to write. The answer was right in front of my eyes all the time: I could write about the Proud To Use Perl website itself. This website is Perl Powered, and I don't have words in any of the four languages I speak to express how proud I am for being part of it.

Movable Type is an amazing piece of Open Source Software, licensed under the version 2 of the GPL. It's maintained by the nice people from Six Apart, with the help of a lot of Perl hackers with Perl skills and blog addiction.

It fills in an important niche of Internet applications in the competitive and highly visible blogging software market. His good quality, easy-to-use, and flexibility makes it a good option for big and small bloggers. Least but bot last, it probably pays the bills for people from Six Apart, or they would have dropped it long ago.

From the user perspective, it's easy to use, with a simple, intuitive and powerful interface. From the administrator point of view, it does The Right Thing(TM), supporting templates and static HTML generation (which scales ad infinitum) among other cool features.

I am proud to say that Proud To Use Perl uses Movable Type, a competitive, high-quality, useful, flexible, and economically viable Perl Application, and a great success among bloggers around the globe.

Authors

  • Dave Cross
  • Luis Motta Campos
  • Jason Purdy
  • Michael Peters
  • Steve Marvell

Recent Comments

Close