Textile2 0+1i

The very first release of a textile 2 plugin for Blosxom is now available, based on Brad Choate's MT Textile 2 beta.

This is beta, or worse. It's been tested on all of half a dozen documents. The underlying engine it uses is also beta. You should expect both the plugin syntax and the markup syntax to change.

To use:

  1. download mttextile-2_0b.zip from Brad Choate's page
  2. download textile2-0-1i.zip
  3. create lib and lib/Text directories in your plugin state directory2, if you don't have them. install extlib/Text/Textile.pm from mttextile-2_0b in that directory
  4. install textile2 from textile2-0-1i.zip in your plugin directory
  5. look at textile2's configuration variables, consider changing them
  6. install the meta plugin if you don't have it installed
  7. rename plugins with numeric prefixes to ensure proper ordering, if necessary. meta needs to be before textile2, and is required. If you're using it, SmartyPants needs to be after textile2. Although it's not as important (or necessarily right), most other plugins that do text changes probably should be after textile2; that would include macros, wikiwordish, imagesizer (which isn't actually needed, in its stock form), and the like.3
  8. create a test story with meta-markup: textile2 in its header
  9. hope

The textile2 syntax is both more regular and more extensive than the textile 1 syntax, and is intended to be at least mostly backwards compatible. In at least one way that matters to me, it isn't, though1, so this plugin is designed to be usable side-by-side with the earlier textile plugin. If you're willing & wanting to switch over entirely, configure the $handle_textile_1 variable to 1 and remove the textile plugin; then meta-markup: textile will invoke textile2.

1 With textile 1, there doesn't have to be any space between the final '!' on an image link and following text; with textile 2, there does.

2 That's your plugin directory, not your plugin state directory; thanks to Andy Fragen for the note.

3 This step added following Andy Fragen's difficulties -- thanks for being a guinea pig, Andy!

2003-07-27 09:14:00 | Comments (18) | TrackBack (0) | Computers::Internet::Web::Blosxom::Plugins::Textile

Textile 2 test post #1

That should be a h1 (well, h4, with my configuration)

this is a blockquote

this ia a normal paragraph

  1. this is
  2. a numbered
  3. list
  • this is
  • an unnumbered
  • list
this isa wikistyle table
with tworows andthree columns

Up to there, that's all textile-1 syntax too

this is a code block

this is a paragraph with id "first"

  1. Multi-level
  2. lists
    1. are now
    2. supported
  3. although
    1. it's not obvious
    2. how you would
  4. format them
    1. if you didn't have one
    2. parent item between
      1. each
      2. sublist

This is code here.

This is a test link

this should go back to first

bq.* Can blockquotes
* contain lists
* now?

2003-07-27 09:03:00 | Comments (1) | TrackBack (0) | Computers::Internet::Web::Blosxom::Plugins::Textile

Feedster Backlog and Blosxom

Feedster, a great RSS-based blog search engine, has a new Backlog feature; you create an RSS feed for the full history of your blog and tell Feedster about it, and it does a one-time load of the whole thing.

There are a few different possible ways for Blosxom bloggers to generate this feed.

The easiest way, for people who started their blogs this year, would to use the built-in date-filtering system; for example, http://molelog.molehill.org/blox/2003/index.rss is an rss feed of all my posts from 2003.

If you have pre-2003 entries, you'll have to be a little more clever. A minimal solution, which has some other possible uses, is to use a very small plugin like the following:

package numentries;
use CGI;
sub start {
  $blosxom::num_entries = CGI::param('numentries') 
    if defined CGI::param('numentries');
  1;
}
1;

then give Feedster an url like http://molelog.molehill.org/blox/index.rss?numentries=1000 (where '1000' is high enough to include all your entries).

I've done more or less that -- rather than create a whole plugin for that, I've just included that snippit in my catch-all plugins for small things like that, jtl.

Update: specified CGI::param rather than just param, as new versions of CGI.pm require.

2003-07-15 04:13:00 | Comments (0) | TrackBack (0) | Computers::Internet::Web::Blosxom

Blosxom Update Noodlings

Anthony Towns has a new blog, and he makes a pretty reasonable and interesting Blosxom suggestion

I think what would be nice is having blosxom see the files,

 -rw-r--r--    1 aj       aj            323 May 25 20:29 foo.txt
 -rw-r--r--    1 aj       aj             80 May 26 13:10 foo.txt-1
 -rw-r--r--    1 aj       aj            103 May 26 14:40 foo.txt-2

and magically translate that into an original entry, with two dated updates. You could then mark the files as uneditable once you've finished writing them, and not worry about accidently revising history.

A simple version of this would be pretty easy -- a plugin with a story() handler that looks for the -## files and just appends them, with an "Update ...:" header.

There are some interesting questions though about how it should act in the face of date sorting and specification; when showing index.html, should foo be listed as May 25 20:29 or May 26 14:40 (the former would be easier; the latter would be doable by supplying an entries()). When showing /2003/05/25 what should be shown? How about /2003/05/26?

2003-06-18 11:51:00 | Comments (5) | TrackBack (0) | Computers::Internet::Web::Blosxom

Blosxom Emacs Joy

Doug Alcorn had an emacs save-buffer-same-timestamp function, useful for editing Blosxom posts. I idly mentioned wanting to set it up to be auto-bound to C-x C-s for story files in my Blosxom tree, and before I could remember/figure out how to do that he posted an updated version.

LazyWeb wins again!

2003-05-16 14:23:00 | Comments (0) | TrackBack (0) | Computers::Internet::Web::Blosxom

I upgraded from Blosxom 1.x to 2.0, and plugins are acting just weird. Help!

I upgraded from Blosxom 1.x to 2.0, and plugins are acting weird. They're running, but...it's hard to describe. Sometimes they work, sometimes they don't. Any ideas what's going on?

One possible problem is that you copied & pasted your configuration variables, including the 'my' on those lines. In Blosxom 2.0, those need to be declared without 'my' so plugins can see them; if they have the 'my', they're private to blosxom, and plugins can't see the plog name, the data directory, etc.

2003-05-13 21:49:00 | Comments (0) | TrackBack (0) | Computers::Internet::Web::Blosxom::FAQ::BlosxomPlugins

Profiling Blosxom, Mark 0

On the Blosxom mailing list, Dave Walker asked about ways to profile Blosxom. There were a few suggestions, such as using time or Devel::SmallProf, but neither of those knows anything about how Blosxom works, and can't give information at very useful levels of detail (time isn't detailed enough; SmallProf is actually too detailed -- if all the time's going in Storable, you'd really rather know if it's from calendar or categories).

Frost Back pointed to the MTTimer Movable Type plugin and asked if anybody could port it.

I'm pretty sure the answer is "no" -- the plugin architectures are radically different, and MTTimer's tag-based approach just doesn't make any sense in a Blosxom world. That doesn't mean there aren't other ways of getting good information, though.

Presented here are two (count them: 1, 2 -- yes, two) completely and totally different ways to do Blosxom profiling. They both require Timer::HiRes but are believed to be otherwise dependancy-free.

Pure Plugin Profiling

The first one is for profiling a plugin at a time, and is minimally invasive; it uses a pair of plugins, "timer_start" and "timer_end". These plugins need to be named in such a way that they 'sandwich' the plugin you're interested in; for instance, if you have a plugin named '65wikiwordish' that you want to profile, you'd install these as '64timer_start' and '66timer_end'.

Together, they measure the time used in the sandwiched plugin's start, filter, head, date, story, foot, and end functions, and write the times out to standard error; usually, that will end up going to a log file.

This method isn't able to measure the time in 'entries', 'template' or 'interpolate', nor in the anonymous functions returned by those. As such, it isn't suitable for profiling plugins such as search (which uses entries), flavourdir (which uses template) or interpolate_conditional (which uses interpolate).

The output looks like (all on one line)

TIMER: date:0.003872 end:0.000100 filter:0.001381 foot:0.000099 head:0.000090 start:0.005967 story:0.012366

For best results, leave this running a while to get multiple result sets, rather than assuming the first one you see is representative. See below (after the invasive method) for information on a summarizing tool.

Incredibly Invasive Instrumentation

The second method replaces your whole blosxom.cgi script with one with lots of instrumentation added. It divides the whole Blosxom execution time up into multiple overlapping bits (in this version, 29 plus up to 9 per plugin). The 'instrumentation.txt' file included presents a hierarchical outline of how these bits relate to each other, but you'll likely need to dive into the blosxom.cgi source to figure out exactly what's included n what -- that's okay though, right, since f you aren't comfortable doing that you aren't trying to profile at that level anyway, right? right.

For each plugin, there's a "plugin_whole_name" bit, which includes all the time spent in the plugin, plus one "plugin_function_name" bit for each function the plugin actually uses; these may well be useful even without digging into the other bits.

The output format is the same as for the first method, except it's tagged with "TIMES" instead of "TIMER", and it's much much longer.

Summarizing

The included 'blos-times' script will the output of either of these (or both, comingled, optionally along with other stuff -- ie, it's okay to throw a whole error log at it), and produce possibly useful summary data. For each defined 'bit' it finds, it will display the minimum time, maximum time, total time, and the average time (mean) per run. Someone with more statistical interest than I might want to add median and standard deviation, but what's there is there.

Using

Download, unzip, and use. If you use the alternate blosxom script, make sure to configure it before you install it, and don't erase your real one. The longer you run it, the better the information you'll get from it, but it chews up disk space so keep an eye on it.

No software comes with a guarantee, and this is no different; that said, it's even less supported than most of my plugins, but it's presented in the hope of being useful or inspiring.

2003-05-13 19:22:00 | Comments (1) | TrackBack (0) | Computers::Internet::Web::Blosxom::Plugins::Profile

I'm using Blosxom 2.0rc2 and some plugins work but others just don't. Why?

I'm using Blosxom 2.0rc2 and some plugins, like 'meta' and 'SmartyPants' are working just fine, but others, like 'buy_from_amazon' and 'ping_weblogs_com' aren't; it's like they're not there at all! What the heck's going on?

You may be tripping over a perl bug; Perl 5.6.0 as shipped with Mac OS X 10.2 (Jaguar) has this problem, as do at least some compilations of 5.5_003.

To work around the bug, change line 149 of blosxom.cgi from

    my($plugin_name, $off) = $plugin =~ /^\d*(\w+?)(_)?$/;

to

    my($plugin_name, $off) = $plugin =~ /^\d*(\w+?)(_?)$/;

. (the only change is transposing the ')' and '?' at the end).

If you're interested in the details of the perl bug, read on; if not, feel free to stop here.

Still here? Okay.

The problem seems to lie in setting the values of capture variables (like $2) for parenthesis that don't match. In the original expression, the (_) doesn't match anything when the expression finally matches, so $2 should be undef; it's not, though, it's "_".

If you walk through the RE evaluator, there's a pretty plausible way this could happen -- at some point, the (\w+?) is matched against "ping_weblogs"; since the ? makes the + non-greedy, the matcher tries to make a match by continuing in the expression; it matches the final "_" against the (_), sets $2 to "_", and goes on, only to run into the "$"; since it's not at the end of the string, the evaluator backtracks to the last choice it made -- and it should clear out the capture variables it set on the way. Possibly as a slightly misguided optimization, it does not -- after all, it'll get set again if the expression matches, right? Finally, the evaluator's matched the whole "ping_weblogs_com" against the (\w+?), and it continues on; it doesn't match the "_" in "(_)", so doesn't set $2, but it turns out that's okay -- that whole group is optional. It gets to the "$", which matches, and it's done, we have a match! But $2 is still set to "_" from the earlier failed match attempt.

The fixed version works just alike, except the (_) isn't optional -- it always matches, it just sometimes matches the empty string. Thus, when the evaluator gets to the final match, and checks (_?) against the end of the string, the parenthesis DO match, and do get filled in -- with "".

This seems to be fixed in 5.6.1, and $2 is properly either "_" or undef in the original version of the expression; the changed version still works too (although the choices are now "_" or "").

This fix will be incorporated into 2.0rc3, due out any day now, so this FAQ entry will hopefully have a short shelf-life as such, but the details of the bug may stay interesting longer.

2003-05-01 16:30:00 | Comments (0) | TrackBack (0) | Computers::Internet::Web::Blosxom::FAQ::BlosxomPlugins

I added a stylesheet link, but my CSS isn't working. Why not?

<link rel="stylesheet" type="text/css" href="blosxom.css" />

A stylesheet link like that won't work with Blosxom for two related but different reasons.

First, it's using a relative URL for the stylesheet, but what that means will vary depending on how the page is accessed. http://molelog.molehill.org/blox/, http://molelog.molehill.org/blox/Computers/Internet/Web/Blosxom/FAQ and http://molelog.molehill.org/blox/2003/04/29/, for instance, will lead to three different meanings for what "blosxom.css" means (it's slightly worse than that, actually! http://molelog.molehill.org/blox/2003/04/29 leads to a fourth meaning for "blosxom.css").

So, you need to specify a full path for your stylesheet. But what full path? That leads to problem #2.

Blosxom serves up blog pages only; it doesn't serve up individual files. If you specified "$url/blosxom.css", Blosxom would go looking for the "blosxom.txt" story and the "css" flavour. Your stylesheet (as well as other related files, such as images) need to be put in a directory where the webserver can get to them directly, not via Blosxom, and you need to give a full path for that.

For instance, I use:

<link rel="stylesheet"
type="text/css"
href="/blog/flavours/$flavour/molelog.css"
title="Default">

2003-04-29 14:04:00 | Comments (1) | TrackBack (0) | Computers::Internet::Web::Blosxom::FAQ::BasicSetup

SeeError 0+1i

Most of my plugins' instructions include like "Look at your error log.". What if your hosting provider won't let you, though?

Well, first, consider getting a different hosting provider -- this one obviously isn't concerned with making it easy (or even possible) for you to do interesting work.

What if that's not an option, though?

Well, the SeeError plugin is a partial solution. In normaly use, it redirects all error output to a temporary file, then appends it to the end of the served page, and removes the temporary file.

If the $handle_die option is enabled, then any raised exceptions will cause a "Possibly-Fatal Error" message to be output to the browser, along wih whatever error text is available. This mode is useful if the only output you're otherwise getting is "fatal server error".

This is not a perfect solution. Drawbacks include, but may not be limited to:

  • error output before seemore is loaded is lost
  • error output after seemore's end() is called is lost
  • if there's a fatal error, no other error output will be printed, even if $handle_die is set; nor will the temporary file be cleaned up
  • this plugin can't be usefully controlled via blosxom's normal enable/disable mechanism; in particular, disabling it will appear to work but will lead to sustained disk-space loss as temporary files are created and not removed. do not leave this plugin installed but disabled.
  • the $handle_die option gives quite a bit of spurious output; it's invoked any time an eval fails, even though that's a perfectly normal occurance, and as far as I can tell it can't differentiate the important times from the unimportant.

Using:

  • download the plugin, unzip it, and put the plugin file in your plugin directory
  • turn on $handle_die if you need to (ie, if you're getting "Fatal server error" rather than blog output)
  • configure the $tmp_dir if you need to; the default should work for unix-like systems.
  • browse to your blog and scroll to the bottom; any error output will be appended. (Depending on your html formatting, you may actually need to look at the page source to see it)

2003-04-28 14:41:00 | Comments (0) | TrackBack (0) | Computers::Internet::Web::Blosxom::Plugins::SeeError

Automatic LuckyGoogle

Inspired by Danny O'Brien's lucky Google VIM macro, but being both an Emacs user and even lazier than him, I've whipped up some automatic lucky Google macros.

Proper nouns, acronyms, and anything in {{double braces}} gets linked to a Google search for that term, with the "I'm Feeling Lucky" option turned on.

I'm sure there's problems with them -- in particular, I'm worried about the proper noun one leading to nested <A>s -- but they seem to be working pretty well, and they're kinda spiffy, so here you go.

I may turn off the completely automatic ones after a while, but I think I'll be keeping the double braces.

Update: I'm now running a new version of these, with the following improvements:

  • the double-brace one matches inner-braces rather than leftmost-braces, making the display on my example look better
  • the REs are spread out and somewhat commented, using perl's /x mode, so there's some hope of understanding what they do
  • the nested <a> problem is taken care of. Unfortunately, this required a new feature in the macros plugin, a 'redo' flag, which causes the macro to keep being run over a block of text as long as it's still changing it; the nested-anchor stripper needs this to be able to deal with an arbitrary number of anchors within another anchor; for any specific maximum, you could just repeat the macro definition that many times.

If you want to use these now, you can as always grab a copy of the actual plugins that I'm running, but as those are by definition works-in-progress they're more likely to have problems (and be harder to install, and be underdocumented) than the real releases.

2003-04-18 10:38:00 | Comments (1) | TrackBack (0) | Computers::Internet::Web::Blosxom::Plugins::Macros

Why is my whole story ending up in the title?

You're probably using classic MacOS to create your stories, but MacOS X or some other Unix system to run Blosxom.

Normally on MacOS, text files' lines end with carriage returns, while on Unix they end with linefeeds. Thus when a MacOS text file is moved to a Unix machine without being translated (or vice versa), it looks like one long line with some funny characters in it.

The easiest way to translate files is to let your file transfer software do it for you -- in FTP clients, you want to transfer text files in 'text' mode as opposed to 'binary' or 'raw'.

Another option is to create and edit your stories with a text editor that can use either convention, and tell it to use Unix-style (linefeed) line endings.

2003-04-16 11:10:00 | Comments (0) | TrackBack (0) | Computers::Internet::Web::Blosxom::FAQ::BasicSetup

Calendar Plugin 0+6i

Calendar's been updated.

Feature changes:

  • New configuration variable $first_dow lets you control which day of week weeks start with
  • New variable $count available in templates, the number of stories in the day/week/month/year
  • Besides $year_calendar, year calendars are built for each year from the current year back to the first year with stories, named $year_calendar_2003 and so on.
  • The default templates include story counts in appropriate places.
  • When generating a month calendar for year with no month specified, choose the last month in the year with stories in it, rather than always choosing December; use December if the year has no stories at all.
  • When saving the cache, try to create the plugin state dir if it doesn't exist.
  • When counting stories, ignore any stories with a timestamp that matches $^T. This does mean that during the second a new story is posted, a generated calendar may not be quite right, but also makes the cache work much better with plugins that dynamically create 'stories' that shouldn't get counted, so long as they set the timestamp to $^T (such as a not-yet-released version of AutoCorrect) -- that's the whole point of these $^T changes.

Bug Fixes:

  • In month calendar, include 'week_foot' for partial last week, if there is one (ie, include the final <tr>)
  • Clear the cache if the day changes, not just when stories are added
  • Properly count the number of stories to tell when to clear the cache; 0+5i accidentally used the number of hash buckets filled rather than the number of items in the hash -- oops
  • If a year before 1970 is (apparently) requested, forcibly switch to year 2000 and log the full requested path, to try to figure out what causes this. Earlier versions would die when trying to build the month calendar. If you see "Bad year ... requested" lines logged, please let me know.

Changed for reasons only I care about:

  • Use $^T rather than time in various places

Things I'd like to be able to do, but can't reasonably without Blosxom changes:

  • use the built-in interpolation system, including any interpolate plugin that's installed
  • create months for appropriate dates in static mode

To install:

  1. download and unzip the plugin.
  2. Copy it to your plugins directory. Make sure it's world-readable.
  3. Modify a head or foot file to include $calendar::calendar, $calendar::month_calendar or $calendar::year_calendar
  4. Try it out — load your blog in your browser. If you see a calendar, great!
  5. Look at your error log. Verify you have an 'enabled' line.
  6. If you're wanting to verify caching is working, load the page again, and now look for an error log line "calendar debug 1: Using cached state"
  7. Once you're satisfied it's working, edit the $debug_level configuration variable to 0. There are a couple other configuration variables you may wish to change, too.
  8. Drop me a note to let me know you're using it; if you're having problems, let me know and I might be able to help. If everything's working okay, please let me know that, too.

Molelog is running this, with some customized templates and stylesheets.

Stylesheet:

.calendar { }
.calendar table {
	margin-left:		auto; 
	margin-right:		auto;
}
.calendar table .prev-link {
	margin-left:		0; 
	text-align:		left;
}
.calendar table .next-link {
	margin-right:		0;
	text-align:		right;
}
.month-calendar, .year-calendar {
	border-collapse:	collapse; 
}
.month-calendar-head, .year-calendar-head {
	font-size:		110%;
	font-weight:		bold;
}
.month-calendar-day-head, .year-calendar-subhead {
	font-weight:		normal;
}

.month-calendar {
	text-align: 		center;
}

.month-calendar-day-noday,
.month-calendar-day-link,
.month-calendar-day-nolink,
.month-calendar-day-this-day,
.month-calendar-day-future {
	font-family:		Georgia,New Century Schoolbook,Times,serif;
}

.year-calendar-month-link, 
.year-calendar-month-nolink,
.year-calendar-this-month, 
.year-calendar-month-future {
}

.month-calendar-day-future, .year-calendar-month-future {
	color:			#83660F;
}

.month-calendar {
	background:		#fff3de;
	border: 		1px solid #83660f;
}
.calendar th {
	border-bottom: 		1px dotted #83660f;
}
.Saturday {
	border-left:		1px dotted #83660f;
}
.Sunday {
	border-right:		1px dotted #83660f;
}
.Saturday, .Sunday {
	background:		#f5deb3;
}
.month-calendar-day-this-day, .year-calendar-this-month {
	background:		#a5e4ff;
}
.year-calendar {
	background:		#fff3de;
	border: 		1px dotted #83660f;
}

calendar.calendar.html":http://molelog.molehill.org/blog/flavours/html/":

<div class="calendar">
  <table>
    <tr>
      <td colspan="2">$calendar::month_calendar</td>
    </tr>
    <tr>
      <td class="prev-link">$prev_month_link</td>
      <td class="next-link">$next_month_link</td>
    </tr>
  </table>
  <table>
    <tr>
      <td>$calendar::year_calendar_2001</td>
      <td>$calendar::year_calendar_2002</td>
      <td>$calendar::year_calendar_2003</td>
    </tr>
  </table>
</div>

calendar.month_head.html:

<table class="month-calendar">
  <caption class="month-calendar-head">
    <a title="$monthname $year ($count stories)" href="$url">
      $monthname $year
    </a>
  </caption>

calendar.next_month_link.html:

<a title="$monthname $year ($count)" href="$url">
  $monthabbr '$year2digit&rarr;
</a>

calendar.next_month_nolink.html:

&rarr;
calendar.next_year_link.html:

<a title="$year ($count)" href="$url">
  '$year2digit &rarr;
</a>

calendar.next_year_nolink.html:

&rarr;

calendar.prev_month_link.html:

<a title="$monthname $year ($count)" href="$url">
  &larr; $monthabbr '$year2digit
</a>

calendar.prev_month_nolink.html:

&larr;

calendar.prev_year_link.html:

<a title="$year ($count)" href="$url">
  &larr; '$year2digit
</a>

calendar.prev_year_nolink.html:

&larr;

calendar.year_hear.html:

<table class="year-calendar">
  <caption class="year-calendar-head">
    <a title="$year ($count)" href="$url">$year</a>
  </caption>

2003-04-13 21:32:00 | Comments (20) | TrackBack (0) | Computers::Internet::Web::Blosxom::Plugins::Calendar

Classing External Links

Tamara asked on the Blosxom mailing list if my macros plugin was capable of making external links open in new windows like this.

My first answer was no -- it's missing two features that that uses, <MTIfMatches> and MTMacros' 'rebuild'. Furthermore, I don't really think MTIfMatches belongs in macros; it's a better fit for a somewhat fancier interpolate-conditional.

I'm not sure how exactly MTMacros' 'rebuild' works, and it may well be a useful feature to steal borrow...I should look at that.

I realized this morning that there is in fact a way, though; it's not quite as clean as Adam Kelsey's, since it's simply text based rather than tag-based, but it seems to work just fine.

The magic is in these macros (use the download link to get a good straight-text version):

define_macro({
  type => 'pattern',
  pattern => qr'<a\s(?![^>]*class)([^>]*href="/)'ms,
  body => '<a class="relative" ${1}',
  inhtml => 1
});

That looks for 'a' tags that don't have a 'class' attribute, with an 'href' attribute that starts with a slash, and adds a 'class="relative"' attribute.

define_macro({
  type => 'pattern',
  pattern => qr'<a\s(?![^>]*class)([^>]*href="http://[^/]*molehill\.org[:/])'ms,
  body => '<a class="local" ${1}',
  inhtml => 1
});

That looks for 'a' elements that don't have a 'class' attribute, with an 'href' attribute that starts with an a "http://", and has my domain name before the next / or :, and gives them a 'class="local"' attribute.

define_macro({
  type => 'pattern',
  pattern => qr'<a\s(?![^>]*class)([^>]*href)'ms,
  body => '<a class="remote" ${1}',
  inhtml => 1
});

That looks for 'a' elements that don't have a 'class' attribute, but do have an 'href' attribute (that prevents it from applying to anchors used just for naming); and gives them a 'class="remote"' attribute; that's right, since every non-remote link has been given a 'local' or 'relative' class.

I'm also using some stylesheet magic:

a.remote {
	padding-right:		12px;
	background-image:	url(/icon/aoutside.gif);
	background-position:	right;
	background-repeat:	no-repeat;
}

and an icon apparently from WebGragpics.

I didn't add "target" attributes, but it should be clear how to do that -- simply put them before the 'class' in the replacement text.

As I said, this isn't quite as clean, and it's not 100% correct -- the word "class" in an href could confuse it, for instance. But it's pretty close, and it's doable now. (it could be improved by replacing the (?![>]*class)s with (?![>]*\bclass=")s, but that still wouldn't be 100% right, and I wanted to present what I'm actually using and have tested).

2003-04-08 17:23:00 | Comments (3) | TrackBack (0) | Computers::Internet::Web::Blosxom::Plugins::Macros

AllConsuming Plugin 0+4i

The AllConsuming plugin has been updated.

Feature changes:

  • Per-list templates are possible; when loading a template bit <bit> in flavour <flavour> for list <list>, it first looks for allconsuming.<list>.<bit>.<flavour>; if not found, it then looks for allconsuming.<bit>.<flavour>, as before.

Bug fixes:

  • Better error reporting if LWP can't be loaded for some reason
  • Caching is optional -- for real this time, missed a bit in 0+3i, so it was actually always used. I still don't think you'd want to not use it, though.
  • If the plugin state dir doesn't exist, try to create it, and report an error if we can't.
  • don't die if a list is configured for random selection but is empty
  • Amazon Associate ID is a configuration variable, not embedded in the default templates -- for real this time; fixed it one place in 0+3i, but missed it anothre place (the cover image links)

Changed for reasons only I care about:

  • The perl variable '$^T' (time the script started) is used instead of 'time' (current time) in various places; this is marginally more efficient, but was really done for consistency with some other plugins where it matters more.

Installation:

  1. Verify you have the requirements for one of the networking implementations installed (SOAP::Lite or the LWP suite of modules or a 'curl' or 'wget' executable); if not, choose one to install
  2. Verify you have a Storable with lock_retrieve installed; if not, decide whether you really want to try to use this without caching, or install it.
  3. download and unzip the plugin.
  4. Copy the plugin to your plugins directory
  5. Configure the username variable; it won't do anything until you do. Configure your Amazon Associate ID if you have one.
  6. Add $allconsuming::reading, $allconsuming::finished, or the like to one of your flavour files. See the included POD documentation (perldoc allconsuming) for the complete list.
  7. Try it out -- load your blog in your browser.
  8. If everything is working, set $debug_level to 0; if not, check your error log to make sure the plugin is being loaded, and see if it's logging any errors
  9. Drop me a note letting me you're using it and how things are working for you.
  10. Enjoy!

Things still to do, still active from 0+1i:

  • locally cache the amazon image files, and supply the width and height; my previous non-plugin method did this, but I just haven't gotten to it for this.

Things I'd like to do that require Blosxom changes:

  • use the system interpolation system, getting the benefits of any interpolation plugins

Molelog is using this with some customized templates.

allconsuming.head.html:

<table class="allconsuming $listname">

allconsuming.item.html:

<tr>
  <td>
    <a href="http://www.amazon.com/exec/obidos/ASIN/$asin/$associate_id/ref=nosim">
    <cite>$title</cite></a>, $author
  </td>
</tr>

allconsuming.reading.item.html (this overrides the above allconsuming.item.html for just the 'reading' list):

<tr>
  <td>
    <a href="http://www.amazon.com/exec/obidos/ASIN/$asin/mtmolel-20/ref=nosim">
      <img border="0" src="$image" alt="$title Book cover">
    </a>
  </td>
  <td>
    <a href="http://www.amazon.com/exec/obidos/ASIN/$asin/$associate_id/ref=nosim">
    <cite>$title</cite></a>, $author
  </td>
</tr>

allconsuming.foot.html:

</table>

2003-04-06 18:27:00 | Comments (0) | TrackBack (0) | Computers::Internet::Web::Blosxom::Plugins::AllConsuming

AutoTrack problem with Some Trackback Implementations

According to the current Trackback spec, trackbacks should be sent with POST instead of GET, so that's what AutoTrack does.

Some Trackback implementations use URLs like "http://www.foo.com/bar/tb.cgi?tb_id=cats", though, with an embedded parameter. The spec is silent about what POSTing clients should do with these -- should AutoTrack parse the URL, recognize that it's setting a "tb_id" parameter, and add that to the POSTed parameters? If so, should it also leave it in the requested URL?

2003-04-05 13:48:00 | Comments (7) | TrackBack (0) | Computers::Internet::Web::Blosxom::Plugins::AutoTrack

Macros Plugin 0+1i

This is the first general release of my macros plugin, a highly generalized macro package modelled on (but not actually based on, code-wise) Brad Choate's MT-Macros package.

This release includes string macros, pattern macros, tag macros (html-like tags without content, like html's <img>) and content tag macros (html-like tags with content, like html's <a>...</a>). String and pattern macros may be restricted to only match in content areas, not in markup. Any macro can be set to only match once per story.

See the documentation in the plugin itself, or the macro files I actually use or that I test with, for documentation and examples of the syntax.

To install:

  1. download and unzip the plugin.
  2. Copy it to your plugins directory. Make sure it's world-readable.
  3. Create a $plugin_state_dir/.macros directory, and put macro definition files in it.
  4. Use it!
  5. Drop me a note to let me know you're using it; if you're having problems, let me know and I might be able to help. If everything's working okay, please let me know that, too.

Things that are missing (not all of them appear useful, though):

  • MT-Macros 'recursion' option isn't available. If this is a real problem for you, please let me know, preferably with a good example of what you can't accomplish currently (remember, macros are invoked in the order they're defined, which you can control with filename naming)
  • tag and ctag macros can't be used in HTML markup. This would be a big problem for Movable Type, where parameter replacement is done with psuedo-HTML, but doesn't seem to be a problem for Blosxom. If it is for you, please let me know, again along with an example.
  • MT-Macros 'no_case' option isn't available. This can be done by including (?i) in your patterns or defining them with qr//i, instead.
  • tag and ctag macros can't be explicitely named, because the 'name' parameter is already being used. Future versions may change tag and ctag to use 'string' or 'pattern' for what 'name' is currently used for, and use 'name' to define a macro. That will only be done if there's a good use for names, though.
  • Once defined, macros are always active. They can't be deactivated on a per-story basis. This might be handled with a meta- header at some point, if someone gives me a reasonable example for why they need it.
  • There's no built-in data-based macro definition syntax. It's not clear to me that a literal define_macro() call is any more difficult than MT-Macros' HTML-looking (but not HTML-acting) definition syntax, though, and as shown above simpler syntaxes ban be custom-built as appropriate. I'd be more than happy to include a simpler syntax, though, if someone were to develop one that were obviously better than define_syntax().

Plugins that I think could be replaced with this:

  • strip_unix_comments (pattern ^#.*?$ -> '')
  • asin
  • dictionary (macro definition file that reads the dictionary file to create macros)
  • citysearchtag
  • macrolinks
  • galleryref
  • amps

Plugins that can't be, but maybe should be -- missing functionality?

  • wikiwordish (would need to be able to invoke a user function to get replacement text)
  • functions (same as wikiwordish)
  • date_fullname (would need to be able to repalce text after interpolation, and to run against date as well as story)
  • date_translate
  • seemore (would need to be able to enable/disable macro based on $path or parameter)

2003-03-29 08:15:00 | Comments (2) | TrackBack (0) | Computers::Internet::Web::Blosxom::Plugins::Macros

AllConsuming Plugin 0+3i

The AllConsuming plugin has been updated (yes, again).

Changes:

  • Amazon Associate ID is a configuration variable, not embedded in the default templates
  • Multiple networking implementations: SOAP::Lite, LWP, wget, curl. The LWP, wget and curl implementations use AllConsuming's demonstration CGI script, which is presumably less supported and less stable than the SOAP interface.
  • Caching is optional (but I don't think you'd want to use it without it; it will at least not cause system errors if the plugin is installed but Storable isn't available).
  • HTML::Entities is optional; if it's not available, a simple implementation which just encodes '<', '&' and '>' is used.
  • Algorithm::Numerical::Shuffle is no longer required; the shuffle algorithm is included directly
  • For lists that are configured to not build (ie, $num{foo}=0), the data isn't even transferred.

Installation:

  1. Verify you have the requirements for one of the networking implementations installed (SOAP::Lite or the LWP suite of modules or a 'curl' or 'wget' executable); if not, choose one to install
  2. Verify you have a Storable with lock_retrieve installed; if not, decide whether you really want to try to use this, or install it.
  3. download and unzip the plugin.
  4. Copy the plugin to your plugins directory
  5. Configure the username variable; it won't do anything until you do. Configure your Amazon Associate ID if you have one.
  6. Add $allconsuming::reading, $allconsuming::finished, or the like to one of your flavour files. See the included POD documentation (perldoc allconsuming) for the complete list.
  7. Try it out -- load your blog in your browser.
  8. If everything is working, set $debug_level to 0; if not, check your error log to make sure the plugin is being loaded, and see if it's logging any errors
  9. Drop me a note letting me you're using it and how things are working for you.
  10. Enjoy!

Things still to do, still active from 0+1i:

  • locally cache the amazon image files, and supply the width and height; my previous non-plugin method did this, but I just haven't gotten to it for this.

Things I'd like to do that require Blosxom changes:

  • use the system interpolation system, getting the benefits of any interpolation plugins

2003-03-28 05:30:00 | Comments (0) | TrackBack (0) | Computers::Internet::Web::Blosxom::Plugins::AllConsuming

AllConsuming Plugin 0+2i

Update: There are newer versions available; please use the newest version unless you have a particular reason not to.

The AllConsuming plugin has been updated.

Changes:

  • several bugs in the default templates fixed (0+1i's are half table based and half list based -- oops)
  • typo fixed so shuffling actually works
  • Author and Titles are now HTML Entity encoded; this requires HTML::Entities
  • If a hash is returned where a list of hashes is expected, treat it as a 1-element list

Installation:

  1. Verify you have the necessary modules (SOAP::Lite, Algorithm::Numerical::Shuffle, CGI, Storable, HTML::Entities) installed; install them if not.
  2. download and unzip the plugin.
  3. Copy the plugin to your plugins directory
  4. Configure the username variable; it won't do anything until you do.
  5. Add $allconsuming::reading, $allconsuming::finished, or the like to one of your flavour files. See the included POD documentation (perldoc allconsuming) for the complete list.
  6. If you're an Amazon Associate, modify the template to use your ID instead of mine ('mtmolel-20'); if you aren't, but don't want to give me gratuitous hits, just remove the '/mtmolel-20' bit from the template
  7. Try it out -- load your blog in your browser.
  8. If everything is working, set $debug_level to 1; if not, check your error log to make sure the plugin is being loaded, and see if it's logging any errors
  9. Drop me a note letting me you're using it and how things are working for you.
  10. Enjoy!

Things still to do, all still active from 0+1i:

  • have a variable for the amazon associate ID rather than hardcoding mine in the default template -- oops, I meant to get that into the first release, honest.
  • locally cache the amazon image files, and supply the width and height; my previous non-plugin method did this, but I just haven't gotten to it for this.
  • use the (less-documented, less-official?) CGI-based AllConsuming API rather than the SOAP, and do XML parsing with regexes, to get the module requirements down to something sane.
  • if the above has been done, make the shuffling support optional, and don't require Shuffle if it's not wanted.
  • if/when blosxom supports it, use a plugged-in interpolate function, so interpolate-conditional can be used to conditionally include images based on the list (my previous non-plugin method did this, too, but there's no sane way to do it in a plugin, yet)

2003-03-27 20:19:00 | Comments (0) | TrackBack (0) | Computers::Internet::Web::Blosxom::Plugins::AllConsuming

AutoTrack 0+2i

AutoTrack has been updated

Interesting changes:

  • internal networking implementation using LWP; can still be configured to use curl if that's available but LWP isn't, and can also be configured to use wget 1.9beta or newer if it's available but neither LWP nor curl is.
  • the response to the ping is parsed, and errors are noticed and logged
  • if pings are attempted but all fail, the timestamp is reverted so they'll be tried again (if some succeed and some failed, though, the failed ones won't be retried)
  • if the meta plugin is installed properly, trackback ping URLs can be given with a meta-tb_ping header, for sites that don't have autodiscovery RDF, and "meta-autotrack: no" can be used to turn off autodiscovery for a story. (for this to work properly, the meta and autotrack plugin files must be named such that meta gets loaded earlier; otherwise, these headers will apply to the next story. ie, names like "10meta" and "90autotrack" are good; names like "meta" and "autotrack" will cause problems.
  • POD documentation is included

Installation

  1. make sure you have at least one of LWP, curl, and wget 1.9+ installed
  2. download and unzip the plugin.
  3. Copy the plugin to your plugins directory
  4. if you want to use the meta functionality, rename meta and/or autotrack with initial numbers to force the meta-before-autotrack order
  5. if you don't have LWP isntalled, configure $networking to use one of the other implementations
  6. Try it out -- load your blog in your browser, with ?autotrack=yes
  7. If everything is working, consider setting $debug_level to 0; if not, check your error log to make sure the plugin is being loaded. In semi_auto mode, there's no output at debug level 1unless the plugin is enabled, so you might want to leave it at 1.
  8. Drop me a note letting me you're using it and how things are working for you.
  9. Enjoy!

Barring bugs, I think this plugin is done; that makes bug reports all the more important, as this will otherwise be re-released as 1.0 soon.

2003-03-27 02:06:00 | Comments (46) | TrackBack (0) | Computers::Internet::Web::Blosxom::Plugins::AutoTrack

Categories Plugin 0+4i

Categories has been updated.

User-visible Interesting Changes, in rough order by interestingness:

  • new $indent template variable, which is the contents of the flavour file 'indent', repeated N times, where N is the depth of the current category
  • new template variable "$prettydir", is the name of the category with spaces added to CamelCaps and instead of underlines in underlined_names.
  • The top-level directory is now called "Root" by default, not "/", and it's configurable
  • uses the built-in templating system, including any template plugin that's installed
  • variables in templates can be interpolated with ${name} as well as $name
  • cached layouts are keyed based on flavour, so if you have template files that vary by flavour it will actually work now
  • cache is only enabled if the available Storable supports lock_retrieve
  • the cache is flushed every time a story is added, not every time the timestamp of the latest file changes; if caching is enabled, the category list (usually) now shows all the categories even if a filtering plugin (such as a search system) has reduced the number of visible files.
  • the $story_count_commulative configuration variable is now spelt $story_count_cumulative, to match the actual english language. Attempts to get enlish to change to match the plugin were unsuccessful.
  • requires Blosxom 2.0rc1 2.0rc2 or newer
  • the default templates are in the 'error' flavour rather than 'html', so they're used for any flavours that don't override them (the same effect was achieved a different way in 0+4i)

Thanks to:

  • Jason Hoffman, prodding me into XHTML validation
  • Robert Hahn, for the directory-name prettification
  • Colin Eric Johnson, for an HTML validation note
  • Earle Martin, HTML validation note

Things I'd like to be able to do, but can't reasonably without Blosxom changes:

  • use the built-in interpolation system, including any interpolate plugin that's installed

To install:

  1. download and unzip the plugin.
  2. Copy it to your plugins directory. Make sure it's world-readable.
  3. Modify a head or foot file to include $categories::categories or $categories::breadcrumbs
  4. Try it out — load your blog in your browser. If you see a category tree, great!
  5. Look at your error log. Verify you have an 'enabled' line.
  6. If you're wanting to verify caching is working, load the page again, and now look for an error log line "calendar debug 1: Using cached state"
  7. Once you're satisfied it's working, edit the $debug_level configuration variable to 0. There are a couple other configuration variables you may wish to change, too.
  8. Drop me a note to let me know you're using it; if you're having problems, let me know and I might be able to help. If everything's working okay, please let me know that, too.

Molelog is running this with some customized templates.

categories.breadcrumb_between_child.html:

|&#x200b;

categories.head.html:

<form name="cat" method="get" action="$url"> 
<!-- XXX any way to do this w/o js? -->
<script type="text/javascript">
function gotocat() {
 location = document.cat.cat.options[document.cat.cat.selectedIndex].value;
}
</script>
<select name="cat" onchange="gotocat()">

categories.indent.html:

&nbsp;&nbsp;&nbsp;

categories.dir_head.html:

<option value="$url/index.html">
  $indent$prettydir /
</option>

categories.this_dir_head.html:

<option selected value="$url/index.$blosxom::flavour">
  $indent$prettydir /
</option>

categories.foot.html:

</select></form>

categories.dir_foot.html, categories.subtree_head.html, categories.subtree_foot.html, categories.this_dir_head.html, and categories.this_dir_foot.html are all empty.

2003-03-25 15:33:00 | Comments (9) | TrackBack (0) | Computers::Internet::Web::Blosxom::Plugins::Categories

PostGraph 0+1i

Next plugin up (yes, I'm procrastinating before tackling the searchlinks -- I'm still not seeing a good solution for the race condition inherent in doing that in a plugin at reasonable speed): PostGraph.

This plugin creates the two graphs over there in my Archives box; the first style shows all posts since a given start date (or all posts, period); the second, just for the current month, but gives more detail on the exact times -- and is (intended to be) directly compatible with the Movable Type blogtimes plugin.

This plugin requires the GD and GD::Graph modules, because I'm both sane and lazy.

Installation

  1. Verify you have the necessary modules installed; install them if not.
  2. download and unzip the plugin.
  3. Copy the plugin to your plugins directory
  4. Configure the $destination_dir variable; it won't do anything until you do. to be useful, this needs to be a directory Blosxom can write to, that's visible through your webserver.
  5. Add <img src="..../graph.png"> or <img src="..../blogtimes.png"> to one of your template files
  6. Try it out -- load your blog in your browser, look for the graph.
  7. If everything is working, set $debug_level to 0; if not, check your error log to make sure the plugin is being loaded, and see if it's logging any errors
  8. Drop me a note letting me you're using it and how things are working for you.
  9. Enjoy!

Things still to do, maybe:

  • Fix the configuration so the width and height bits are treated the same -- they should both be either for the overall image or for the contained graph, not one one way and the other the other.

The BLOGTIMES-specific code is directly copied from code by Nilesh Chaudhari, but he's not responsible for any bugs I've introduced.

Molelog is using this with the following configuration:

$postgraph::destination_dir = $blosxom::datadir;
$postgraph::graph_start_day = "20030202";
$postgraph::graph_num_bars  = 24;
$postgraph::graph_width     = 200;
$postgraph::graph_height    = 100;
$postgraph::barcolor 	    = "#f5deb3";
$postgraph::bordercolor     = "#83660f";
$postgraph::outlinecolor    = "#83660f";
$postgraph::boxcolor 	    = "#fffbf0";
$postgraph::textcolor 	    = "#4f0000";
$postgraph::bt_width 	    = 165;
$postgraph::bt_height 	    = 30;
$postgraph::bt_linecolor    = '#83660f';
$postgraph::bt_textcolor    = '#4f0000';
$postgraph::bt_fillcolor    = '#f5deb3';
$postgraph::bt_bordercolor  = '#83660f';
$postgraph::bt_padding 	    = 5;
$postgraph::bt_show_text    = 1;
$postgraph::debug_level     = 2;

2003-03-25 05:20:00 | Comments (0) | TrackBack (0) | Computers::Internet::Web::Blosxom::Plugins::PostGraph

SeeMore Plugin 0+3i

SeeMore's been updated.

User-visible Interesting Changes, in rough order by interestingness:

  • new configuration item $more_on_article, on by default; if set, then single-article pages will show the whole article, not just the first part. This is good for people wanting summaries in index pages, not so good for people wanting spiler protection.
  • requires Blosxom 2.0rc1 2.0rc2 or newer
  • uses the built-in templating system, including any template plugin that's installed
  • variables in templates can be interpolated with ${name} as well as $name

Things I'd like to be able to do, but can't reasonably without Blosxom changes:

  • use the built-in interpolation system, including any interpolate plugin that's installed

To install:

  1. download and unzip the plugin.
  2. Copy it to your plugins directory. Make sure it's world-readable.
  3. Create a story with a formfeed (control-l) or "<;-- more -->" in it, and view it to see the "See more..." link
  4. Once you're satisfied it's working, edit the $debug_level configuration variable to 0. There are a couple other configuration variables you may wish to change, too.
  5. Drop me a note to let me know you're using it; if you're having problems, let me know and I might be able to help. If everything's working okay, please let me know that, too.

2003-03-24 21:07:00 | Comments (2) | TrackBack (0) | Computers::Internet::Web::Blosxom::Plugins::SeeMore

Blogroll Plugin 0+4i

Blogroll's been updated.

User-visible Interesting Changes, in rough order by interestingness:

  • in addition to $blogroll::blogroll, there's a variable for each input file, named after the file with all non-alphanumerics replaced with underscores (ie, $blosxom::com_ranchero_NetNewsWire_plist). This variable includes the items in the order they're in the file, includng any hierarchy (currently only NNW plist files support hierarchies).
  • NNW plist files with items split into hierarchical categories can be read
  • cached layouts are keyed based on flavour, so if you have template files that vary by flavour it will actually work now
  • $blosxom::debug contains the debugging output, for people who can't see system error logs
  • requires Blosxom 2.0rc1 2.0rc2 or newer
  • uses the built-in templating system, including any template plugin that's installed
  • variables in templates can be interpolated with ${name} as well as $name
  • cache is only enabled if the available Storable supports lock_retrieve
  • POD documentation is included

Things I'd like to be able to do, but can't reasonably without Blosxom changes:

  • use the built-in interpolation system, including any interpolate plugin that's installed

To install:

  1. download and unzip the plugin.
  2. Copy it to your plugins directory. Make sure it's world-readable.
  3. Modify a head or foot file to include $blogroll::blogroll.
  4. Create a .blogroll directory in your plugin state directory, and copy or symlink source files into it; if symlinking, be careful with permissions -- blosxom will need execute permissions for every directory along the path (this is particularly an issue for the NetNewsWire.plist file)
  5. Try it out — load your blog in your browser. If you see a blogroll, great!
  6. Look at your error log. Verify you have an 'enabled' line.
  7. If you're wanting to verify caching is working, load the page again, and now look for an error log line "blogroll debug 1: Loaded cache"
  8. Once you're satisfied it's working, edit the $debug_level configuration variable to 0. There are a couple other configuration variables you may wish to change, too.
  9. Drop me a note to let me know you're using it; if you're having problems, let me know and I might be able to help. If everything's working okay, please let me know that, too.

Molelog is running this, with some customized templates and stylesheets.

Stylesheet:

.blogroll {
	margin-left:		22px;
}
.blogroll-item {
	text-indent:		-22px;
}

blogroll.head.html:

<div class="blogroll">

blogroll.item_xml.html:

<div class="blogroll-item">
  <a href="$xmlurl">
    <img src="/blog/xml.gif" 
         width="18" height="7" border="0" 
         alt="XML">
  </a>
  &nbsp;
  <a href="$htmlurl">
    $title
  </a>
</div>

blogroll.item_no_xml.html:

<div class="blogroll-item">
  <img src="/blog/blank.gif" 
       width="18" height="7" border="0" 
       alt="No XML">
  &nbsp;
  <a href="$htmlurl">
    $title
  </a>
</div>

blogroll.foot.html:

</div>

2003-03-24 16:15:00 | Comments (3) | TrackBack (0) | Computers::Internet::Web::Blosxom::Plugins::Blogroll

Calendar Plugin 0+5i

Calendar's been updated.

User-visible Interesting Changes, in rough order by interestingness:

  • On single-article pageviews, create a calendar for the date of the article (this only works in dynamic mode currently, requires a Blosxom change to give full $path_info support in static mode)
  • requires Blosxom 2.0rc1 2.0rc2 or newer
  • uses the built-in templating system, including any template plugin that's installed
  • cached layouts are keyed based on flavour, so if you have template files that vary by flavour it will actually work now
  • variables in templates can be interpolated with ${name} as well as $name
  • with the default templates, the current day/month is only a link if there are stories for it
  • this_day template split into this_day_link and this_day_nolink
  • this_month template split into this_month_link and this_month_nolink
  • the default templates are in the 'error' flavour rather than 'html', so they're used for any flavours that don't override them (the same effect was achieved a different way in 0+4i)
  • cache is only enabled if the available Storable supports lock_retrieve
  • the cache is flushed every time a story is added, not once a day -- this is required for the this_day_link and this_month_link support

Things I'd like to be able to do, but can't reasonably without Blosxom changes:

  • use the built-in interpolation system, including any interpolate plugin that's installed
  • create months for appropriate dates in static mode

To install:

  1. download and unzip the plugin.
  2. Copy it to your plugins directory. Make sure it's world-readable.
  3. Modify a head or foot file to include $calendar::calendar, $calendar::month_calendar or $calendar::year_calendar
  4. Try it out — load your blog in your browser. If you see a category tree, great!
  5. Look at your error log. Verify you have an 'enabled' line.
  6. If you're wanting to verify caching is working, load the page again, and now look for an error log line "calendar debug 1: Using cached state"
  7. Once you're satisfied it's working, edit the $debug_level configuration variable to 0. There are a couple other configuration variables you may wish to change, too.
  8. Drop me a note to let me know you're using it; if you're having problems, let me know and I might be able to help. If everything's working okay, please let me know that, too.

Molelog is running this, with some customized templates and stylesheets.

Stylesheet:

.calendar { }
.month-calendar, .year-calendar {
	border-collapse:	collapse; 
}
.month-calendar-head, .year-calendar-head {
	font-size:		110%;
	font-weight:		bold;
}
.month-calendar-day-head, .year-calendar-subhead {
	font-weight:		normal;
/*	font-size:		80%; */
}

.month-calendar-day-noday,
.month-calendar-day-link,     .year-calendar-month-link,
.month-calendar-day-nolink,   .year-calendar-month-nolink,
.month-calendar-day-this-day, .year-calendar-this-month,
.month-calendar-day-future,   .year-calendar-month-future  {
	text-align:		center;
	font-family:		"Georgia", "New Century Schoolbook", "Times", serif;
}

.month-calendar-day-future, .year-calendar-month-future {
	color:			#83660F;
}

.Saturday, .Sunday {
	background:		#f5deb3;
}

.month-calendar-day-this-day, .year-calendar-this-month {
	background:		#a5e4ff;
}

calendar.calendar.html:

<div align="center" class="calendar">
  <table>
    <tr>
      <td colspan="2">$calendar::month_calendar</td>
      <td> </td>
      <td colspan="2">$calendar::year_calendar</td>
    </tr>
    <tr>
      <td align="left">$prev_month_link</td>
      <td align="right">$next_month_link</td>
      <td> </td>
      <td align="left">$prev_year_link</td>
      <td align="right">$next_year_link</td>
    </tr>
  </table>
</div>

calendar.month_head.html:

<table class="month-calendar">
  <caption class="month-calendar-head">
    <a title="$monthname $year" href="$url">$monthname</a>
  </caption>

calendar.year_head.html:

<table class="year-calendar"