--- /dev/null
+# Blosxom Plugin: absolute
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2.0b3-4
+# Documentation: See the bottom of this file or type: perldoc readme
+
+package absolute;
+
+# --- Configurable variables -----
+
+# What's the URL of your images directory?
+my $image_url = "";
+# e.g. http://www.example/images
+
+# What's the URL of your $datadir, if publicly-accessible?
+my $datadir_url = "";
+# e.g. http://www.example/blosxom
+
+# --------------------------------
+
+$image_url =~ s!/$!!; $datadir_url =~ s!/$!!;
+
+sub start {
+ 1;
+}
+
+sub story {
+ my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
+
+ $$body_ref =~ s!(<a.+?href\s*=\s*(["']))(/.+?)\2(.*?)>!$1$blosxom::url$3$2$4>!sig;
+
+ $image_url and $$body_ref =~ s!(<img.+?src=(["']))(/.+?)\2(.*?)>!$1$image_url$3$2$4>!sig;
+
+ $datadir_url and $$body_ref =~ s!(<img.+?src=(["']))([^\/]+?)\2(.*?)>!$1$datadir_url$path/$3$2$4>!sig;
+
+ return 1;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: absolute
+
+=head1 SYNOPSIS
+
+Replaces <a href="/relative/path/to/something.html"> with the fully-qualified/
+absolute <a href="$blosxom::url/relative/path/to/something.html">, especially
+important for RSS feeds, since most RSS readers don't make these absolute
+themselves.
+
+Optionally replaces <img src="/relative/path/to/image.gif"> with the
+fully-qualified/absolute <img src="$image_url/relative/path/to/image.gif">.
+
+For those who have their $datadir publicly-available (i.e. under their
+Web server's document root), also optionally adds fully-qualified/absolute
+paths to images. So mention of <img src="something.gif"> in
+/relative/path/to/something.txt will be replaced with
+<img src="$datadir_url/relative/path/to/something.gif">.
+
+The plug-in also should preserve any attributes included in the <a /> or
+<img /> tags.
+
+=head1 VERSION
+
+2.0b3-4
+
+Version number coincides with the version of Blosxom with which the
+current version was first bundled.
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: atomfeed -*-cperl-*-
+# Author(s): Original plugin: Rael Dornfest <rael@oreilly.com>
+# XML::Parser: Sam Ruby
+# UTC and <modified> fixes for 0.3: Frank Hecker
+# Enclosures support: Dave Slusher and Keith Irwin
+# Upgrade to Atom 1.0 spec: Sam Pearson
+# Version: 2005-08-04
+# Docs: Included below: type "perldoc atomfeed", or scroll down
+# Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+# Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+package atomfeed;
+
+# ----- Mandatory configurable variables -----
+
+# For a basic atom feed, you only need set $default_author and $feed_yr.
+# If you do not, the plugin will exit quietly.
+# All other configuration is optional, and can be safely ignored.
+
+# Who would you like your feed to credit as the default author of each entry?
+# Leave blank and the atomfeed plugin will attempt to use the whoami and
+# fauxami plugins
+$default_author = "";
+
+# What year was your weblog started? This will be used
+# to form part of your weblog's unique ID.
+$feed_yr = "";
+
+# ----- Optional configurable variables -----
+
+# What is the default author's URL?
+# Blank defaults to $blosxom::url
+$author_uri = "";
+
+# What is the default author's email address?
+# Leave blank to exclude.
+$author_email = '';
+
+# Copyright statement:
+# leave blank to exclude.
+$copyright = "";
+
+# What domain should Blosxom use in ID tags?
+# Leave blank if you don't understand or for Blosxom to use the domain in $url.
+$id_domain = "";
+
+# Feed url
+# Set the URL of the atom feed here. Defaults to $blosxom::url/index.atom
+$feed_url = "";
+
+# Icon
+# Put the URL for a site icon here (for example, your site's favicon). Leave blank to exclude.
+$icon_url = "";
+
+# Logo
+# Set to the URL for your site logo. Leave blank to exclude.
+$logo_url = "";
+
+# What template placeholder in your flavour template should I replace with feed-level <updated>?
+# If you are using the built-in templates, leave this alone.
+my $template_placeholder = "{{{updated}}}";
+
+# Enclosures support
+# ------------------
+
+# You can add enclosures to your atom feed by linking to them in your post
+# and giving the anchor tag a rel attribute of "enclosure".
+
+# Set $use_full_enclosures to 1 if you wish to add length and content-type
+# to your enclosures. This function relies upon your webserver having
+# LWP modules installed.
+$use_full_enclosures = '0';
+
+# Name of a file to cache info about your enclosures:
+$DataFile = "$blosxom::plugin_state_dir/enclosures.dat";
+
+# Stylesheet support
+# ------------------
+
+# If you have a stylesheet to associate with your atom feed, place it's URL here.
+$css_url = "";
+
+# You can specify the type of stylesheet here:
+$css_type = "text/css";
+
+# ----- END OF CONFIGURABLE VARIABLES -----
+
+# --- Plug-in package variables -----
+
+$author = '';
+$T = 'T';
+$colon = ':';
+$zerozero = '00';
+
+# Try to glean the domain from $url
+$id_domain or ($id_domain) = $blosxom::url =~ m#http://(?:www\.)?([^\/]+)#;
+
+$utc_date = '';
+$feed_utc_date = '';
+use vars qw/$feed_utc_date/;
+$category;
+$links;
+$summary;
+
+# ----- plugin subroutines -----
+
+sub start {
+
+ # Check for our two mandatory variables:
+ unless ( ( eval { whoami::start() or fauxami::start() } or $default_author ) and $feed_yr ) {
+ warn 'Blosxom plugin: atomfeed > Please set $default_author and $feed_yr. Exiting.\n';
+ return 0;
+ }
+
+ # Check for the existence of already-loaded flavour templates or theme,
+ # loading templates if there's nothing:
+ # Note that it looks like this condition should *never* be met, so why
+ # did Rael put this code here? Can't we just do _load_templates();
+
+ $blosxom::template{'atom'}{'head'} or _load_templates();
+
+ # changed to require from use to make plugin work for those
+ # without XML::Parser. Consequence: entries will never be labelled
+ # type='xhtml', only 'text' or 'html'. Thanks, S2!
+ eval { require XML::Parser; $parser = new XML::Parser; };
+
+ %escape = ('<'=>'<', '>'=>'>', '&'=>'&', '"'=>'"');
+ $escape_re = join '|' => keys %escape;
+
+ foreach ( keys %escape ) { $unescape{$escape{$_}} = $_; }
+ $unescape_re = join '|' => keys %unescape;
+
+ # If required, initialise the enclosures data cache:
+ $use_full_enclosures and _load_cache();
+
+ 1;
+}
+
+sub head {
+
+ # Make adjustments to plugin variables here, so that users
+ # can modify their defaults using the config and prefs plugins.
+ # Note that these plugins will have to run *before* atomfeed for this to work as intended.
+
+ $css_url and $css_url = "\n<?xml-stylesheet href=\"$css_url\" type=\"$css_type\"?>";
+
+ $feed_url or $feed_url = "$blosxom::url/index.atom";
+
+ $copyright and $copyright = "<rights>$copyright</rights>";
+
+ $author_uri or $author_uri = "$blosxom::url";
+ $author_uri = "<uri>$author_uri</uri>";
+
+ $author_email and $author_email = "\n <email>$author_email</email>";
+ $icon_url and $icon_url = "<icon>$icon_url</icon>";
+ $logo_url and $logo_url = "<logo>$logo_url</logo>";
+
+ # Check and prepare a <title> and <subtitle>:
+
+ ($blog_title_type, $blog_title) = _parse_markup($blosxom::blog_title);
+ ($blog_description_type, $blog_description) = _parse_markup($blosxom::blog_description);
+
+ 1;
+}
+
+
+sub story {
+ my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
+
+ use File::stat;
+
+ # set up <category>:
+ if ( $path ) {
+ $category = "<category term=\"$path\"/>";
+ }
+
+ # <published>: derive from %blosxom::files
+ my @published_utc = gmtime($blosxom::files{"$blosxom::datadir$path/$filename.$blosxom::file_extension"});
+ $published_utc_date = sprintf("%4d-%02d-%02dT%02d:%02d:00Z",
+ $published_utc[5]+1900,
+ $published_utc[4]+1,
+ $published_utc[3],
+ $published_utc[2],
+ $published_utc[1]);
+
+ # <updated>: derive by stat()ing the file for its mtime:
+ my @updated_utc = gmtime(stat("$blosxom::datadir$path/$filename.$blosxom::file_extension")->mtime);
+ $updated_utc_date = sprintf("%4d-%02d-%02dT%02d:%02d:00Z",
+ $updated_utc[5]+1900,
+ $updated_utc[4]+1,
+ $updated_utc[3],
+ $updated_utc[2],
+ $updated_utc[1]);
+
+ # Date/time of most recently-modified story becomes date/time of the feed.
+ $feed_utc_date = $updated_utc_date if $updated_utc_date > $feed_utc_date;
+
+ # use %blosxom::files for the year component of feed-level <atom:id>
+ # in case the creation time is cached somewhere.
+ $utc_yr = $published_utc[5]+1900;
+
+ # Set authorship if available, falling back to $atomfeed::author
+ $author = $whoami::fullname || $fauxami::name || $default_author || '';
+
+ # Setup $summary. Adapted from Rael's foreshortened plugin.
+ # For simplicities sake, we're going to provide plaint text summaries.
+ $summary = $$body_ref;
+ # first remove tags:
+ $summary =~ s/<.+?>//gs;
+ # then unescape any entities:
+ $summary =~ s/($unescape_re)/$unescape{$1}/g;
+ # truncate to what looks like first sentence:
+ $summary =~ s/[\.\!\?].+$/.../s;
+ # Remove newlines and carriage returns:
+ $summary =~ s/[\r\n]/ /g;
+ # Prepare for use in tempate:
+ $summary = "<summary type=\"text\">$summary</summary>";
+
+ # take look through $$body_ref for any enclosures or via/related links:
+ my @anchors = ( $$body_ref =~ /(<a [^>]+>)/gis );
+ $links = "\n";
+ foreach my $anchor ( @anchors ) {
+ if ( $anchor =~ /rel\s*=\s*"?\s*(via|enclosure|related)"?/is ) {
+ my( $type, $href );
+ $type = $1;
+ if ( $anchor =~ /href\s*=\s*"([^"]+)"/is ) {
+ $href = $1;
+ }
+ elsif ( $anchor =~ /href\s*=\s*([^\s]+)/is ) {
+ $href = $1;
+ }
+ if ( $href ){
+ $href =~ s/\s//g;
+ if ( $use_full_enclosures && ( $type eq "enclosure" ) ) {
+ my( $mime, $length );
+ # Check for presence of enclosure in $info:
+ unless ( $info->{$href} ) { _get_info($href); }
+ if ( $info->{$href} ) {
+ # Check again for data on enclosure in $info, just in case of problems getting it.
+ $mime = $info->{$href}->{type};
+ $length = $info->{$href}->{length};
+ $links .= " <link rel=\"$type\" href=\"$href\" type=\"$mime\" length=\"$length\"/>\n";
+ }
+ else {
+ # Fall back on a basic link:
+ $links .= " <link rel=\"$type\" href=\"$href\"/>\n";
+ }
+ }
+ else {
+ # Basic link:
+ $links .= " <link rel=\"$type\" href=\"$href\"/>\n";
+ }
+ }
+ }
+ }
+
+ # Parse post title:
+ ($title_type, $title) = _parse_markup($$title_ref);
+
+ # Parse the post body:
+ ($body_type, $body) = _parse_markup($$body_ref);
+
+ 1;
+}
+
+sub foot {
+ my($pkg, $currentdir, $foot_ref) = @_;
+ # Replace the placeholder with the feed-level <updated> element:
+ $feed_utc_date = "<updated>$feed_utc_date</updated>";
+ $blosxom::output =~ s/$template_placeholder/$feed_utc_date/m;
+ return 1;
+}
+
+# ----- private subroutines -----
+
+sub _parse_markup {
+
+ # Pass in some test to parse, and I'll return a type and the text suitably configured.
+ my $text = shift;
+ my $type;
+
+ # First, check to see if $text appears to contain markup.
+ # This regex should match any tag-like string: opening, closing or orphan tags.
+ if ( $text =~ m!</?[a-zA-Z0-9]+ ?/?>! ) {
+ # OK, looks like markup in there.
+ # Now, check to see if it looks well-formed:
+ if ( eval{$parser->parse("<div>$text</div>")}) {
+ # Yes? XHTML it is, then. I hope.
+ $type = 'xhtml';
+ $text = "<div xmlns=\"http://www.w3.org/1999/xhtml\">$text</div>";
+ }
+ else {
+ # No? Good old tag soup.
+ $type = 'html';
+ $text =~ s/($escape_re)/$escape{$1}/g;
+ }
+ }
+ else {
+ # We'll assume it's plaintext then.
+ $type = 'text';
+ }
+
+ # Out go the results:
+ return $type, $text;
+
+}
+
+sub _load_cache {
+ # Loads the data stored in $DataFile:
+ $info = {};
+ #open data file
+ local *FH;
+ if( -e "$DataFile") {
+ open FH, "$DataFile" or return $info;
+ }
+ flock(FH, 2);
+ while (<FH>) {
+ chomp ($_);
+ my ($url, $size, $type) = split (/ /, $_);
+ $info->{$url}->{length} = $size;
+ $info->{$url}->{type} = $type;
+ }
+ close (FH);
+ return $info;
+}
+
+sub _save_cache {
+ # Saves enclosure data structure in $info out to $DataFile
+ local *FH;
+ open FH, ">$DataFile" or return 0;
+ flock(FH, 2);
+ foreach $url (keys (%{$info})) {
+ print FH $url." ".$info->{$url}->{length} ." ". $info->{$url}->{type}."\n";
+ }
+ close FH;
+ return 1;
+}
+
+sub _get_info {
+ # Uses LWP to get content-type and content-length data
+ # for a given URL, adds this to the $info data structure
+ # and then calls _save_cache to preserve $info
+ return 0 unless eval "require LWP::UserAgent";
+ my $url = shift;
+ my $ua = LWP::UserAgent->new;
+ $ua->agent('BlosxomAtomFeed/0.5');
+ my $req = HTTP::Request->new(HEAD => "$url");
+ my $res = $ua->request($req);
+ my( $ct, $cl );
+ if ( $res->is_success ){
+ $ct = $res->header('content-type');
+ $cl = $res->header('content-length');
+ $info->{$url}->{type} = $ct;
+ $info->{$url}->{length} = $cl;
+ _save_cache();
+ return 1;
+ }
+ return 0;
+}
+
+sub _load_templates {
+ $blosxom::template{'atom'}{'content_type'} = 'application/atom+xml';
+
+ $blosxom::template{'atom'}{'date'} = "\n";
+
+ $blosxom::template{'atom'}{'head'} =<<'HEAD';
+<?xml version="1.0" encoding="utf-8"?>$atomfeed::css_url
+<feed xmlns="http://www.w3.org/2005/Atom" xml:base="http://$atomfeed::id_domain">
+ <title type="$atomfeed::blog_title_type">$atomfeed::blog_title</title>
+ <subtitle type="$atomfeed::blog_description_type">$atomfeed::blog_description</subtitle>
+ <link rel="self" type="application/atom+xml" href="$atomfeed::feed_url"/>
+ <link rel="alternate" type="text/html" hreflang="$blosxom::blog_language" href="$blosxom::url" />
+ <id>tag$atomfeed::colon$atomfeed::id_domain,$atomfeed::feed_yr$atomfeed::colon/$blosxom::path_info</id>
+ <generator uri="http://www.blosxom.com/" version="$blosxom::version">Blosxom</generator>
+ $atomfeed::copyright
+ $atomfeed::icon_url
+ $atomfeed::logo_url
+ {{{updated}}}
+HEAD
+
+ $blosxom::template{'atom'}{'story'} =<<'STORY';
+ <entry>
+ <id>tag$atomfeed::colon$atomfeed::id_domain,$atomfeed::utc_yr$atomfeed::colon$path/$fn</id>
+ <link rel="alternate" type="text/html" href="$blosxom::url$blosxom::path/$blosxom::fn.$blosxom::default_flavour" />$atomfeed::links
+ <title type="$atomfeed::title_type">$atomfeed::title</title>
+ <published>$atomfeed::published_utc_date</published>
+ <updated>$atomfeed::updated_utc_date</updated>
+ $atomfeed::category
+ <author>
+ <name>$atomfeed::author</name>
+ $atomfeed::author_uri$atomfeed::author_email
+ </author>
+ <content type="$atomfeed::body_type" xml:base="http://$atomfeed::id_domain" xml:lang="$blosxom::blog_language">
+$atomfeed::body
+ </content>
+ </entry>
+
+STORY
+
+ $blosxom::template{'atom'}{'foot'} =<<'FOOT';
+</feed>
+FOOT
+
+ 1;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: atomfeed
+
+=head1 SYNOPSIS
+
+Provides an Atom 1.0 feed of your weblog.
+
+The plugin has all you need right on-board, including the appropriate
+flavour template components and a couple-three configuration
+directives.
+
+It supports the majorty of the Atom 1.0 spec exluding the <source>
+element, which seems intended for use in feeds that contain items
+aggregated from other feeds, and currently the <contributor> element,
+which could be included using the meta plugin.
+
+Point you browser/Atom feed reader at http://yoururl/index.atom.
+
+=head1 VERSION
+
+2005-08-04
+
+=head1 AUTHORS
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+ - wrote the original plugin based on the 0.3 spec
+
+Sam Ruby <sam@intertwingly.net>, http://www.intertwingly.net/
+ - contributed the XML::Parser magic
+
+Frank Hecker <hecker@hecker.org>, http://www.hecker.org/
+ - contributed patches for Atom 0.3 compliance, UTC date/time fix
+
+Sam Pearson <sam@sgp.me.uk>, http://sgp.me.uk/
+ - Upgraded the plugin to handle Atom 1.0
+
+Additional code was incorporated in the Atom 1.0 revision from the
+enclosures plugin originally written by:
+
+Dave Slusher, http://www.evilgeniuschronicles.org/wordpress/ and Keith
+Irwin, http://www.asyserver.com/~kirwin/.
+
+=head1 QUICKSTART INSTALLATION
+
+To get an Atom feed up and running in a jiffy, you need only set the
+following variables and drop the plugin into your plugins directory:
+
+B<$default_author> is where you specify who to credit as the default
+author of each entry. This can be overidden with the value provided
+by the B<whoami> or B<fauxami> plugins.
+
+B<$feed_yr> is where you specify the year your site began. This is
+important as atomfeed needs to create a unique, unchanging ID for
+your weblog and it need this information to do so.
+
+Everything else is optional.
+
+=head1 FURTHER CONFIGURATION
+
+There are a lot of variables available in the plugin you can use to
+customise your Atom feed. These are all listed under B<CONFIGURABLE
+VARIABLES>, below, with some notes as to their intended usage. Some
+have defaults already specified, others will silently be excluded
+until you set them.
+
+As there are some variables generated entirely by the plugin, and as
+some of the configurable variables are modified by the plugin, there
+is also a complete list of all the variables available for use in
+templates with notes on their form under B<TEMPLATE VARIABLES>.
+
+If you wish to include enclosures or other types of <link> element in
+your feed, see the section B<ENCLOSURES AND LINK ELEMENTS>, below.
+
+Although you can use this plugin without anything other than blosxom
+itself and a standard perl installation, it will perform better with
+some optional extras available. See B<PERL MODULES> and B<OTHER
+PLUGINS> for more information, particularly if you intend to use the
+B<config> or B<prefs> plugins, any plugin that modifies your posts'
+actual content (particularly by introducing markup), or any plugin
+that operates on Blosxom's variable interpolation, such as
+B<interpolate_fancy>.
+
+=head1 CONFIGURABLE VARIABLES
+
+In addition to B<$default_author> and B<$feed_yr>, the plugin has the
+following user-configurable variables. Note that when setting
+variables that are to be used at feed level and that contain URLs, any
+relative URLs will be interpreted in relation to the value of the
+variable B<$id_domain>. This is also true of any URLs included in
+your posts.
+
+B<$author_uri> provides a URI for your default author. If you
+leave this blank, it defaults to B<$blosxom::url>.
+
+B<$author_email> Set this if you wish to include an email address for
+the author of each entry. Leave it blank to exclude this element of
+the feed.
+
+B<$copyright> Set this variable to a statement of copyright for your
+site. Leave blank to exclude.
+
+B<$id_domain> Atom associates unique ID tags with the feed itself and
+individual entries. By default it'll attempt to glean your domain
+from the specified or calculated value of B<$blosxom::url>, but you can
+override this by setting this variable.
+
+B<$feed_url> Atom feeds contain pointers to themselves, so you can set
+this variable to the location of your atom feed. If you leave in
+blank, it will use B<$blosxom::url/index.atom>, which in most cases will
+be correct.
+
+B<$icon_url> Set this variable to the URL of an icon to associate with
+your site. This should be a small image with a 1:1 aspect ratio -
+favicons are ideal. Leave blank to exclude.
+
+B<$logo_url> Set this variable to the URL of a logo to associate with
+your site. This can be larger than the icon, and should have an
+aspect ratio of 2:1. Leave blank to exclude.
+
+B<$template_placeholder> Set this varibale to the string used in your
+head.atom flavour template to identify where you would like the
+feed-level updated element to appear. If you are using the built-in
+templates, there is no need to change the default value.
+
+B<$use_full_enclosures> If you are including enclosures in your Atom
+feed, set this variable to 1 if you would like to include length and
+type attributes. This requires that you have the LWP modules
+installed on your webserver to work. See B<ENCLOSURES AND LINK
+ELEMENTS>, below, for more information.
+
+B<$DataFile> Set this variable to the name of a file where length and
+type data on your enclosures is stored.
+
+B<$css_url> Set this variable to the location of a stylesheet you
+would like to have applied to your Atom feed. Leave blank to exclude
+altogether.
+
+B<$css_type> Set this variable to the correct MIME type for the
+stylesheet you are including in your feed. Defaults to 'text/css'.
+
+=head1 TEMPLATE VARIABLES
+
+The following notes will be of use if you intend to create your own
+atom flavour templates.
+
+Note that some variables have the necessary markup included, while
+others do not; it is stated clearly when a variable contains the
+required markup. This is so that they can be included in templates
+without leaving empty elements when they are not required.
+
+B<$atomfeed::author> contains the contents for the author section's
+<name> element.
+
+B<$atomfeed::author_email> contains any <email> element for the
+author. Includes the required opening and closing tags.
+
+B<$atomfeed::author_uri> contains any <uri> element for the author.
+Includes the required opening and closing tags.
+
+B<$atomfeed::blog_description> contains the contents for the
+<subtitle> element.
+
+B<$atomfeed::blog_description_type> contains the value for the type
+attribute of the <subtitle> element of the feed.
+
+B<$atomfeed::blog_title> contains the title of your blog, suitably
+prepared for use as the content of the feed-level <title> element.
+
+B<$atomfeed::blog_title_type> contains the value required for the type
+attribute for the feed-level <title> element.
+
+B<$atomfeed::body> contains the full text of the body of your weblog
+post, suitably formatted for use as the contents of the <content>
+element.
+
+B<$atomfeed::body_type> contains the value for the type attribute of
+the <content> element.
+
+B<$atomfeed::category> contains a <category> for an entry, derived
+from a story's path. This variable contains the required opening and
+closing tags.
+
+B<$atomfeed::colon> simply contains a colon character, for use in the
+<id> elements - helps avoid confusion with variable interpolation.
+
+B<$atomfeed::copyright> contains any copyright statement. This
+variable includes the required opening and closing tags.
+
+B<$atomfeed::css_url> contains everything you need to link to a
+stylesheet, including the required opening and closing tags. Note
+that this element belongs before the opening <feed> tag, as it is a
+generic XML element.
+
+B<$atomfeed::feed_url> contains the value for the href attribute of a
+feed-level <link rel="self"> element which points back at the feed
+itself.
+
+B<$atomfeed::feed_yr> contains the year your weblog started.
+
+B<$atomfeed::icon_url> contains a complete <icon> element, including
+the required opening and closing tags.
+
+B<$atomfeed::id_domain> contains the root domain for your weblog.
+
+B<$atomfeed::links> contains all the via, related and enclosure links
+for an entry. This variable contains all the required markup.
+
+B<$atomfeed::logo_url> contains a complete <logo> element, including
+the required opening and closing tags.
+
+B<$atomfeed::published_utc_date> contains the timestamp for an entry
+based on the value stored in the B<%blosxom::files> hash.
+
+B<$atomfeed::summary> contains a trimmed <summary> element, including
+the opening and closing tags. Derived by truncating the entry down to
+the first sentence, similar to the B<foreshortened> plugin.
+
+B<$atomfeed::title> contains the contents for the story-level <title>
+element.
+
+B<$atomfeed::title_type> contains the value required for the type
+attribute of the story-level <title> element.
+
+B<$atomfeed::updated_utc_date> contains the timestamp for an entry
+based on a direct stat on the story file itself.
+
+B<$atomfeed::utc_yr> contains the year in which an entry was made,
+based upon the value stored in the B<%blosxom::files> hash.
+
+=head1 ENCLOSURES AND LINK ELEMENTS
+
+Atom provides an elegant method for expressing relationships between
+different resources using the rel attribute of its <link> element.
+This includes the method Atom uses to support enclosures, used to
+deliver additional content - often audio or video data - to the
+receipient of the feed.
+
+To take advantage of this, the plugin supports rel attribute values of
+via, related and enclosure. To have these included in your feed,
+simply link the the resource in the body of your weblog post and make
+sure that the anchor tag has an appropriate rel attribute of
+enclosure, via or related, depending upon the kind of relationship you
+are expressing.
+
+Ideally, enclosures should also contain information on their length
+(the size of the file) and MIME type. The atomfeed plugin will try to
+determine this information if you set the B<$use_full_enclosures>
+variable to '1'. To make sure this works correctly, you should link
+to the anclosure using an absolute URL rather than a relative one -
+"http://example.com/podcasts/july-05.mp3" instead of
+"/podcasts/july-05.mp3" - even if the enclosure is hosted under the
+same domain.
+
+If you are unsure as to whether your server has this module installed,
+you should be able to experiment by setting the variable anyway, as
+the plugin should continue to function even if it is not present.
+
+=head1 PERL MODULES
+
+This plugin will work at its best if your server has B<XML::Parser>
+and B<LWP> modules installed, although it will function adequately
+without them.
+
+=head1 OTHER PLUGINS
+
+In order for the <published> and <updated> timestamps to make sense,
+you should be running a plugin like B<entries_cache> that retains the
+original timestamps of your entries and places them into the
+B<%blosxom::files> hash. If you are not, you should remove the
+<published> element from the story template.
+
+The atomfeed plugin assumes you're not running any fancy interpolation
+plugin (e.g. B<interpolate_fancy>) which changes the way variables are
+specified in a template (e.g. <$foo /> rather than $foo). If you are
+running B<interpolate_fancy> or the like use the B<config> plugin and
+a config.atom file in your blosxom B<$datadir> consisting of:
+
+ $blosxom::plugins{"interpolate_fancy"} = 0;
+
+Where "interpolate_fancy" is the name of the interpolation plugin
+you're turning off _just for the atom feed_.
+
+If you are planning on using the B<config> or B<prefs> plugins to alter
+varibales in the atomfeed namespace, you will need to ensure that
+these plugins run B<before> the atomfeed plugin. You can do this by
+prefixing a number to the name of the relevant plugin, such as B<1config>
+or B<1prefs>.
+
+Similarly, if you are running any plugins that alter the content of
+your posts - for example by escaping characters or adding markup -
+these should also be set to run before atomfeed. Essentially, you
+want atomfeed to get each post as it would be sent to a normal web
+browser for it to work as intended.
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing:
+http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs:
+http://www.raelity.org/apps/blosxom/plugin.shtml
+
+1.0 Update Release Notes:
+http://sgp.me.uk/sam/2005/08/04/atom-for-blosxom
+
+Atom 1.0 Specification:
+http://atompub.org/2005/07/11/draft-ietf-atompub-format-10.html
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list:
+http://www.yahoogroups.com/group/blosxom
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: breadcrumbs
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2003-12-29
+# Documentation: See the bottom of this file or type: perldoc readme
+
+package breadcrumbs;
+
+# --- Configurable variables -----
+
+# Should I prepend a link back home to the path?
+# Specify a word to use for the link back to $blosxom::url or leave blank
+# to exclude it
+
+my $home = 'home';
+
+# What divider should I use between path components (e.g. a > path > to...)
+my $divider = " :: ";
+
+# --------------------------------
+
+$breadcrumbs; # use as $breadcrumbs::breadcrumbs in flavour templates
+
+use FileHandle;
+
+my $fh = new FileHandle;
+
+sub start {
+ 1;
+}
+
+sub head {
+ my($pkg, $path, $head_ref) = @_;
+
+ $path or return 0;
+ $path =~ s/\.$blosxom::flavour$//;
+
+ my(@p, $p);
+ $home and push @p, qq{<a href="$blosxom::url/index.$blosxom::flavour">$home</a>};
+
+ foreach ( split /\//, $path ) {
+ $p .= "/$_";
+
+ push @p,
+ $p ne "/$path"
+ ? qq{<a href="$blosxom::url$p/index.$blosxom::flavour">$_</a>}
+ : qq{$_};
+ }
+
+ $breadcrumbs = join $divider, @p;
+
+ return 1;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: breadcrumbs
+
+=head1 SYNOPSIS
+
+Populates $breadcrumbs::breadcrumbs with a clickable trail to
+your current path in the weblog hierarchy (a la Yahoo!).
+
+e.g. a/path/to/somewhere becomes
+<a href="/a">a</a> :: <a href="/a/path">path</a> :: ...
+
+Optionally prepends the path with a link back to home. Alter $home
+as you please, leaving it blank to turn off the link to home.
+
+=head1 VERSION
+
+2003-12-29
+
+Version number coincides with the version of Blosxom with which the
+current version was first bundled.
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: buy_from_amazon
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2.0b1
+# Documentation: See the bottom of this file or type: perldoc buy_from_amazon
+
+package buy_from_amazon;
+
+# --- Configurable variables -----
+
+# What is your Amazon Associate ID?
+my $associate_id = "raelitybytes-20";
+# If you're not an Amazon Associate, feel free to leave this as is ;-)
+
+# --------------------------------
+
+$amazon; # use as $buy_from_amazon::amazon in flavour templates
+
+sub start {
+ 1;
+}
+
+sub story {
+ my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
+
+ ($amazon) = $$body_ref =~ m!['"]http://www.amazon.com.+?/(\w+)/$associate_id.*?['"]!mg;
+
+ $amazon and $amazon = qq{<a href="http://buybox.amazon.com/exec/obidos/redirect?tag=$associate_id&link_code=xsc&creative=23424&camp=2025&path=/dt/assoc/tg/aa/xml/assoc/-/$amazon/$associate_id/ref=ac_bb6_,_amazon" onclick="window.open(this.href, 'buy from amazon', 'location=yes,scrollbars=yes,status=yes,toolbar=yes,resizable=yes,width=380,height=450,screenX=10,screenY=10,top=10,left=10'); return false;">buy from amazon</a>};
+
+ return 1;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: buy_from_amazon
+
+=head1 SYNOPSIS
+
+Purpose: Populates $buy_from_amazon::amazon with a link to
+Amazon Quick Click(TM) Buying for the first Amazon product
+link (if any) found in the current weblog story body.
+
+=head1 VERSION
+
+2.0b1
+
+Version number coincides with the version of Blosxom with which the
+current version was first bundled.
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: config
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2003-07-16
+# Documentation: See the bottom of this file or type: perldoc config
+
+package config;
+
+# --- Configurable variables -----
+
+# --------------------------------
+
+sub start {
+ 1;
+}
+
+sub head {
+
+ my $path = $blosxom::path_info;
+ $path &&= "/$path";
+
+ for (;;) {
+ do {
+ $blosxom::others{"$blosxom::datadir$path/config.$blosxom::flavour"} and eval { require "$blosxom::datadir$path/config.$blosxom::flavour" } and ( $@ ? warn $@ : last );
+ $blosxom::others{"$blosxom::datadir$path/config"} and eval { require "$blosxom::datadir$path/config" } and ( $@ ? warn $@ : last );
+ } while ($path =~ s/(\/*[^\/]*)$// and $1);
+ last;
+ }
+
+
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: config
+
+=head1 SYNOPSIS
+
+Override Blosxom's inline configuration settings on a per-directory, per-flavour, and per-directory-per-flavour basis.
+
+=head1 VERSION
+
+2003-07-16
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: cookies
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2003-03-20
+# Documentation: See the bottom of this file or type: perldoc cookies
+
+package cookies;
+
+# --- Configurable variables -----
+
+# What domain should I assign to cookies (e.g. .example.com, www.example.com)?
+# REQUIRED; if you don't fill in a domain, the plug-in won't work properly.
+$domain = '';
+
+# What path should I assign to cookies?
+$path = '/';
+
+# How soon should cookies expire?
+# (e.g. +1d is 1 day, +3m is 3 months, and +10y is 10 years from now)
+# Leave this blank and the cookie will expire when the browser is closed
+$expires = '+10y';
+
+# --------------------------------
+
+use CGI qw/:standard/;
+
+my %cookies = ();
+
+sub start {
+ foreach ( cookie() ) {
+ my %hash = cookie($_);
+ $cookies{$_} = \%hash;
+ }
+ 1;
+}
+
+sub foot {
+ my @cookies = values %cookies;
+ $blosxom::header->{'-cookie'} = \@cookies;
+
+ 1;
+}
+
+sub add {
+ foreach ( @_ ) {
+ my($name) = $_ =~ /^(.+?)=/;
+ $cookies{$name} = $_;
+ }
+ 1;
+}
+
+sub remove {
+ foreach ( @_ ) {
+ delete $cookies{$_};
+ }
+ 1;
+}
+
+sub clear {
+ foreach ( @_ ) {
+ $cookies{$_} = '';
+ }
+ 1;
+}
+
+sub get {
+ my($name) = @_;
+ return $name ? $cookies{$name} : \%cookies;
+}
+
+sub list {
+ return keys %cookies;
+}
+
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: cookies
+
+=head1 SYNOPSIS
+
+Provides basic cookie functionality for use by any number of Blosxom plug-ins.
+
+=head1 INSTALLATION & CONFIGURATION
+
+Drop the cookies plug-in into your Blosxom plugins directory.
+
+Be sure cookies is called last, giving all other plugins a chance to
+add, remove, and clear cookies before the the cookies plug-in returns the
+header to the browser. The easiest way to do this is to rename the plug-in
+9999cookies or the like, assuring that is sorted last, alphanumerically.
+
+Set a $domain for your cookies. I recommend using any host in your domain,
+e.g. .example.com, instead of just limiting to www, e.g. www.yourdomain.
+
+Assign a $path for your cookies. This should be the base path of your weblog.
+Use / if your weblog lives at the root of your domain (e.g. http://www.example.com/) or /weblog, for example, if it lives at a /weblog subpath (e.g. http://www.example.com/weblog).
+
+Set a time-out period for cookies. While there are various allowed forms
+for this expires piece (see perldoc CGI.pm), I like using +n(d,m,y) for
+n days, months, or years from now. For example: +1d is 1 day,
++3m is 3 months, and +10y is 10 years from now. The default is 10 years
+from now.
+
+=head1 USAGE
+
+As an end-user, once you have the cookies plug-in installed and configured,
+you're done.
+
+=head1 DEVELOPMENT
+
+Plug-in developers may use the cookies module as a base for cookie-usage
+by your own Blosxom plug-in. An example may be found in the writeback
+plug-in's use of cookies to remember the name and url of a person leaving a
+comment.
+
+All cookies are kept on a stack (in a %cookies hash, actually). Incoming
+cookies sent by the browser are automagically added to the %cookies stack
+in the start() subroutine.
+
+You have the following methods at your disposal:
+
+=item * add($cookie1, $cookie2, ...) adds a cookie to the stack to be sent to the client browser. Cookies should be well-formed; I suggest using the Perl CGI.pm module's cookie() subroutine to create each cookie.
+
+So that cookies can all be handled in the same manner by the cookies plug-in,
+you must use a hash as your cookie value, even if you only have one value to
+set.
+
+usage:
+
+&cookies::add(
+ cookie(
+ -name=>'plugin cookie 1'
+ -value=>{ 'some key' => 'some value' }
+ -path=>$cookies::path,
+ -domain=>$cookies::domain
+ )
+ cookie(
+ -name=>'plugin cookie 2',
+ -value=>{ 'first key' => 'first value', 'second key' => 'second value' }
+ -path=>$cookies::path,
+ -domain=>$cookies::domain
+ )
+);
+
+=item * remove('cookie name') removes a previously added cookie named 'cookie
+name' from the stack. Note, this does not unset the cookie in the client
+browser.
+
+usage:
+
+&cookies::remove('plugin cookie 1');
+
+=item * clear('cookie name') sets a blank value for the 'cookie name' cookie,
+thereby clearing it in the client browser.
+
+usage:
+
+&cookies::clear('plugin cookie 2');
+
+=item * list() lists the names of all cookies on the stack.
+
+usage:
+
+my @cookie_names = &cookies::list();
+
+=item * get() gets a reference to a hash {cookie name => cookie value} of all
+cookies on the stack. get('cookie name') gets a hash reference for the 'cookie name' cookie.
+
+usage:
+
+my $cookies = &cookies::get();
+my @cookie_names = keys %$cookies;
+
+my $particular_cookie = &cookies::get('cookie name');
+my $values = values %$particular_cookie;
+
+=head1 VERSION
+
+2003-03-20
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: date_fullname
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# and Tamara Crowe <tamara@darkglass.org>
+# Version: 2.0b4
+# Documentation: See the bottom of this file or type: perldoc date_fullname
+
+package date_fullname;
+
+# --- Configurable variables -----
+
+# A list of full month names rather than Jan, Feb, ...
+my @months = qw! 00 January February March April May June July August September October November December !;
+
+# A list of full day names rather than Mon, Tue, ...
+my %daysoftheweek = ( Mon=>'Monday', Tue=>'Tuesday', Wed=>'Wednesday', Thu=>'Thursday', Fri=>'Friday', Sat=>'Saturday', Sun=>'Sunday' );
+
+# --------------------------------
+
+$dw; # use $date_fullname::dw for full day-of-the-week name (e.g. Monday)
+$mo; # use $date_fullname::mo for full month name (e.g. January)
+
+sub start {
+ 1;
+}
+
+sub date {
+ my ($pkg, $path, $date_ref, $mtime, @date_bits) = @_;
+
+ $dw = $daysoftheweek{$date_bits[0]};
+ $mo = $months[$date_bits[2]];
+
+ 1;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: date_fullname
+
+=head1 SYNOPSIS
+
+Purpose: Populates $date_fullname::dw (day of the week) and
+$date_fullname::mo (month name) with full day and month names,
+respectively.
+
+=head1 VERSION
+
+2.0b4
+
+Version number coincides with the version of Blosxom with which the
+current version was first bundled.
+
+=head1 AUTHORS
+
+Rael Dornfest <rael@oreilly.com> and Tamara Crowe <tamara@darkglass.org>
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: date_translate
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2.0b2
+# Documentation: See the bottom of this file or type: perldoc date_translate
+
+package date_translate;
+
+# --- Configurable variables -----
+
+# A list of properly encoded month names in the language of your choice
+my @months = qw! 00 Janvier Février Mars Avril Mai Juin Juillet Août Septembre Octobre Novembre Décembre !;
+
+# A list of properly encoded day names in the language of your choice
+my %daysoftheweek = ( Mon=>'Lundi', Tue=>'Mardi', Wed=>'Mercredi', Thu=>'Jeudi', Fri=>'Vendredi', Sat=>'Samedi', Sun=>'Dimanche' );
+
+# --------------------------------
+
+$dw; # use $date_translate::dw for translated week day in flavour templates
+$mo; # use $date_translate::mo for translated month name in flavour templates
+
+sub start {
+ 1;
+}
+
+sub date {
+ my ($pkg, $path, $date_ref, $mtime, @date_bits) = @_;
+
+ $dw = $daysoftheweek{$date_bits[0]};
+ $mo = $months[$date_bits[2]];
+
+ 1;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: date_translate
+
+=head1 SYNOPSIS
+
+Purpose: Populates $date_translate::dw (day of the week) and
+$date_translate::mo (month name) with translated versions of the
+default English $dw and $mo. Default is French; alter in the
+Configurable variables section below.
+
+=head1 VERSION
+
+2.0b2
+
+Version number coincides with the version of Blosxom with which the
+current version was first bundled.
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: entries_index
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2003-03-23
+# Documentation: See the bottom of this file or type: perldoc entries_index
+
+package entries_index;
+
+# --- Configurable variables -----
+
+# --------------------------------
+
+use File::stat;
+use File::Find;
+use Data::Dumper;
+use CGI qw/:standard/;
+
+sub start {
+ 1;
+}
+
+sub entries {
+ return sub {
+ my(%files, %indexes);
+
+ if ( open ENTRIES, "$blosxom::plugin_state_dir/.entries_index.index" ) {
+ my $index = join '', <ENTRIES>;
+ close ENTRIES;
+ $index =~ /\$VAR1 = \{/ and eval($index) and !$@ and %files = %$VAR1;
+ }
+
+ my $reindex = 0;
+ for my $file (keys %files) { -f $file or do { $reindex++; delete $files{$file} }; }
+
+ find(
+ sub {
+ my $d;
+ my $curr_depth = $File::Find::dir =~ tr[/][];
+ if ( $blosxom::depth and $curr_depth > $blosxom::depth ) {
+ $files{$File::Find::name} and delete $files{$File::Find::name};
+ return;
+ }
+
+ $File::Find::name =~ m!^$blosxom::datadir/(?:(.*)/)?(.+)\.$blosxom::file_extension$!
+ and $2 ne 'index' and $2 !~ /^\./ and (-r $File::Find::name)
+ # to show or not to show future entries
+ and (
+ $blosxom::show_future_entries
+ or stat($File::Find::name)->mtime <= time
+ )
+ and ( $files{$File::Find::name} || ++$reindex )
+ and ( $files{$File::Find::name} = $files{$File::Find::name} || stat($File::Find::name)->mtime )
+ # Static
+ and (
+ param('-all')
+ or !-f "$blosxom::static_dir/$1/index." . $blosxom::static_flavours[0]
+ or stat("$blosxom::static_dir/$1/index." . $blosxom::static_flavours[0])->mtime < stat($File::Find::name)->mtime
+ )
+ and $indexes{$1} = 1
+ and $d = join('/', (blosxom::nice_date($files{$File::Find::name}))[5,2,3])
+ and $indexes{$d} = $d
+ and $blosxom::static_entries and $indexes{ ($1 ? "$1/" : '') . "$2.$blosxom::file_extension" } = 1;
+ }, $blosxom::datadir
+ );
+
+ if ( $reindex ) {
+ if ( open ENTRIES, "> $blosxom::plugin_state_dir/.entries_index.index" ) {
+ print ENTRIES Dumper \%files;
+ close ENTRIES;
+ } else {
+ warn "couldn't > $blosxom::plugin_state_dir/.entries_index.index: $!\n";
+ }
+ }
+
+ return (\%files, \%indexes);
+ };
+
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: entries_index
+
+=head1 SYNOPSIS
+
+Purpose: Preserves original creation timestamp on weblog entries,
+allowing for editing of entries without altering the original
+creation time.
+
+Maintains an index ($blosxom::plugin_state_dir/.entries_index.index) of
+filenames and their creation times. Adds new entries to the index
+the first time Blosxom encounters them (read: is run after their
+creation).
+
+Replaces the default $blosxom::entries subroutine
+
+=head1 VERSION
+
+2003-03-23
+
+Version number coincides with the version of Blosxom with which the
+current version was first bundled.
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: fauxami
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2.0b4
+# Documentation: See the bottom of this file or type: perldoc whoami
+
+package fauxami;
+
+# --- Configurable variables -----
+
+# What should I consider a delimiter between poster's name
+# and the rest of the filename (e.g. . for jack.story1.txt)?
+my $delimiter = '\.';
+
+# What should I fall back to as the default name (leave blank for none)?
+my $default_name = '';
+
+# --------------------------------
+
+$name;
+
+use File::stat;
+
+sub start {
+ 1;
+}
+
+sub story {
+ my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
+
+ $name = $filename =~ m!^(.+)$delimiter(.+)$! ? $1 : $default_name;
+
+ 1;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: fauxami
+
+=head1 SYNOPSIS
+
+Populates $fauxami::name with the "name" of the person
+posting the weblog entry, using anything before a specified delimiter
+( the default is . ) as the "name." So, jack.story1.txt would yield
+a $fauxami::name of jack and jill.story2.txt would yield a $fauxami::name
+of jill.
+
+You can optionally provide a $default_name, used when no faux name is
+specified.
+
+=head1 VERSION
+
+2.0b4
+
+Version number coincides with the version of Blosxom with which the
+current version was first bundled.
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: flavourdir
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2003-03-13
+# Documentation: See the bottom of this file or type: perldoc flavourdir
+
+package flavourdir;
+
+# --- Configurable variables -----
+
+# Where might I find your flavours?
+my $flavour_dir = "$blosxom::datadir/flavours";
+
+# Should I fall back to looking in your Blosxom datadir before using the
+# default built-in templates?
+# 0 = no; 1 = yes
+my $fallback_to_datadir = 0;
+
+# --------------------------------
+
+use FileHandle;
+my $fh = new FileHandle;
+
+sub start {
+ 1;
+}
+
+sub template {
+ return sub {
+ my ($path, $chunk, $flavour) = @_;
+
+ $path =~ s!^/*!!; $path = "/$path";
+
+ my $p = $path;
+ do {
+ return join '', <$fh> if $fh->open("< $flavour_dir/$p/$chunk.$flavour");
+ } while ($p =~ s/(\/*[^\/]*)$// and $1);
+
+ $p = $path;
+ $fallback_to_datadir and do {
+ return join '', <$fh> if $fh->open("< $blosxom::datadir/$p/$chunk.$flavour");
+ } while ($p =~ s/(\/*[^\/]*)$// and $1);
+
+ return join '', ($blosxom::template{$flavour}{$chunk} || $blosxom::template{error}{$chunk} || '');
+ };
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: flavourdir
+
+=head1 SYNOPSIS
+
+Keep your flavours in a separate flavour directory rather than alongside all of your weblog entries. Optionally falls back to the default of looking in your Blosxom datadir.
+
+Overrides Blosxom's default template() subroutine.
+
+Respects the Blosxom concept of finding flavours along specific paths, expecting to find these paths echoed in your flavour directory.
+
+=head1 INSTALLATION AND CONFIGURATION
+
+Drop the flavourdir plug-in into your Blosxom plugins folder.
+
+The plug-in is preconfigured to assume a flavour directory beneath your Blosxom data directory. Alter the $flavour_dir configurable variable to move it elsewhere.
+
+If you'd like the plug-in to fall back to looking in your Blosxom data directory if it doesn't find the appropriate flavour in your flavour directory, set the $fallback_to_datadir configurable variable to 1. Note: This results in additional processing and isn't a particularly efficient use of a plug-in's time.
+
+=head1 VERSION
+
+2003-03-13
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: foreshortened
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2.0b1
+# Documentation: See the bottom of this file or type: perldoc foreshortened
+
+package foreshortened;
+
+# --- Configurable variables -----
+
+# --------------------------------
+
+$body; # use as $foreshortened::body in flavour templates
+
+sub start {
+ 1;
+}
+
+sub story {
+ my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
+
+ $body = $$body_ref;
+ $body =~ s/<.+?>//gs;
+ $body =~ s/[\.\!\?].+$/.../s;
+
+ 1;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: foreshortened
+
+=head1 SYNOPSIS
+
+Purpose: Populates $foreshortened::body with the first sentence
+(defined as everything before the first ., !, or ?) and strips out
+HTML tags along the way. Perfect for providing shortened, plaintext
+versions of stories for an RSS feed.
+
+=head1 VERSION
+
+2.0b1
+
+Version number coincides with the version of Blosxom with which the
+current version was first bundled.
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: google_highlight
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2003-09-09
+# Documentation: See the bottom of this file or type: perldoc google_highlight
+
+package google_highlight;
+
+# --- Configurable variables -----
+
+# none, null, nada, nothing, zip, zero, zilch
+
+# --------------------------------
+
+my $query;
+
+sub start {
+ my $referer = $ENV{'HTTP_REFERER'};
+
+ ($query) = $referer =~ m#^http://(?:www\.)?google.*q=([^\&]+)#i or return 0;
+ $query =~ s#['"]##g;
+ $query = join '|', split /[\s,\+\.]+/, $query;
+
+ 1;
+}
+
+sub story {
+ my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
+
+ $$body_ref =~ s#(?<=>)([^<]+)?\b($query)\b#$1<span class="highlight">$2</span>#gis;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: google_highlight
+
+=head1 SYNOPSIS
+
+Highlights any Google search terms used to find your weblog.
+
+An adaptation of Dean Allen's [http://www.textism.com/] Google
+Hilite [http://www.textism.com/tools/google_hilite/].
+
+=head1 VERSION
+
+2003-09-09
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 INSTALLATION
+
+Drop the interpolate_fancy plug-in into your Blosxom plugins folder.
+
+Add a "highlight" style to your document or CSS style sheet, e.g.:
+
+<html>
+<head>
+<style>
+.highlight { background-color: #FF9; }
+</style>
+</head>
+<body>
+...
+</body>
+</html>
+
+=head1 USAGE
+
+Search Google for something that'll lead you to your weblog. Follow
+the Google link and notice the terms used in your search are highlighted
+in your weblog.
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://blosxom.sourceforge.net/
+
+Blosxom Plugin User Docs:
+ http://blosxom.sourceforge.net/documentation/users/plugins.html
+Blosxom Plugin Developer Docs:
+ http://blosxom.sourceforge.net/documentation/developers/plugins.html
+
+Dean Allen's Textism [http://www.textism.com/]
+Dean Allen's Google Hilite [http://www.textism.com/tools/google_hilite/]
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: google_sitesearch
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2.0b4
+# Documentation: See the bottom of this file or type: perldoc google_sitesearch
+
+package google_sitesearch;
+
+# --- Configurable variables -----
+
+# What text should appear on your Search button?
+
+# To which domain(s) would you like to restrict your Google SiteSearch?
+# (Defaults to what you set as your Blosxom $url)
+
+my $domains = "";
+
+# What customization bits were included in the "cof" field when
+# you signed up for your free Google SiteSearch?
+
+my $cof = "";
+
+# --------------------------------
+
+$searchbox; # use as $google_sitesearch::searchbox in flavour templates
+
+sub start {
+
+ $domains ||= $blosxom::url;
+ $domains =~ s!^\w+?://!!; # get rid of the http:// bit
+
+ $searchbox = <<"SEARCHBOX";
+<!-- Search Google -->
+<form method="GET" action="http://www.google.com/custom">
+<a href="http://www.google.com/"><img src="http://www.google.com/logos/Logo_40wht.gif" border="0" alt="Google"></a>
+<br />
+<input name="q" type="text" size="25" maxlength="255" />
+<br />
+<input type="submit" name="sa" value="Google Search" />
+<input type="hidden" name="domains" value="$domains">
+<input type="hidden" name="cof" VALUE="$cof">
+<br>
+<font face=arial,sans-serif size=-1>
+<input type="radio" name="sitesearch" value="" checked />Search WWW
+<input type="radio" name="sitesearch" value="$domains" />Search $blosxom::blog_title
+</font>
+</form>
+<!-- Search Google -->
+SEARCHBOX
+
+ 0; # No need to continue; we're done.
+}
+
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: google_sitesearch
+
+=head1 SYNOPSIS
+
+Provides Google Free SiteSearch [http://www.google.com/services/free.html]
+for your weblog.
+
+=head1 INSTALLATION
+
+Drop the google_sitesearch plug-in into your plugins directory.
+
+Use $google_sitesearch::searchbox anywhere in your flavour templates you wish.
+
+=head1 CONFIGURATION
+
+The google_sitesearch plug-in assumes you've signed up for Google's Free
+SiteSearch [http://www.google.com/services/free.html] for your site.
+
+The plug-in will just work out of the box without any configuration.
+That said, it's probably best to apply any configuration settings you
+made when you signed up for Google SiteSearch in the Configurable
+Variables section.
+
+While $domains defaults to something intelligent -- your Blosxom $url
+sans the http:// bit -- you might fill in whatever values appear in
+the domains field of the form Google created for you when you signed
+up.
+
+e.g. <INPUT type=hidden name=domains value="example">
+
+Simply paste everything between the "" between the "" of $domains in the
+Configurable Variables section.
+
+Also, Google Free SiteSearch allows you to customize the look-and-feel
+of your results pages. If you'd like, you can set $cof to the value
+appearing in the cof field of the form Google created for you when
+you signed up.
+
+e.g. <INPUT type=hidden name=cof VALUE="GIMP:#666666;T:#666666;ALC:#666666;L:http://www.example/images/example.gif;GFNT:#666666;LC:#666666;BGC:#dddddd;AH:center;VLC:#666666;GL:1;S:http://www.example/;GALT:#666666;AWFID:2498b45f59b093e3;">
+
+Simply paste everything between the "" between the "" of $cof in the
+Configurable Variables section.
+
+=head1 VERSION
+
+2.0b4-5
+
+Version number coincides with the version of Blosxom with which the
+current version was first bundled.
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: interpolate_conditional
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2003-05-16
+# Documentation: See the bottom of this file or type:
+# perldoc interpolate_conditional
+
+package interpolate_conditional;
+
+# --- Configurable variables -----
+
+# --------------------------------
+
+sub start {
+ 1;
+}
+
+sub interpolate {
+ return sub {
+
+ package blosxom;
+
+ my $template = shift;
+
+ # defined
+ $template =~ s#\?\{(\$\w+(?:::)?\w*) (.*?)\}#"defined $1 ? \$2 : ''"#gee;
+
+ # not defined
+ $template =~ s#\?\{!(\$\w+(?:::)?\w*) (.*?)\}#"!defined $1 ? \$2 : ''"#gee;
+
+ # not equal to
+ $template =~ s#\?\{(\$\w+(?:::)?\w*)!=(.*?) (.*?)\}#"defined $1 and $1 ne '$2' ? \$3 : ''"#gee;
+
+ # equal to
+ $template =~ s#\?\{(\$\w+(?:::)?\w*)=(.*?) (.*?)\}#"defined $1 and $1 eq '$2' ? \$3 : ''"#gee;
+
+ # greater than
+ $template =~ s#\?\{(\$\w+(?:::)?\w*)>(.*?) (.*?)\}#"defined $1 and $1 gt '$2' ? \$3 : ''"#gee;
+
+ # less than
+ $template =~ s#\?\{(\$\w+(?:::)?\w*)<(.*?) (.*?)\}#"defined $1 and $1 lt '$2' ? \$3 : ''"#gee;
+
+ # unconditional (and recursive)
+ while( $template =~ s/(\$[a-zA-Z]\w+(?:::)?\w*)/"defined $1 ? $1 : ''"/gee ) { }
+
+ return $template;
+
+ };
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: interpolate_conditional
+
+=head1 SYNOPSIS
+
+Include bits of text and template variable values in templates based on
+one or more of the following conditions:
+
+ * Unconditionally (and recursively), just as with the Blosxom default
+
+ e.g. include a link to the story's path using various template variables.
+
+ <a href="$url$path">$path</a>
+
+ * The template variable has a value (i.e. is defined)
+
+ e.g. include a hyperlink to the story's path if it has a path (i.e.
+ $path is defined).
+
+ ?{$path <a href="$url$path">$path</a>}
+
+ * The template variable doesn't have a value (i.e. is NOT defined)
+
+ e.g. include a hyperlink to home if path is undefined.
+
+ ?{!$path <a href="$url">/</a>}
+
+ * The template variable is equal (=) to a particular value
+
+ e.g. include "1 writeback" (singular) if the value of writeback count is 1
+
+ ?{$writeback::count=1 $writeback::count writeback}
+
+ * The template variable is not equal (!=) to a particular value
+
+ e.g. include "x writebacks" (plural) if the value of writeback
+ count (x) is not 1
+
+ ?{$writeback::count!=1 $writeback::count writebacks}
+
+ * The template variable is less than (<) a particular value
+
+ e.g. include "no writebacks" if the value of writeback count is < 1
+
+ ?{$writeback::count<1 no writebacks}
+
+ * The template variable is greater than (>) a particular value
+
+ e.g. include "oodles of writebacks" if the value of writeback count is > 50
+
+ ?{$writeback::count>50 oodles of writebacks}
+
+Overrides Blosxom's default interpolate() subroutine.
+
+=head1 INSTALLATION
+
+Drop the interpolate_conditional plug-in into your Blosxom plugins folder.
+
+=head1 VERSION
+
+2003-05-16
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 ACKNOWLEDGEMENTS
+
+Eric David Sherman, for < and >
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: interpolate_fancy
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2003-09-09:12:10
+# Documentation: See the bottom of this file or type:
+# perldoc interpolate_fancy
+
+package interpolate_fancy;
+
+# --- Configurable variables -----
+
+# Do you want me to recursively interpolate into the story $title
+# and $body? Consider and reconsider carefully before turning this
+# on as if anyone other than you has the ability to post stories,
+# there's a chance of some tomfoolery, exposing variables and calling
+# actions/subroutines you might not want called.
+# 0 = No (default), 1 = Yes
+my $recurse_into_story = 0;
+
+# --------------------------------
+
+sub start {
+ 1;
+}
+
+sub interpolate {
+ return sub {
+
+ package blosxom;
+
+ # Halt recursive interpolation of story $body
+ # by mangling interpolation tags (to be unmangled in a moment)
+ unless ($recurse_into_story) {
+ $blosxom::title =~ s/<(\@|\??\$)/<#INTERPOLATE_FANCY_DEFANG#$1/gsi;
+ $blosxom::body =~ s/<(\@|\??\$)/<#INTERPOLATE_FANCY_DEFANG#$1/gsi;
+ }
+
+ my $template = shift;
+
+ # Backward Compatibility with core Blosxom style interpolation
+ $template =~ s#(?<!<)(?<!<\?)(?<!<\?!)(\$\w+(?:::)?\w*)#<$1 />#gs;
+
+ # Defined
+ # e.g. <?$var>display if defined</?>
+ $template =~ s#<\?(\$\w+(?:::)?\w*)>(.*?)<\/\?>#"defined $1 ? \$2 : undef"#gsee;
+
+ # Undefined
+ # e.g. <?!$var>display if not defined</?>
+ $template =~ s#<\?!(\$\w+(?:::)?\w*)>(.*?)<\/\?>#"!defined $1 ? \$2 : undef"#gsee;
+
+ # Tests
+ # eq (eq), ne (ne), lt (<), gt (>), like (=~), unlike (!~)
+ # e.g. <?$var lt="123">display if $var less than 123</?>
+ $template =~ s#<\?(\$\w+(?:::)?\w*)\s+?(.+?)>(.*?)<\/\?>#"interpolate_fancy::_test(qq{$1}, q{$2}, q{$3})"#gsee;
+
+ # Unconditional, Recursive
+ # e.g. <$var />
+ while( $template =~ s/<\$([a-zA-Z?]\w+(?:::)?\w*)\s+?\/>/"defined \$$1 ? \$$1 : undef"/gsee ) { }
+
+ # Actions
+ # e.g. <@plugin.subroutine arg1="a" output="no" />
+ # e.g. <@plugin.subroutine encoding="Latin1" output="yes">pass content</@>
+ $template =~ s#<\@(\w+?)\.(\w+?)\s+?(.+?)?(?:>(.*?)<\/\@\1\.\2>|\s+?\/>)#&interpolate_fancy::_action($1,$2,$3,$4)#gse;
+
+ # Unmangle mangled interpolation tags in story $title and $body
+ # (by now in the template itself)
+ unless ($recurse_into_story) {
+ $template =~ s/<#INTERPOLATE_FANCY_DEFANG#(\@|\??\$)/<$1/gsi;
+ }
+
+ return $template;
+
+ };
+}
+
+sub _test {
+ my($variable, $attr, $content) = @_;
+
+ my $result;
+
+ my $attributes = interpolate_fancy::_attributes($attr);
+
+ defined $attributes->{eq} and return $variable eq $attributes->{eq} ? $content : undef;
+ defined $attributes->{ne} and return $variable ne $attributes->{ne} ? $content : undef;
+ defined $attributes->{gt} and return $variable > $attributes->{gt} ? $content : undef;
+ defined $attributes->{lt} and return $variable < $attributes->{lt} ? $content : undef;
+ defined $attributes->{like} and return $variable =~ /$attributes->{like}/ ? $content : undef;
+ defined $attributes->{unlike} and return $variable !~ /$attributes->{unlike}/ ? $content : undef;
+
+ return undef;
+}
+
+sub _action {
+ my($plugin, $action, $attr, $content) = @_;
+
+ $content =~ s#<\@(\w+?)\.(\w+?)\s+?(.+?)?(?:>(.*?)<\/\@\1\.\2>|\s+?\/>)#&interpolate_fancy::_action($1,$2,$3,$4)#gse;
+
+ my $attributes = interpolate_fancy::_attributes($attr);
+
+ $blosxom::plugins{$plugin}
+ and $plugin->can($action)
+ and $result = $plugin->$action($attributes, $content);
+
+ return $attributes->{'output'} =~ /yes/i ? $result : undef;
+}
+
+sub _attributes {
+ my $attr = shift;
+
+ my $attributes = {};
+ while ( $attr =~ /\b(\w+?)\s*?=\s*?(["'])(.*?)\2/g ) {
+ $attributes->{$1} = $3;
+ }
+
+ return $attributes;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: interpolate_fancy
+
+=head1 SYNOPSIS
+
+Overrides Blosxom's far simpler to use, but more limited, default interpolate()
+subroutine.
+
+Include bits of text and template variable values in templates, either
+conditionally or unconditionally:
+
+Perform actions (i.e. call plug-in subroutines) at any point in your page,
+whether to act on current content and return results or no.
+
+=head2 Includes
+
+ * Unconditionally and recursively
+
+ e.g. include a link to the story's path using various template variables.
+
+ <a href="<$url /><$path />"><$path /></a>
+
+ Limited by the $recurse_into_story configuration directive (see
+ the CONFIGURATION below).
+
+ * Unconditionally and recursively (backward compatibility with Blosxom's standard interpolation)
+
+ e.g. include a link to the story's path using various template variables.
+
+ <a href="$url$path">$path</a>
+
+ Limited by the $recurse_into_story configuration directive (see
+ the CONFIGURATION below).
+
+ * The template variable has a value (i.e. is defined)
+
+ e.g. include a hyperlink to the story's path if it has a path (i.e.
+ $path is defined).
+
+ <?$path><a href="<$url /><$path />"><$path /></a></?>
+
+ * The template variable doesn't have a value (i.e. is NOT defined)
+
+ e.g. include a hyperlink to home if path is undefined.
+
+ <?!$path><a href="<$url />">home</a></?>
+
+ * The template variable is equal (=) to a particular value
+
+ e.g. include "1 writeback" (singular) if the value of writeback count is 1
+
+ <$writeback::count /> <?$writeback::count eq="1">writeback</?>
+
+ * The template variable is not equal (!=) to a particular value
+
+ e.g. include "x writebacks" (plural) if the value of writeback
+ count (x) is not 1
+
+ <$writeback::count /> <?$writeback::count ne="1">writebacks</?>
+
+ * The template variable is less than (<) a particular value
+
+ e.g. include "no writebacks" if the value of writeback count is < 1
+
+ <?$writeback::count lt="1">no writebacks</?>
+
+ * The template variable is greater than (>) a particular value
+
+ e.g. include "oodles of writebacks" if the value of writeback count is > 50
+
+ <?$writeback::count gt="50">oodles of writebacks</?>
+
+ * The template variable is like (=~) a particular regular expression
+
+ e.g. Greet a visitor properly, depending on their courtesy title
+
+ Howdy,
+ <?$user::courtesy like="^(Mr\.?|Sir)$">Sir</?>
+ <?$user::courtesy like="^(Mr?s\.?|Miss)$">M'am</?>
+
+ * The template variable is unlike (!~) a particular regular expression
+
+ e.g. The posting is neither a film nor a book
+
+ <?$path unlike="/(Film|Literature)">no review</?>
+
+=head2 Actions
+
+Perform an action (i.e. call a plug-in's subroutine) at any point in your page.
+Optionally pass arguments as key/value pairs stated as XML-style attributes.
+For example:
+
+ <@plugin.subroutine arg1="a" arg2="bee" />
+
+calls &plugin::subroutine( {'arg1'=>'a', 'arg2'=>'bee' } ).
+
+Specify that results should be sent to the browser using the output="yes"
+attribute like so:
+
+ <@plugin.subroutine arg1="a" arg2="bee" output="yes" />
+
+Otherwise, subroutines will still have their effect, but the results will
+be tossed out.
+
+Content wrapped in the action call is sent as another argument to the
+subroutine:
+
+ <@plugin.subroutine encoding="Latin1" output="yes">
+ pass this content
+ </@plugin.subroutine>
+
+This calls &plugin::subroutine( {'encoding'=>'Latin1', 'output'=>'yes' }, "pass this content" ).
+
+Actions are recursive, meaning that you can embed an action inside another,
+and so on and so on and so on. Actions are unfolded from the inside out,
+with the most deeply embedded first, second deepest second, and so forth until
+the outermost action is performed last.
+
+Recursion is limited by the $recurse_into_story configuration directive (see
+the CONFIGURATION below).
+
+=head3 An Example
+
+For those of you interested in writing plugin actions or using some of the
+more advanced features in your Blosxom blog templates, here are a couple of
+sample actions:
+
+--
+
+# For the sake of this example, assume these actions live in a "myplugin"
+# plugin
+
+# This action strips HTML from its content
+sub strip_html {
+ my($self, $attributes, $content) = @_;
+ $content =~ s!</?.+?>!!g;
+ return $content;
+}
+
+# This action foreshortens its content to a length specified in the call to
+# action's length attribute
+sub foreshorten {
+ my($self, $attributes, $content) = @_;
+ my $default_length = 144;
+ return substr($content, 0, $attributes{'length'}||$default_length);
+}
+
+--
+
+Calling these individually in a Blosxom flavour template looks something like:
+
+The following bit of text is devoid of HTML:
+<@myplugin.strip_html output="Yes">
+Silly <a href="http://www.raelity.org/">me</a>, I plumb
+<em>forgot</em> to remove the HTML.
+</@myplugin.strip_html>
+
+The following bit of text is only 20 characters in length:
+<@myplugin.foreshorten output="Yes">
+This text is far longer than 20 characters on the page,
+but will only appear as "This text is far lon" in the
+resulting page.
+</@myplugin.foreshorten>
+
+And in combination, stripping the HTML _before_ foreshortening (notice
+the strip_html action is embedded inside the foreshorten action and
+thus is run first):
+
+The following bit of text is only 20 characters in length and devoid of HTML:
+<@myplugin.foreshorten output="Yes">
+<@myplugin.strip_html output="Yes">
+Silly <a href="http://www.raelity.org/">me</a>, I plumb
+<em>forgot</em> to remove the HTML.
+This text is far longer than 20 characters on the page,
+but will only appear as "This text is far lon" in the
+resulting page.
+</@myplugin.strip_html>
+</@myplugin.foreshorten>
+
+=head1 INSTALLATION
+
+Drop the interpolate_fancy plug-in into your Blosxom plugins folder.
+
+=head1 CONFIGURATION
+
+None necessary; interpolate_fancy will run out of the box with no need
+of additional configuration or fiddling on your part (caveat: see
+BACKWARD COMPATILITY below).
+
+The interpolate_fancy plugin does sport one configuration directive
+which you should very much consider leaving alone.
+
+# 0 = No (default), 1 = Yes
+my $recurse_into_story = 0;
+
+$recurse_into_story decides whether or not the interpolation engine
+should respect and interpolate (swap for the associated value)
+variables and actions embedded in story $title and $body themselves.
+
+Off by default, you should consider and reconsider carefully before
+turning this on as if anyone other than you has the ability to post
+stories to your blog, there's a chance of some tomfoolery, exposing
+variables and calling actions/subroutines you might not want called.
+
+=head1 BACKWARD COMPATIBILITY
+
+If you've been using core Blosxom's interpolation style
+(e.g. $title), this plugin will provide backward compatibility,
+requiring no template rewriting on your part.
+
+If you've been using the interpolate_conditional plugin,
+the conditional bits won't be respected by default. You should
+run your templates through the interpolate2fancy utility
+[http://blosxom.sourceforge.net/downloads/utilities/interpolate2fancy.py].
+
+=head1 VERSION
+
+2003-09-09:12:10
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: isp
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2.0b3
+# Documentation: See the bottom of this file or type: perldoc readme
+
+package isp;
+
+# --- Configurable variables -----
+
+# What bit of the URL should I treat as username?
+# Be sure the username bit is caught by the first () in the regular expression,
+# e.g. /~(.*)/weblog matches "sam" in http://www.example/~sam/weblog
+
+my $url_match = q!/~(.*?)/weblog!;
+
+# Where should I look for the user's Blosxom data directory ($datadir)?
+# Assume $username is populated by the results of the regular expression match
+# above, e.g. /home/sam/weblog
+
+my $user_datadir = q!/home/$username/weblog!;
+
+# Where should plug-ins keep their state for each user?
+# You should create this directory for them or no state will be saved.
+
+my $user_plugin_state_dir = q!/home/$username/.weblog/plugins/state!;
+
+# --------------------------------
+
+use CGI qw/:standard/;
+
+sub start {
+ url() =~ /$url_match/ or return 0;
+ my $username = $1;
+
+ $blosxom::datadir = $user_datadir and $blosxom::datadir =~ s!\$username!$username!;
+ $blosxom::plugin_state_dir = $user_plugin_state_dir and $blosxom::plugin_state_dir =~ s!\$username!$username!;
+
+
+ 1;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: isp
+
+=head1 SYNOPSIS
+
+This plug-in is designed for the ISP looking to provide Blosxom weblogs to all of its users.
+
+It traps URLs of the form /~username/weblog (as defined by $url_match), setting
+$blosxom::datadir to an appropriate directory (as defined by $user_datadir) in
+"username"'s home directory.
+
+=head2 Usage
+
+Be sure this plug-in sits BEFORE all other plug-ins. To force this, rename it
+to 00isp.
+
+This plugin works in concert with the "config" plug-in, without which it
+won't allow individual users to override the global Blosxom configuration by
+placing config files in their $datadir.
+
+Aside from this simple renaming, about all that should be needed is to
+ScriptAlias /~username/weblog to /cgi-bin/blosxom.cgi, replacing the paths as
+appropriate to your particular setup, of course.
+
+=head2 Warning
+
+Be sure to choose a $user_datadir _outside_ of the user's personal
+Web-accessible document-root. In other words, don't use a $user_datadir of
+/home/$username/www/weblog or the like, where anything under /home/$username/www
+is world-readable.
+
+=head2 Limitations
+
+This plug-in doesn't allow for users to add their own plug-ins to their own plugin directories. There's a race condition in this I've not yet worked my way around, but I have it in mind.
+
+=head1 VERSION
+
+2.0b3
+
+Version number coincides with the version of Blosxom with which the
+current version was first bundled.
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: kwiki
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2003-07-27
+# Documentation: See the bottom of this file or type: perldoc kwiki
+
+package kwiki;
+
+# --- Configurable variables -----
+
+# --------------------------------
+
+use 'CGI::Kwiki::Formatter';
+
+sub start {
+ return $meta::markup eq 'kwiki' ? 1 : 0;
+}
+
+sub story {
+ my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
+
+ $$body_ref = CGI::Kwiki::Formatter->process($$body_ref);
+
+ return 1;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: kwiki
+
+=head1 SYNOPSIS
+
+Purpose: Uses Brian Ingerson's Kwiki [http://www.kwiki.org/] wiki software
+as a formatting tool for Weblog entries.
+
+=head1 PREREQUISITES
+
+The CGI::Kwiki Perl module.
+
+=head1 VERSION
+
+2003-07-27
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://blosxom.sourceforge.net/
+
+Blosxom Plugin Docs: http://blosxom.sourceforge.net/documentation/users/plugins.html
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: lucene
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# and Sam Ruby <rubys@intertwingly.net>
+# Version: 2.0b2
+# Documentation: See the bottom of this file or type: perldoc lucene
+
+package lucene;
+
+# --- Configurable variables -----
+
+# Turn on the Lucene engine (set to 1 only once the other bits are in place)?
+my $lucene_on = 0;
+
+# Where's Java?
+my $JAVA_HOME = '/path/to/j2sdk1.3.1/';
+
+# Where's lucene?
+my $lucene = '/path/to/lib/java/*.jar';
+
+# What's my index?
+my $index = '/Library/WebServer/Data/lucene';
+
+# --------------------------------
+
+$search;
+
+use CGI qw/:standard/;
+use File::stat;
+use URI::Escape;
+use POSIX qw(strftime);
+use Env qw(@PATH @CLASSPATH);
+
+unshift @PATH, "$JAVA_HOME/bin";
+push @CLASSPATH, "$JAVA_HOME/lib/tools.jar";
+push @CLASSPATH, "$JAVA_HOME/jre/lib/rt.jar";
+push @CLASSPATH, "/any/other/appropriate/java/lib";
+push @CLASSPATH, glob($lucene);
+
+sub start {
+ $lucene_on or return 0;
+ $blosxom::static_or_dynamic eq 'dynamic' or return 0;
+ param('q') or return 0;
+ $search = "Search results for: " . param('q');
+ 1;
+}
+
+sub entries {
+ return sub {
+ my(%files, %indexes);
+
+ my $query = uri_escape(param('q'));
+ $query =~ s/;//g;
+
+ # Take a gander at what Lucene came up with based upon the search criteria
+ foreach (`$JAVA_HOME/bin/java -cp $ENV{CLASSPATH} LuceneSearch $index $query`) {
+ chomp;
+ s!\./!!;
+ $_ =~ /\.txt$/ and $files{"$blosxom::datadir/$_"} = stat("$blosxom::datadir/$_")->mtime;
+ }
+
+ return (\%files, \%indexes);
+ };
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: lucene
+
+=head1 SYNOPSIS
+
+Based upon: http://radio.weblogs.com/0101679/stories/2002/08/13/luceneSearchFromBlosxom.html
+
+Purpose: Lucene [http://jakarta.apache.org/lucene/] is a fabulous
+text search engine written in Java. This plug-in hooks in the results
+of a Lucene search, displaying only the stories matching the search query
+(as specified by ?q=keywords).
+
+Populates $lucene::search with "Search results for: keywords" for use in
+flavour templates.
+
+Replaces the default $blosxom::entries subroutine. You'd best put it before
+any other plug-ins that override the default $blosxom::entries subroutine.
+When ?q=keywords turns on the lucene plug-in, it'll then be used instead of
+whatever other entries overrides you have down the chain.
+
+E.g. My setup is as follows:
+
+01lucene
+
+02entries_index
+
+other
+
+plugins
+
+follow
+
+This plug-in could be used as a template for hooking into just about any
+files-based text search engine.
+
+=head1 VERSION
+
+2.0b1
+
+Version number coincides with the version of Blosxom with which the
+current version was first bundled.
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: meta
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2.0b4
+# Documentation: See the bottom of this file or type: perldoc readme
+
+package meta;
+
+# --- Configurable variables -----
+
+# What prefix should I expect prepended to each meta tag?
+my $meta_prefix = 'meta-';
+
+# --------------------------------
+
+sub start {
+ 1;
+}
+
+sub story {
+ my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
+
+ $$_ = undef foreach @keys;
+ @keys = ();
+
+ my($body, $in_header) = ('', 1);
+ foreach ( split /\n/, $$body_ref ) {
+ /^\s*$/ and $in_header = 0 and next;
+ if ( $in_header ) {
+ my($key, $value) = m!^$meta_prefix(.+?):\s*(.+)$!;
+ $key =~ /^\w+$/ and push(@keys,$key) and $$key = $value and next;
+ }
+ $body .= $_ . "\n";
+ }
+ $$body_ref = $body;
+
+ return 1;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: meta
+
+=head1 SYNOPSIS
+
+Purpose: Populates the $meta namespace with variables corresponding to meta tags found in the "header" (anything before a blank line) of a weblog post, removing the meta tags along the way. These variables are available to plug-ins and flavour templates as $meta::variablename.
+
+=head1 VERSION
+
+2.0b4
+
+Version number coincides with the version of Blosxom with which the
+current version was first bundled.
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: ping_weblogs_com
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2.0b4
+# Documentation: See the bottom of this file or type: perldoc ping_weblogs_com
+
+package ping_weblogs_com;
+
+# --- Configurable variables -----
+
+# What URL should this plugin ping?
+my $ping_url = "http://newhome.weblogs.com/pingSiteForm?name=" . encode($blosxom::blog_title) . "&url=" . encode($blosxom::url);
+
+# What external program should this plugin use to ping Weblogs.com?
+# 'lynx -source'
+# 'wget --quiet -U "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" -O -';
+# 'curl -m 30 -s'
+my $get_app = '';
+
+# --------------------------------
+
+use FileHandle;
+use File::stat;
+
+# Keep track of the newest story's mtime
+my $newest = 0;
+
+sub start {
+ $get_app or return 0;
+print STDERR "here\n";
+ 1;
+}
+
+sub filter {
+ my($pkg, $files_ref) = @_;
+
+ $newest = $files_ref->{( sort { $files_ref->{$b} <=> $files_ref->{$a} } keys %$files_ref )[0]};
+
+ 1;
+}
+
+sub end {
+ # If no timestamped touch-file or newest is newer than the touch-file...
+ if ( !-e "$blosxom::plugin_state_dir/.ping_weblogs_com.output" or $newest > stat("$blosxom::plugin_state_dir/.ping_weblogs_com.output")->mtime ) {
+
+ my $response = '';
+ my $ping_success = 0;
+ my $fh = new FileHandle;
+ $fh->open(qq{$get_app "$ping_url" |});
+ while (<$fh>) {
+ $response .= $_;
+ $_ =~ /Thanks for the ping/ and $ping_success++, last;
+ }
+ $fh->close();
+
+ $ping_success or return 0;
+
+ # Touch the touchfile (creates if doesn't already exist)
+ open TOUCH, "> $blosxom::plugin_state_dir/.ping_weblogs_com.output";
+ print TOUCH $response;
+ close TOUCH;
+
+ return 1;
+ }
+
+ return 1;
+}
+
+sub encode {
+ my($string) = @_;
+
+ my %encodings;
+ for (0..255) {
+ $encodings{chr($_)} = sprintf("%%%02X", $_);
+ }
+
+ $string =~ s/([^A-Za-z0-9\-_.!~*'()])/$encodings{$1}/g;
+ return $string;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: ping_weblogs_com
+
+=head1 SYNOPSIS
+
+Purpose: Notifies weblogs.com [http://www.weblogs.com] that your weblog
+has been updated upon encountering any new story.
+
+Maintains a touch-file ($blosxom::plugin_state_dir/.ping_weblogs_com.output)
+to which to compare the newest story's creation date. Fills the
+touch-file with the HTML results of the latest ping.
+
+=head1 VERSION
+
+2.0b3
+
+Version number coincides with the version of Blosxom with which the
+current version was first bundled.
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: postheadprefoot
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2.0b4-5
+# Documentation: See the bottom of this file or type: perldoc postheadprefoot
+
+package postheadprefoot;
+
+# --- Configurable variables -----
+
+# How should I decorate my posthead, if at all?
+# A dressed up version might look like:
+# my $posthead = '<span class="head">$posthead</span>';
+# The default is plain and simple:
+my $posthead = '$posthead';
+
+# How should I decorate my prefoot, if at all?
+# A dressed up version might look like:
+# my $prefoot = '<span class="foot">$prefoot</span>';
+# The default is plain and simple:
+my $prefoot = '$prefoot';
+
+# --------------------------------
+
+use FileHandle;
+
+my $fh = new FileHandle;
+
+sub start {
+ 1;
+}
+
+sub head {
+ my($pkg, $path, $head_ref) = @_;
+
+ $posthead =~ s!\$posthead!load($path, 'posthead')!eis;
+ $$head_ref .= $posthead;
+
+ 1;
+}
+
+sub foot {
+ my($pkg, $path, $foot_ref) = @_;
+
+ $prefoot =~ s!\$prefoot!load($path, 'prefoot')!eis;
+ $$foot_ref = $prefoot . $$foot_ref;
+
+ 1;
+}
+
+sub load {
+ my($path, $chunk) = @_;
+
+ my($path,$fn) = $path =~ m!^(?:(.*)/)?(.*)\.$blosxom::flavour!;
+
+ $path =~ s!^/*!!; $path &&= "/$path";
+
+ do {
+ $fh->open("< $blosxom::datadir$path/$chunk") || $fh->open("< $blosxom::datadir$path/$chunk.$blosxom::flavour") and return join '', <$fh>;
+ } while ($path =~ s/(\/*[^\/]*)$// and $1);
+
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: postheadprefoot
+
+=head1 SYNOPSIS
+
+Appends the contents of any posthead.flavour (specific to a particular flavour)
+or posthead (general, regardless of flavour) file found along a particular
+category path/directory to the head.flavour.
+
+Prepends the contents of any prefoot.flavour (specific to a particular flavour)
+or prefoot (general, regardless of flavour) file found along a particular
+category path/directory to the foot.flavour.
+
+In both cases, the plug-in prefers the posthead or prefoot found closest to
+the point of the path at hand. Also, preference is given to the flavour
+specific versus general version.
+
+=head1 VERSION
+
+2.0b4-5
+
+Version number coincides with the version of Blosxom with which the
+current version was first bundled.
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 INSTALLATION
+
+Drop into your Blosxom plug-in directory ($plugin_dir).
+
+Optionally, you can gussie up the included posthead or prefoot
+by altering the $posthead and $prefoot variables in the
+Configurable Variables section. Just be sure to include
+$posthead and $prefoot where the respective includes should go.
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: rating
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2003-06-27
+# Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+# Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+package rating;
+
+# --- Configurable variables -----
+
+# What's the default rating minimum?
+my $default_min = 1;
+
+# What's the default rating maximum?
+my $default_max = 5;
+
+# What's the width per rating point for graphical style?
+my $width = 10;
+
+# What's the height for graphical style?
+my $height = 10;
+
+# Where are the graphical images (rating_below.gif, rating.gif,
+# rating_above.gif) kept?
+my $image_url = "/images";
+
+# --------------------------------
+
+$numerical; # use as $rating::numerical in flavour templates
+$textual; # use as $rating::textual in flavour templates
+$graphical; # use as $rating::graphical in flavour templates
+$star; # use as $rating::star in flavour templates
+
+my $min = $meta::rating_min || $default_min;
+my $max = $meta::rating_max || $default_max;
+
+$image_url =~ s!/+$!!;
+
+sub start {
+ 1;
+}
+
+sub story {
+ my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
+
+ # Don't bother unless there's a rating; clear out previous ratings
+ unless ($meta::rating) {
+ ($numerical, $textual, $graphical, $star) = (undef, undef, undef, undef);
+ return 0;
+ }
+
+ # The numerical representation
+ $numerical = $meta::rating || 0;
+
+ # Sanity checks
+ $numerical < $min and $numerical = $min;
+ $numerical > $max and $numerical = $max;
+
+ # The textual representation
+ $textual =
+ '<'
+ . '=' x ($numerical - $min)
+ . 'O'
+ . '=' x ($max - $numerical)
+ . '>';
+
+ # The star representation
+ $star ='*' x $numerical;
+
+ # The graphical representation
+ $graphical =
+ qq{<img src="$image_url/rating_below.gif" height="$height" width="}
+ . ( $width * ( $numerical - $min ) ) . qq{" align="absmiddle">}
+ . qq{<img src="$image_url/rating.gif" height="$height" width="$width" align="absmiddle">}
+ . qq{<img src="$image_url/rating_above.gif" height="$height" width="}
+ . ( $width * ( $max - $numerical ) ) . qq{" align="absmiddle">};
+
+ return 1;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: rating
+
+=head1 SYNOPSIS
+
+For stories specifying a meta-rating value (using the meta plug-in),
+this plug-in generates numerical, textual, star, and graphical representations
+of said rating for use in a flavour template.
+
+For example, a story specifying:
+
+ meta-rating: 4
+
+results in the following flavour template variables and associated
+representations (the minimum, in this case, being 1 and maximum being 5):
+
+ $rating::numerical: 4
+
+ $rating::textual: <===O=>
+
+ $rating::star: ****
+
+ $rating::graphical:
+ <img src="/images/rating_below.gif" height="10" width="30">
+ <img src="/images/rating.gif" height="10" width="10">
+ <img src="/images/rating_above.gif" height="10" width="10">
+
+Simply add one of these template variables wherever you please in your
+story.{flavour} (e.g. story.html) flavour template and it'll be replaced
+on the fly with your rating in the selected style.
+
+A rating lower than the minimum is set to the minimum; a rating higher than
+the maximum is set to the maximum.
+
+=head1 PREREQUISITES
+
+The rating plug-in requires the meta plug-in, available at:
+
+ http://www.raelity.org/apps/blosxom/plugins/meta/meta.individual
+
+=head1 INSTALLATION
+
+Drop the rating plug-in into your Blosxom plugins folder.
+
+=head1 CONFIGURATION
+
+The plug-in will just work out of the box without any configuration. All
+further configuration is entirely optional.
+
+# What's the default rating minimum?
+my $default_min = 1;
+
+The default minimum ($default_min) specifies the default minimum for the
+rating scale. Besides adjusting the value of $default_min in the
+plug-in's configuration section, you can override the minimum on a weblog
+posting by posting basis by setting a meta-rating_min value in the entry
+itself.
+
+# What's the default rating maximum?
+my $default_max = 5;
+
+The default maximum ($default_max) specifies the default maximum for the
+rating scale. Besides adjusting the value of $default_max in the
+plug-in's configuration section, you can override the maximum on a weblog
+posting by posting basis by setting a meta-rating_max value in the entry
+itself.
+
+# What's the width per rating point for graphical style?
+my $width = 10;
+
+Sets the width in pixels for each rating point (e.g. a rating of 2 with
+$width set to 10 results in a bar of 20 pixels wide)..
+
+# What's the height for graphical style?
+my $height = 10;
+
+Sets the height in pixels for each rating point.
+
+# Where are the graphical images (rating_below.gif, rating.gif,
+# rating_above.gif) kept?
+my $image_url = "/images";
+
+A relative or absolute URL pointing at the location of 1-pixel
+rating_below.gif, rating.gif, and rating_above.gif images for use
+in creating the graphical representation of the rating.
+
+=head1 VERSION
+
+2003-06-27
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: readme
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2003-11-12
+# Documentation: See the bottom of this file or type: perldoc readme
+
+package readme;
+
+# --- Configurable variables -----
+
+my $before_readme = qq{<span class="readme">};
+my $after_readme = qq{</span>};
+
+# --------------------------------
+
+$readme; # use as $readme::readme in flavour templates
+
+use FileHandle;
+
+my $fh = new FileHandle;
+
+sub start {
+ 1;
+}
+
+sub head {
+ my($pkg, $path, $head_ref) = @_;
+
+ LOOK: {
+ do {
+ $fh->open("< $blosxom::datadir/$path/readme") || $fh->open("< $blosxom::datadir/$path/readme.$blosxom::flavour") and $readme = join('', $before_readme, <$fh>, $after_readme), $fh->close, last LOOK;
+ } while ($path =~ s/(\/*[^\/]*)$// and $1);
+ }
+
+ return 1;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: readme
+
+=head1 SYNOPSIS
+
+Purpose: Populates $readme::readme with the contents of any readme.flavour
+(specific to a particular flavour) or readme (general, regardless of flavour)
+file found along a particular category path/directory, preferring those found
+closest to the point of the path at hand.
+
+=head1 VERSION
+
+2003-11-12
+
+Version number coincides with the version of Blosxom with which the
+current version was first bundled.
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: rss10
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2.0b4
+# Documentation: See the bottom of this file or type: perldoc rss10
+
+package rss10;
+
+# --- Configurable variables -----
+
+# What is your full name?
+$creator = 'John Jacob Jingleheimer Schmidt';
+
+# What is your email address?
+$email = 'jjjs@example';
+
+# What is your timezone's offset from GMT?
+$tz_offset = "-08:00"; #PST
+
+# What placeholder in your flavour tempalte should I replace with <items />?
+my $template_placeholder = "{{{items}}}";
+
+# What is your TrackBack implementation's URL (if any)?
+#$trackback_url = "$blosxom::url/tb.cgi";
+
+# --- Plug-in package variables -----
+
+$items;
+$body;
+$trackback_ping;
+
+$generatorAgent = "http://www.raelity.org/apps/blosxom/?v=$blosxom::version";
+
+$T = 'T';
+$colon = ":";
+
+# --------------------------------
+
+use FileHandle;
+
+my $fh = new FileHandle;
+
+sub start {
+ 1;
+}
+
+sub head {
+ $items = '';
+}
+
+sub story {
+ my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
+
+ $body = $$body_ref;
+
+ $trackback_ping = $trackback_url ? qq{<trackback:ping rdf:resource="$trackback_url$path/$filename" />} : '';
+
+ $items .= qq{ <rdf:li rdf:resource="$blosxom::url$path/$filename.html" />\n};
+
+ 1;
+}
+
+sub foot {
+ my($pkg, $currentdir, $foot_ref) = @_;
+
+ $items = <<"ITEMS";
+ <items>
+ <rdf:Seq>
+$items
+ </rdf:Seq>
+ </items>
+ITEMS
+
+ $blosxom::output =~ s/$template_placeholder/$items/m;
+
+ return 1;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: rss10
+
+=head1 SYNOPSIS
+
+Purpose: Provides the extra bit of programming needed to produce a valid
+RSS 1.0 [http://www.purl.org/rss/1.0/] feed for syndication. Works
+in concert with the associated {head,story,foot,content_type,date}.rss10
+flavour files.
+
+=head1 VERSION
+
+2.0b1
+
+Version number coincides with the version of Blosxom with which the
+current version was first bundled.
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: sort_by_path
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2003-03-15
+# Documentation: See the bottom of this file or type: perldoc sort_by_path
+
+package sort_by_path;
+
+# --- Configurable variables -----
+
+# --------------------------------
+
+use File::Basename;
+
+sub start {
+ 1;
+}
+
+sub sort {
+ return sub {
+ my($files_ref) = @_;
+
+ map { $_->[1] }
+ sort { $a->[0] cmp $b->[0] || $a->[1] cmp $b->[1] }
+ map { [ dirname( $_ ), $_ ] }
+ keys %$files_ref;
+
+ };
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: sort_by_path
+
+=head1 SYNOPSIS
+
+Sorts Weblog entries by path rather than in the default reverse-chronological
+order.
+
+Use in concert with an appropriate "date" replacement, using path instead
+of date as the divider. E.g.: <p><b>$path</b></p>
+
+Overrides Blosxom's default sort() subroutine.
+
+=head1 INSTALLATION
+
+Drop the sort_by_default plug-in into your Blosxom plugins folder.
+
+=head1 VERSION
+
+2003-03-15
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: theme
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2003-08-26
+# Documentation: See the bottom of this file or type: perldoc theme
+
+package theme;
+
+# --- Configurable variables -----
+
+# Where do your themes live?
+my $theme_dir = "$blosxom::datadir/themes";
+
+# What's the URL of your themes directory?
+# This is vital for those themes that employ images, stylesheets, or other
+# external content pulled in from outside the page itself.
+$theme_dir_url = "$blosxom::url/themes";
+
+# Should I fall back to the blosxom template system, looking in $datadir
+# and paths beyond for template components?
+# 0 = no; 1 = yes (default)
+my $fallback_to_templates = 1;
+
+# --------------------------------
+
+use FileHandle;
+my $fh = new FileHandle;
+
+my $cache = {};
+
+sub start {
+ return -r $theme_dir ? 1 : 0;
+}
+
+sub template {
+ return sub {
+ my ($path, $chunk, $flavour) = @_;
+
+ $path =~ s!^/*!!; $path = "/$path";
+
+ # Return cached chunk, if available
+ $cache->{$flavour}->{$chunk} and return $cache->{$flavour}->{$chunk};
+
+ # Glean, spindle, and cache the theme
+ if (!keys %{$cache->{$flavour}} and $fh->open("$theme_dir/$flavour/page")) {
+ my $in_chunk = '';
+ while (my $line = <$fh>) {
+ $line =~ /<!--\s*blosxom\s+(\w+)(?:\s+(.*)\b)?\s*-->/;
+ $1 and $2 and $cache->{$flavour}->{$1} = $2 and next;
+ $1 and $in_chunk = $1 and next;
+ $cache->{$flavour}->{$in_chunk} .= $line;
+ }
+
+ # Return the requested chunk
+ $cache->{$flavour}->{$chunk} and return $cache->{$flavour}->{$chunk};
+ }
+
+ # Fall back to standard blosxom templating (if $fallback_to_templates)
+ $fallback_to_templates and do {
+ $blosxom::others{"$blosxom::datadir$path/$chunk.$flavour"} and
+ $fh->open("< $blosxom::datadir$path/$chunk.$flavour") and
+ return join '', <$fh>;
+ } while ($path =~ s/(\/*[^\/]*)$// and $1);
+
+ # Finally, fall back to baked-in basic flavours
+ return join '', ($blosxom::template{$flavour}{$chunk} || $blosxom::template{error}{$chunk} || '');
+
+ };
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: theme
+
+=head1 SYNOPSIS
+
+Build themes or use those built by others for your Blosxom-powered weblog.
+Themes consist of a directory named for your theme (e.g. "yellowish")
+containing a single template file ("page") and any supporting images,
+stylesheets, javascript source, etc. A typical theme directory structure
+looks something like:
+
+$theme_dir
+ /page
+ /images
+ /background.gif
+ /logo.gif
+ /javascript
+ /util.js
+
+The only bit that's required is that "page" file.
+
+The "page" file should define a content type, head, date, story,
+and foot --just as with Blosxom's default flavour template system
+[http://blosxom.sourceforge.net/documentation/users/flavour.html], except all
+in a single file rather than individual flavour files. Components are
+deliniated using <!-- blosxom componentname --> comments.
+
+Here's a sample (over-simplified) page definition:
+
+ <!-- blosxom content_type text/html -->
+
+ <!-- blosxom head -->
+ <html>
+ <head>
+ <title>my blosxom blog</title>
+ </head>
+ <body>
+ <h1>my blosxom blog</h1>
+
+ <!-- blosxom date -->
+ <p><b>$dw, $da $mo $yr</b></p>
+
+ <!-- blosxom story -->
+ <p>
+ <a name="$fn"><b>$title</b></a>
+ <br />
+ $body
+ <br />
+ <a href="$url$path/$fn.$default_flavour">permanent link</a>
+ </p>
+
+ <!-- blosxom foot -->
+ </body>
+ </html>
+
+Everything after a <!-- blosxom componentname --> comment (until the
+next one) is part of the component. Notice the only exception is the
+content_type component, the content type for the document being defined
+in the comment itself; this is to assure only a single line is used for
+content type.
+
+The theme plugin overrides Blosxom's default template() subroutine,
+falling back to Blosxom's default flavour template system if the
+requested theme is not available. It falls further back to Blosxom's
+baked in default HTML and RSS flavours if no theme or flavour
+templates are available for the requested theme/flavour.
+
+=head1 INSTALLATION
+
+Drop the theme plugin into your Blosxom plugins folder.
+
+=head1 CONFIGURATION
+
+The plugin is preconfigured to assume a themes directory beneath your
+Blosxom data directory ($datadir, as configured in the blosxom.cgi script).
+Alter the $theme_dir configurable variable to have your themes live elsewhere.
+
+e.g.
+ # Where do your themes live?
+ my $theme_dir = "/somewhere/else/themes";
+
+Wherever it lives, your themes directory should be Web-accessible since
+themes may (and probably do) employ images, stylesheets, and other
+content pulled in from outside the page itself.
+
+e.g.
+ # What's the URL of your themes directory?
+ my $theme_dir_url = "http://example.com/somewhere/else/themes";
+
+By default, the theme plugin falls back to Blosxom's built-in flavour
+template system [http://blosxom.sourceforge.net/documentation/users/flavour.html].
+You can turn this off by setting the $fallback_to_templates variable to 0.
+
+e.g.
+ # Should I fall back to the blosxom template system, looking in $datadir
+ # and paths beyond for template components?
+ # 0 = no; 1 = yes (default)
+ my $fallback_to_templates = 0;
+
+=head1 VERSION
+
+2003-08-26
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing:
+ http://blosxom.sourceforge.net/
+
+Blosxom Plugin User Documentation:
+ http://blosxom.sourceforge.net/documentation/users/plugins.html
+
+Blosxom Plugin Developer Documentation:
+ http://blosxom.sourceforge.net/documentation/developers/plugins.html
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: tiki
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2.0b2
+# Documentation: See the bottom of this file or type: perldoc tiki
+
+package tiki;
+
+# --- Configurable variables -----
+
+# What flag in your weblog entries lets me know to turn on tiki translation?
+my $tiki_on_flag = "<!-- tiki on -->";
+
+# --------------------------------
+
+use lib qq{$blosxom::plugin_dir/lib};
+
+sub start {
+ eval "require Text::Tiki";
+ return $@ ? 0 : 1;
+}
+
+sub story {
+ my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
+
+ $$body_ref =~ s/$tiki_on_flag//mi or return 0;
+
+ my $processor=new Text::Tiki;
+ $$body_ref = $processor->format($$body_ref);
+
+ return 1;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: tiki
+
+=head1 SYNOPSIS
+
+Purpose: Provides Tiki [http://www.mplode.com/tima/archives/000215.html]
+formatting for Weblog entries.
+
+Assumes $plugin_dir/lib/Text/Tiki.pm
+
+=head1 VERSION
+
+2.0b2
+
+Version number coincides with the version of Blosxom with which the
+current version was first bundled.
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: trackback_counts_display
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2.0b2
+# Documentation: See the bottom of this file or
+# type: perldoc trackback_counts_display
+
+package trackback_counts_display;
+
+# --- Configurable variables -----
+
+# What is the trackbacks base URL?
+my $trackback_url = "http://www.example/tb.cgi";
+
+# Where are trackbacks kept?
+my $trackback_dir = "/Library/WebServer/Data/trackbacks";
+
+# --------------------------------
+
+use File::Spec::Functions;
+
+$trackback; # use as $trackback_counts_display::trackback in flavour templates
+
+sub start {
+ -d $trackback_dir or return 0;
+ 1;
+}
+
+sub story {
+ my($pkg, $path, $filename, $story_ref) = @_;
+ my $trackback_id = "$path/$filename";
+ $trackback_id =~ s!^/!!;
+ $trackback_id =~ tr/a-zA-Z0-9/_/cs;
+
+ require Storable;
+ my $trackback_count = -e "$trackback_dir/$trackback_id.stor" ? @{Storable::retrieve("$trackback_dir/$trackback_id.stor")} : 0;
+ my $trackback_text = $trackback_count == 1 ? 'trackback' : 'trackbacks';
+
+ $trackback = qq{<a href="$trackback_url?__mode=list&tb_id=$trackback_id" onclick="window.open(this.href, 'trackbacks', 'width=640,height=480,scrollbars=yes,status=yes'); return false">$trackback_count $trackback_text</a>};
+
+ 1;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: trackback_counts_display
+
+=head1 SYNOPSIS
+
+Purpose: Incorporates TrackBack [http://www.movabletype.org/trackback/]
+counts into Blosxom flavours. Populates $trackback_counts_display::trackback
+with "n trackback(s)", n being the number of trackbacks associated with a
+particular story. Further provides a popup link to the TrackBack CGI
+for a view of current trackbacks for a particular story.
+
+Assumes the MT Standalone TrackBack implementation is already up and running.
+
+=head1 VERSION
+
+2.0b2
+
+Version number coincides with the version of Blosxom with which the
+current version was first bundled.
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: whoami
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2.0b4-5
+# Documentation: See the bottom of this file or type: perldoc whoami
+
+package whoami;
+
+# --- Configurable variables -----
+
+# --------------------------------
+
+$fullname;
+$username;
+
+use File::stat;
+
+sub start {
+ 1;
+}
+
+sub story {
+ my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
+
+ $username = $fullname = '';
+
+ if ( -e "$blosxom::datadir$path/$filename.$blosxom::file_extension" ) {
+ my @user_info = getpwuid( stat("$blosxom::datadir$path/$filename.$blosxom::file_extension")->uid );
+ ($username, $fullname) = ($user_info[0],$user_info[6]);
+ };
+
+ 1;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: whoami
+
+=head1 SYNOPSIS
+
+Populates $whoami::username and $whoami::$fullname with
+local username and full name, respectively, for each story. Useful
+for group Blosxom blogs.
+
+=head1 VERSION
+
+2.0b4-5
+
+Version number coincides with the version of Blosxom with which the
+current version was first bundled.
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: wikieditish
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2003-05-29
+# Documentation: See the bottom of this file or type: perldoc wikieditish
+
+package wikieditish;
+
+# --- Configurable variables -----
+
+# Should I attempt to preserve the last modified date/time when
+# editing an existing file? (May not work on your operating system.)
+# 0 = no (default), 1 = yes
+$preserve_lastmodified = 0;
+
+# Should editing this blog require a password?
+# 0 = no, 1 = yes (default)
+$require_password = 1;
+
+# What is the password for editing this blog?
+my $blog_password = '';
+
+# Should editing this blog be restricted to a particular set of IPs?
+# 0 = no (default), 1 = yes
+$restrict_by_ip = 0;
+
+# To what IPs should editing this blog be restricted?
+@ips = qw/ 127.0.0.1 /;
+
+# What file extension should I use for edited pages?
+# (Not sure why you'd change this, but just in case...)
+my $file_extension = $blosxom::file_extension;
+
+# --------------------------------
+
+# Response to wikieditish; use as $wikieditish::response in
+# flavour templates
+$response = '';
+
+# The raw title and body
+($title, $body) = ('', '');
+
+# The password entered into the form (for prepopulating the form upon Save)
+$password = '';
+
+# --------------------------------
+
+use vars qw/$require_password/;
+
+use CGI qw/:standard/;
+use FileHandle;
+
+my $fh = new FileHandle;
+
+# Strip potentially confounding bits from user-configurable variables
+$file_extension =~ s!^\.!!;
+
+sub start {
+
+ # Only spring into action if POSTing to the wikieditish plug-in
+ if ( request_method() eq 'POST' and param('plugin') eq 'wikieditish' ) {
+
+ my($path,$fn) = $blosxom::path_info =~ m!^(?:(.*)/)?(.*)\.$blosxom::flavour!;
+ $path =~ m!^/! or $path = "/$path";
+
+ $password = param('password');
+ $title = param('title');
+ $body = param('body');
+
+ # Something's fishy with the path
+ $path =~ /[^\/\w\-]/
+ and warn "blosxom : wikieditish plugin : something's fishy with the path, $path\n"
+ and $response = "Something didn't go as expected; page not saved."
+ and return 1;
+
+ # password required, but not set
+ $require_password and !$blog_password
+ and warn "blosxom : wikieditish plugin : password required but is not yet set; trying to > $blosxom::datadir$path/$fn.file_extension\n"
+ and $response = "A password is required to edit this page but one has not yet been set; page not saved."
+ and return 1;
+
+ # password required, set, but not correctly supplied
+ $require_password and (!param('password') or (param('password') and param('password') ne $blog_password))
+ and warn "blosxom : wikieditish plugin : incorrect password supplied for > $blosxom::datadir$path/$fn.file_extension\n"
+ and $response = "Incorrect password supplied; page not saved."
+ and return 1;
+
+ # restricted by ip
+ $restrict_by_ip and !grep(/^\Q$ENV{'REMOTE_ADDR'}\E$/, @ips)
+ and warn "blosxom : wikieditish plugin : incorrect IP address > $blosxom::datadir$path/$fn.file_extension\n"
+ and $response = "Incorrect IP address; page not saved."
+ and return 1;
+
+ # blosxom's $datadir is not writeable
+ !-w $blosxom::datadir
+ and warn "blosxom : wikieditish plugin > \$blosxom::datadir, $blosxom::datadir, is not writeable.\n"
+ and $response = "Something didn't go as expected; page not saved."
+ and return 1;
+
+ # the destination directory for this blog entry does not yet exist
+ unless ( -d "$blosxom::datadir$path" and -w "$blosxom::datadir$path" ) {
+ warn "blosxom : wikieditish plugin : mkdir $blosxom::datadir$path\n";
+ foreach ( ('', split /\//, $path) ) {
+ $p .= "/$_";
+ $p =~ s!^/!!;
+ -d "$blosxom::datadir/$p" or mkdir "$blosxom::datadir/$p", 0755
+ or ( warn "blosxom : wikieditish plugin : couldn't mkdir $blosxom::datadir/$p." and return 1 );
+ }
+ }
+
+ # If file already exists, memorize the lastmodified date/time
+ my $mtime = (stat "$blosxom::datadir$path/$fn.$file_extension")[9];
+
+ # If file is writeable
+ if ( $fh->open("> $blosxom::datadir$path/$fn.$file_extension") ) {
+ print $fh join "\n", $title, $body;
+ $fh->close();
+ $response = "Page saved successfully.";
+
+ # reset lastmodified date/time to memorized value (if possible)
+ $preserve_lastmodified
+ and utime(time, $mtime, "$blosxom::datadir$path/$fn.$file_extension")
+ ? $response .= " Preserved last modified date/time."
+ : warn "blosxom : wikieditish plugin : couldn't reset lastmodified time on $blosxom::datadir$path/$fn.$file_extension.";
+
+ } else {
+ warn "couldn't > $blosxom::datadir$path/$fn.file_extension";
+ $response = "There was a problem saving this page.";
+ }
+ }
+
+ 1;
+}
+
+sub story {
+ my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
+
+ unless ( param('plugin') eq 'wikieditish' ) {
+ my @body;
+ ($title, @body) = split /\n/, $blosxom::raw;
+ $body = join "\n", @body;
+ }
+
+ 1;
+}
+
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: wikieditish
+
+=head1 SYNOPSIS
+
+Edit a Blosxom blog wiki-style, from right in the browser.
+
+=head2 QUICK START
+
+Drop this wikieditish plug-in file into your plug-ins directory
+(whatever you set as $plugin_dir in blosxom.cgi).
+
+Wikieditish, being a well-behaved plug-in, won't do anything until you
+either set a password or turn off the password requirement
+(set $require_password = 0).
+
+Move the contents of the flavours folder included in this distribution
+into your Blosxom data directory (whatever you set as $datadir in blosxom.cgi).
+Don't move the folder itself, only the files it contains! If you don't
+have the the sample flavours handy, you can download them from:
+
+http://www.raelity.org/apps/blosxom/downloads/plugins/wikieditish.zip
+
+Point your browser at one of your Blosxom entries, specifying the wikieditish
+flavour (e.g. http://localhost/cgi-bin/blosxom.cgi/path/to/a/post.wikieditish)
+
+Edit the entry, supply your password (if required -- the default), and hit the Save button to save your changes.
+
+You can just as easily create a new blog entry by pointing your browser at a non-existent filename, potentially on a non-existent path (e.g. http://localhost/cgi-bin/blosxom.cgi/path/to/a/nonexistent_post.wikieditish). Give the entry a
+title and body, supply your password (again, if required), and hit the Save
+button. The wikieditish plug-in will create a new blog entry for you on
+your specified path, creating the supplied path's directory structure for you
+on the fly if necessary.
+
+Enjoy!
+
+=back
+
+=head2 SAMPLE FLAVOUR TEMPLATES
+
+I've made sample flavour templates available to you to help with any
+learning curve this plug-in might require.
+
+Take a gander at the source HTML for:
+
+=item * head.wikieditish, a basic head template -- nothing special.
+
+=item * story.wikieditish, a basic story template -- nothing special.
+
+=item * foot.wikieditish, a basic foot template just about like any other.
+The big difference is the "edit this blog" form for editing the current
+blog entry or creating a fresh one.
+
+NOTE: The wikieditish plug-in requires the presence of a "plugin" form
+variable with the value set to "wikieditish"; this tells the plug-in
+that it should handle the incoming POSTing data rather than leaving it
+for another plug-in.
+
+=back
+
+=head2 FLAVOURING WIKIEDITISH
+
+While there's not much in the way of template variables and the sample
+foot.wikieditish provides about everything you'll need, here's a list of
+variables and their purposes for your reference:
+
+=item * $wikieditish::title and $wikieditish::body prepopulate the form with the values from the existing blog entry file.
+
+=item * $wikieditish::password is prepopulated with the password you just entered into and submitted in the "edit this blog" form or preferences stored in a 'wikieditish' cookie, if you've the cookie plug-in installed and enabled.
+
+=back
+
+=head2 INVITING CONTRIBUTIONS
+
+The wikieditish plug-in serves dual purposes: as a browser-based editor for
+your Blosxom blog and as a wiki-style community blog, allowing contributions
+by a particular group of bloggers (using a shared password) or passers-by
+(without need of a password -- true Wiki-style).
+
+If you'd like to invite contribution, you can assocate an "edit" button with
+each entry like so:
+
+<a href="$url$path/$fn.wikieditish">edit this blog</a>
+
+HERE
+
+=head1 INSTALLATION
+
+Drop wikieditish into your plug-ins directory ($blosxom::plugin_dir).
+
+=head1 CONFIGURATION
+
+=head2 PRESERVING LAST MODIFIED DATE/TIME ON EDITED ENTRY
+
+The wikieditish plug-in can attempt to maintain the last modified date/time
+stamp on any blog entry you're editing. Otherwise, editing an entry will
+cause it to rise to the top of your blog like so much cream.
+
+I say "attempt" since this doesn't work on every operating system
+(it doesn't do any harm, though).
+
+To turn this feature on -- it's off by default -- set the
+$preserve_lastmodified variable to 1.
+
+=head2 RESTRICTING BY PASSWORD
+
+By default, the wikieditish plug-in requires a password. You'll need to
+set one before being able to edit anything. Set the $blog_password
+configuration variable to anything you wish
+(e.g. my $blog_password = 'abc123';). Just be
+sure to use something you'll remember and other's won't guess.
+
+You can disable password-protection if you wish, allowing passers-by to
+contribute to your blog, Wiki-style. Be sure this is something you want to
+do. It has some possible security implications, anyone being able to write
+to your server's hard drive, post to your public-facing blog, and edit
+(read: alter, spindle, contort) any blog postings. Those warning's out of
+the way, to turn off password-protection, set $require_password to 0.
+
+=head2 RESTRICTING BY IP
+
+You can alternatively decide to restrict editing to a particular IP address
+or addresses -- those in your office, for example, or the machine actually
+running Blosxom (127.0.0.1).
+
+To do so, set $restrict_by_ip to 1 (it's off, or 0, by default), and
+populate the @ips array with a list of approved IP addresses. By default,
+this is set to "this machine", the machine running Blosxom; shorthand for
+"this machine" in IP-speak is 127.0.0.1. The following example restricts
+editing to those coming from three IPs, including 127.0.0.1:
+
+ # Should editing this blog be restricted to a particular set of IPs?
+ # 0 = no (default), 1 = yes
+ $restrict_by_ip = 1;
+
+ # To what IPs should editing this blog be restricted?
+ @ips = qw/ 127.0.0.1 10.0.0.3 140.101.22.10/;
+
+Of course, you can use a combination of password-protection and IP
+restriction if you so wish.
+
+=head1 VERSION
+
+2003-05-29
+
+Version number is the date on which this version of the plug-in was created.
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+The wikieditish plug-in plays nicely with the wikiwordish plug-in
+[http://www.raelity.org/apps/blosxom/plugins/text/wikiwordish.individual]
+for wiki-style linking action. And for wiki-style markup, be sure to try the
+textile [http://www.raelity.org/apps/blosxom/plugins/text/textile.individual]
+or tiki [http://www.raelity.org/apps/blosxom/plugins/text/tiki.individual]
+plug-ins.
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: wikieditish
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2003-05-27
+
+# Quick Start
+
+Welcome to the Blosxom [http://www.raelity.org/apps/blosxom/] wikieditish
+plug-in.
+
+This package provides you all you need to get wikieditish up and running
+on your Blosxom weblog.
+
+Installation is quick and easy...
+
+1. Drop the wikieditish plug-in file, found in this package's plugins
+ directory, into your plug-ins directory (whatever you set as
+ $plugin_dir in blosxom.cgi).
+
+2. wikieditish, being a well-behaved plug-in, won't do anything until you
+ either set a password ($password) or turn off the password requirement
+ (set $require_password = 0).
+
+4. Move the contents of the flavours folder included in this distribution
+ into your Blosxom data directory (whatever you set as $datadir in
+ blosxom.cgi).
+
+ Don't move the folder itself, only the files it contains! If you don't
+ have the the sample flavours handy, you can download them from:
+
+ http://www.raelity.org/apps/blosxom/downloads/plugins/wikieditish.zip
+
+5. Point your browser at one of your Blosxom entries, specifying the
+ wikieditish flavour:
+
+ http://localhost/cgi-bin/blosxom.cgi/path/to/a/post.wikieditish
+
+ (Replace "localhost/cgi-bin/blosxom.cgi" with your weblog's URL and
+ "/path/to/a/post" with the path to a weblog post, including its
+ filename.)
+
+6. Edit the entry, supply your password (if required -- the default), and
+ hit the Save button to save your changes.
+
+You can just as easily create a new blog entry by pointing your browser at a non-existent filename, potentially on a non-existent path (e.g. http://localhost/cgi-bin/blosxom.cgi/path/to/a/nonexistent_post.wikieditish). Give the entry a
+title and body, supply your password (again, if required), and hit the Save
+button. The wikieditish plug-in will create a new blog entry for you on
+your specified path, creating the supplied path's directory structure for you
+on the fly if necessary.
+
+For detailed documentation, take a gander at the bottom of writeback
+plug-in file itself or type:
+
+ perldoc wikieditish
--- /dev/null
+# Blosxom Plugin: writeback
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2003-09-18
+# Documentation: See the bottom of this file or type: perldoc writeback
+
+package writeback;
+
+# --- Configurable variables -----
+
+# Where should I keep the writeback hierarchy?
+# I suggest: $writeback_dir = "$blosxom::plugin_state_dir/writeback";
+#
+# NOTE: By setting this variable, you are telling the plug-in to go ahead
+# and create a writeback directory for you.
+my $writeback_dir = "";
+
+# What flavour should I consider an incoming trackback ping?
+# Otherwise trackback pings will be ignored!
+my $trackback_flavour = "trackback";
+
+# What file extension should I use for writebacks?
+# Make sure this is different from that used for your Blosxom weblog
+# entries, usually txt.
+my $file_extension = "wb";
+
+# What fields are used in your comments form and by trackbacks?
+my @fields = qw! name url title comment excerpt blog_name !;
+
+# --------------------------------
+
+# Comments for a story; use as $writeback::writebacks in flavour templates
+$writebacks;
+
+# Count of writebacks for a story; use as $writeback::count in flavour templates
+$count;
+
+# The path and filename of the last story on the page (ideally, only 1 story
+# in this view) for displaying the trackback URL;
+# use as $writeback::trackback_path_and_filename in your foot flavour templates
+$trackback_path_and_filename;
+
+# Response to writeback; use as $writeback::writeback_response in
+# flavour templates
+$writeback_response;
+
+# Response to a trackback ping; use as $writeback::trackback_response in
+# head.trackback flavour template
+$trackback_response =<<'TRACKBACK_RESPONSE';
+<?xml version="1.0" encoding="iso-8859-1"?>
+<response>
+<error></error>
+<message></message>
+</response>
+TRACKBACK_RESPONSE
+
+$blosxom::template{'trackback'} = {
+ 'content_type' => 'text/xml',
+ 'head' => '$writeback::trackback_response',
+ 'date' => ' ',
+ 'story' => ' ',
+ 'foot' => ' '
+};
+
+# --------------------------------
+
+use CGI qw/:standard/;
+use FileHandle;
+
+my $fh = new FileHandle;
+
+# Strip potentially confounding bits from user-configurable variables
+$writeback_dir =~ s!/$!!; $file_extension =~ s!^\.!!;
+
+# Save Name and URL/Email via cookie if the cookies plug-in is available
+$cookie;
+
+sub start {
+
+ # $writeback_dir must be set to activate writebacks
+ unless ( $writeback_dir ) {
+ warn "blosxom : writeback plugin > The \$writeback_dir configurable variable is not set; please set it to enable writebacks. Writebacks are disabled!\n";
+ return 0;
+ }
+
+ # the $writeback_dir exists, but is not a directory
+ if ( -e $writeback_dir and ( !-d $writeback_dir or !-w $writeback_dir ) ) {
+ warn "blosxom : writeback plugin > The \$writeback_dir, $writeback_dir, must be a writeable directory; please move or remove it and Blosxom will create it properly for you. Writebacks are disabled!\n";
+ return 0;
+ }
+
+ # the $writeback_dir does not yet exist, so Blosxom will create it
+ if ( !-e $writeback_dir ) {
+
+ my $mkdir_r = mkdir("$writeback_dir", 0755);
+
+ warn $mkdir_r
+ ? "blosxom : writeback plugin > \$writeback_dir, $writeback_dir, created.\n"
+ : "blosxom : writeback plugin > There was a problem creating your \$writeback_dir, $writeback_dir. Writebacks are disabled!\n";
+
+ $mkdir_r or return 0;
+
+ my $chmod_r = chmod 0755, $writeback_dir;
+
+ warn $chmod_r
+ ? "blosxom : writeback plugin > \$writeback_dir, $writeback_dir, set to 0755 permissions.\n"
+ : "blosxom : writeback plugin > There was a problem setting permissions on \$writeback_dir, $writeback_dir. Writebacks are disabled!\n";
+
+ $chmod_r or return 0;
+
+ warn "blosxom : writeback plugin > writebacks are enabled!\n";
+ }
+
+ $path_info = path_info();
+ my($path,$fn) = $path_info =~ m!^(?:(.*)/)?(.*)\.$blosxom::flavour!;
+ $path =~ m!^/! or $path = "/$path";
+ $path = "/$path";
+
+ # Only spring into action if POSTing to the writeback plug-in
+ if ( request_method() eq 'POST' and (param('plugin') eq 'writeback' or $blosxom::flavour eq $trackback_flavour) ) {
+
+ foreach ( ('', split /\//, $path) ) {
+ $p .= "/$_";
+ $p =~ s!^/!!;
+ -d "$writeback_dir/$p" or mkdir "$writeback_dir/$p", 0755;
+ }
+
+ if ( $fh->open(">> $writeback_dir$path/$fn.$file_extension") ) {
+ foreach ( @fields ) {
+ my $p = param($_);
+ $p =~ s/<.*?>//mg; # a gross way to prevent tomfoolery, to be redone
+ $p =~ s/\r?\n\r?/\r/mg;
+ print $fh "$_: $p\n";
+ }
+ print $fh "-----\n";
+ $fh->close();
+
+ $trackback_response =~ s!<error></error>!<error>0</error>!m;
+ $trackback_response =~ s!<message></message>\n!!s;
+ $writeback_response = "Thanks for the writeback.";
+
+ # Make a note to save Name and URL/Email if save_preferences checked
+ param('save_preferences') and $cookie++;
+ # Pre-set Name and URL/Email based on submitted values
+ $pref_name = param('name') || '';
+ $pref_url = param('url') || '';
+
+ } else {
+ warn "couldn't >> $writeback_dir$path/$fn.$file_extension\n";
+
+ $trackback_response =~ s!<error></error>!<error>1</error>!m;
+ $trackback_response =~ s!<message>trackback error</message>!!m;
+ $writeback_response = "There was a problem posting your writeback.";
+ }
+ }
+
+ 1;
+}
+
+sub story {
+ my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
+
+ $path =~ s!^/*!!; $path &&= "/$path";
+
+ ($writebacks, $count) = ('', 0);
+ my %param = ();
+
+ # Prepopulate Name and URL/Email with cookie-baked preferences, if any
+ if ( $blosxom::plugins{cookies} > 0 and my $cookie = &cookies::get('writeback') ) {
+ $pref_name ||= $cookie->{'name'};
+ $pref_url ||= $cookie->{'url'};
+ }
+
+ if ( $fh->open("$writeback_dir$path/$filename.$file_extension") ) {
+ foreach my $line (<$fh>) {
+ $line =~ /^(.+?):\s*(.*)$/ and $param{$1} = $2;
+ if ( $line =~ /^-----$/ ) {
+
+ my $writeback = &$blosxom::template($path,'writeback',$blosxom::flavour) || '<p><b>Name/Blog:</b> $writeback::name$writeback::blog_name<br /><b>URL:</b> $writeback::url<br /><b>Title:</b> $writeback::title<br /><b>Comment/Excerpt:</b> $writeback::comment$writeback::excerpt</p>';
+
+ $writeback =~ s/\$writeback::(\w+)/$param{$1}/ge;
+ $writebacks .= $writeback;
+ $count++;
+ }
+ }
+
+ }
+
+ $trackback_path_and_filename = "$path/$filename";
+
+ 1;
+}
+
+sub foot {
+ $blosxom::plugins{cookies} > 0 and $cookie and &cookies::add(
+ cookie(
+ -name=>'writeback',
+ -value=>{ 'name' => param('name'), 'url' => param('url') },
+ -path=>$cookies::path,
+ -domain=>$cookies::domain,
+ -expires=>$cookies::expires
+ )
+ );
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Blosxom Plug-in: writeback
+
+=head1 SYNOPSIS
+
+Provides WriteBacks, a combination of comments and TrackBacks
+[http://www.movabletype.org/trackback/].
+
+All comments and TrackBack pings for a particular story are kept in
+$writeback_dir/$path/$filename.cmt.
+
+=head2 QUICK START
+
+Drop this writeback plug-in file into your plug-ins directory
+(whatever you set as $plugin_dir in blosxom.cgi).
+
+Writeback, being a well-behaved plug-in, won't do anything until you set
+$writeback_dir.
+
+While you can use the same directory as your blosxom $datadir (WriteBacks
+are saved as path/weblog_entry_name.wb), it's probably better to keep
+them separate.
+
+Once set, the next time you visit your site, the writeback plug-in will
+perform some checks, creating the $writeback_dir and setting appropriate
+permissions if it doesn't already exist. (Check your error_log for details
+of what's happening behind the scenes.)
+
+Move the contents of the flavours folder included in this distribution
+into your Blosxom data directory (whatever you set as $datadir in blosxom.cgi).
+Don't move the folder itself, only the files it contains! If you don't
+have the the sample flavours handy, you can download them from:
+
+http://www.raelity.org/apps/blosxom/downloads/plugins/writeback.zip
+
+Point your browser at one of your Blosxom entries, specifying the writeback
+flavour (e.g. http://localhost/cgi-bin/blosxom.cgi/path/to/a/post.writeback)
+
+Enjoy!
+
+=back
+
+=head2 FLAVOUR TEMPLATE VARIABLES
+
+Wherever you wish all the WriteBacks for a particular story to appear
+in your flavour templates, use $writeback::writebacks.
+
+A count of WriteBacks for each story may be embedded in your flavour
+templates with $writeback::count.
+
+If you'd like, you can embed a "Thanks for the writeback." or
+"There was a problem posting your writeback." message after posting with
+$writeback::writeback_response.
+
+=head2 SAMPLE FLAVOUR TEMPLATES
+
+I've made sample flavour templates available to you to help with any
+learning curve this plug-in might require.
+
+Take a gander at the source HTML/XML for:
+
+=item * story.writeback, a basic example of a single-entry story
+flavour with WriteBacks embedded. You should not use this as your
+default flavour since every story on the home page would have WriteBacks
+right there with the story itself.
+
+=item * foot.writeback provides a simple comment form for posting to the
+WriteBack plug-in. NOTE: The writeback plug-in requires the presence
+of a "plugin" form variable with the value set to "writeback"; this tells
+the plug-in that it should handle the incoming POSTing data rather than
+leaving it for another plug-in.
+
+=item * writeback.writeback is a sample flavour file for WriteBacks themselves.
+Think of a WriteBacks flavour file as a story flavour file for individual
+WriteBacks.
+
+=back
+
+=head2 FLAVOURING WRITEBACKS
+
+While the default does a pretty good job, you can flavour your WriteBacks
+in the writeback flavour file (e.g. writeback.writeback) using the following
+variables:
+
+=item * $writeback::name$writeback::blog_name - Name entered in comment form or weblog name used in TrackBack ping.
+
+=item * $writeback::url - URL entered in comment form or that of writing citing your weblog entry via TrackBack ping.
+
+=item * $writeback::title - Title entered into comment form or that of writing citing your weblog entry via TrackBack ping.
+
+=item * $writeback::comment$writeback::excerpt - Comment entered into comment aorm or excerpt of writing citing your weblog entry via TrackBack ping.
+
+=item * $writeback::pref_name and $writeback::pref_url are prepopulated with the values of the form you just submitted or preferences stored in a 'writeback' cookie, if you've the cookie plug-in installed an enabled.
+
+=back
+
+=head2 INVITING AND SUPPORTING TRACKBACKS
+
+You should provide the TrackBack ping URL for each story so that those
+wanting to TrackBack ping you manually know where to ping.
+$writeback::trackback_path_and_filename, together with $url and
+a TrackBack flavour will provide them all they need.
+
+e.g. $url$writeback::trackback_path_and_filename.trackback
+
+The writeback plugin provides an XML response to TrackBack pings in the form
+of a baked-in trackback flavour. If you alter the value of $trackback_flavour
+(why would you?), you'll have to create a set of flavour templates by hand; all
+should be blank save the content_type (text/xml) and head ($writeback::trackback_response).
+
+=head1 INSTALLATION
+
+Drop writeback into your plug-ins directory ($blosxom::plugin_dir).
+
+=head1 CONFIGURATION
+
+=head2 (REQUIRED) SPECIFYING A WRITEBACK DIRECTORY
+
+Writeback, being a well-behaved plug-in, won't do anything until you set
+$writeback_dir, create the directory, and make it write-able by Blosxom.
+
+Create a directory to save WriteBacks to (e.g. $plugin_state_dir/writeback),
+and set $writeback_dir to the path to that directory.
+
+While you can use the same directory as your blosxom $datadir (WriteBacks
+are saved as path/weblog_entry_name.wb), it's probably better to keep
+them separate.
+
+The writeback plug-in will create the appropriate paths to mimick your
+$datadir hierarchy on-the-fly. So, for a weblog entry in
+$datadir/some/path/or/other/entry.txt, WriteBacks will be kept in
+$writeback_dir/some/path/or/other/entry.wb.
+
+=head2 (OPTIONAL) ALTERING THE TRACKBACK FLAVOUR
+
+The $trackback_flavour sets the flavour the plug-in associates with incoming TrackBack pings. Unless this corresponds to the flavour associated with your trackback URL, the writeback plug-in will ignore incoming pings.
+
+=head2 (OPTIONAL) SPECIFYING AN EXTENSION FOR WRITEBACK FILES
+
+The default extension for WriteBacks is wb. You can change this if
+you wish by altering the $file_extension value.
+
+=head2 (OPTIONAL) SPECIFYING WHAT FIELDS YOU EXPECT IN YOUR COMMENTS FORM
+
+The defaults are probably ok here, but you can specify that the writeback
+plug-in should look for more fields in your comments form by adding to this
+list. You should keep at least the defaults in place so as not to break
+anything.
+
+my @fields = qw! name url title comment excerpt blog_name !;
+
+=head1 VERSION
+
+2003-09-18
+
+=head1 AUTHOR
+
+Rael Dornfest <rael@oreilly.com>, http://www.raelity.org/
+
+=head1 SEE ALSO
+
+Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/
+
+Blosxom Plugin Docs: http://www.raelity.org/apps/blosxom/plugin.shtml
+
+=head1 BUGS
+
+Address bug reports and comments to the Blosxom mailing list
+[http://www.yahoogroups.com/group/blosxom].
+
+=head1 LICENSE
+
+Blosxom and this Blosxom Plug-in
+Copyright 2003, Rael Dornfest
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Blosxom Plugin: writeback
+# Author(s): Rael Dornfest <rael@oreilly.com>
+# Version: 2003-03-23
+
+# Quick Start
+
+Welcome to the Blosxom [http://www.raelity.org/apps/blosxom/] writeback plug-in.
+
+This package provides you all you need to get writebacks up and running
+on your Blosxom weblog.
+
+Installation is quick and easy...
+
+1. Drop the writeback plug-in file, found in this package's plugins
+ directory, into your plug-ins directory (whatever you set as
+ $plugin_dir in blosxom.cgi).
+
+2. Writeback, being a well-behaved plug-in, won't do anything until you set
+ $writeback_dir.
+
+ While you can use the same directory as your blosxom $datadir (WriteBacks
+ are saved as path/weblog_entry_name.wb), it's probably better to keep
+ them separate.
+
+ I suggest: $writeback_dir = "$blosxom::plugin_state_dir/writeback";
+
+3. Visit your site. Once $writeback_dir is set, the next time you visit
+ your site, the writeback plug-in will perform some checks, creating
+ the $writeback_dir and setting appropriate permissions if it doesn'
+ already exist.
+
+ (Check your error_log for details of what's happening behind the scenes.)
+
+4. Move the contents of the flavours folder included in this distribution
+ into your Blosxom data directory (whatever you set as $datadir in
+ blosxom.cgi).
+
+ Don't move the folder itself, only the files it contains! If you don't
+ have the the sample flavours handy, you can download them from:
+
+5. Point your browser at one of your Blosxom entries, specifying the
+ writeback flavour:
+
+ http://localhost/cgi-bin/blosxom.cgi/path/to/a/post.writeback
+
+ (Replace "localhost/cgi-bin/blosxom.cgi" with your weblog's URL
+ and "/path/to/a/post" with the path to a weblog post, including its
+ filename.)
+
+For detailed documentation, take a gander at the bottom of writeback
+plug-in file itself or type:
+
+ perldoc writeback