From 3282be229999dc36c197b264d63063a18d136331 Mon Sep 17 00:00:00 2001 From: Andreas Brachold Date: Sun, 11 Nov 2007 06:55:13 +0000 Subject: * Update installation list with required modules * Remove unused/doubled provided external perl moduls --- lib/Bundle/Xxv.pm | 77 +- lib/CGI.pm | 7318 -------------------------- lib/CGI/Apache.pm | 26 - lib/CGI/Carp.pm | 524 -- lib/CGI/Cookie.pm | 478 -- lib/CGI/Fast.pm | 230 - lib/CGI/Pretty.pm | 275 - lib/CGI/Push.pm | 328 -- lib/CGI/Switch.pm | 27 - lib/CGI/Util.pm | 317 -- lib/Config/Tiny.pm | 248 - lib/Date/Manip.pm | 7362 --------------------------- lib/Digest/HMAC.pm | 111 - lib/Digest/HMAC_MD5.pm | 71 - lib/Digest/HMAC_SHA1.pm | 71 - lib/GD/Graph/Data.pm | 725 --- lib/GD/Graph/Error.pm | 346 -- lib/GD/Graph/FAQ.pod | 130 - lib/GD/Graph/area.pm | 112 - lib/GD/Graph/axestype3d.pm | 787 --- lib/GD/Graph/bars.pm | 372 -- lib/GD/Graph/bars3d.pm | 349 -- lib/GD/Graph/colour.pm | 371 -- lib/GD/Graph/cylinder.pm | 126 - lib/GD/Graph/cylinder3d.pm | 30 - lib/GD/Graph/hbars.pm | 71 - lib/GD/Graph/lines.pm | 182 - lib/GD/Graph/lines3d.pm | 522 -- lib/GD/Graph/linespoints.pm | 46 - lib/GD/Graph/mixed.pm | 99 - lib/GD/Graph/pie.pm | 446 -- lib/GD/Graph/pie3d.pm | 331 -- lib/GD/Graph/points.pm | 183 - lib/GD/Graph/utils.pm | 49 - lib/GD/Graph3d.pm | 157 - lib/HTML/TextToHTML.pm | 5266 ------------------- lib/MP3/Info.pm | 1563 ------ lib/Mail/SendEasy.pm | 6 +- lib/Net/Amazon.pm | 1255 ----- lib/Net/Amazon/Attribute/Review.pm | 104 - lib/Net/Amazon/Attribute/ReviewSet.pm | 137 - lib/Net/Amazon/Property.pm | 320 -- lib/Net/Amazon/Property/Book.pm | 152 - lib/Net/Amazon/Property/DVD.pm | 156 - lib/Net/Amazon/Property/Music.pm | 161 - lib/Net/Amazon/Request.pm | 221 - lib/Net/Amazon/Request/ASIN.pm | 139 - lib/Net/Amazon/Request/Artist.pm | 86 - lib/Net/Amazon/Request/Blended.pm | 80 - lib/Net/Amazon/Request/BrowseNode.pm | 137 - lib/Net/Amazon/Request/Exchange.pm | 91 - lib/Net/Amazon/Request/Keyword.pm | 90 - lib/Net/Amazon/Request/Manufacturer.pm | 78 - lib/Net/Amazon/Request/Power.pm | 95 - lib/Net/Amazon/Request/Seller.pm | 84 - lib/Net/Amazon/Request/Similar.pm | 95 - lib/Net/Amazon/Request/Sort.pm | 246 - lib/Net/Amazon/Request/TextStream.pm | 76 - lib/Net/Amazon/Request/UPC.pm | 94 - lib/Net/Amazon/Request/Wishlist.pm | 89 - lib/Net/Amazon/Response.pm | 214 - lib/Net/Amazon/Response/ASIN.pm | 28 - lib/Net/Amazon/Response/Artist.pm | 29 - lib/Net/Amazon/Response/Blended.pm | 73 - lib/Net/Amazon/Response/BrowseNode.pm | 29 - lib/Net/Amazon/Response/Exchange.pm | 81 - lib/Net/Amazon/Response/Keyword.pm | 29 - lib/Net/Amazon/Response/Manufacturer.pm | 29 - lib/Net/Amazon/Response/Power.pm | 28 - lib/Net/Amazon/Response/Seller.pm | 78 - lib/Net/Amazon/Response/Similar.pm | 28 - lib/Net/Amazon/Response/TextStream.pm | 28 - lib/Net/Amazon/Response/UPC.pm | 40 - lib/Net/Amazon/Response/Wishlist.pm | 29 - lib/Net/Amazon/Result/Seller.pm | 130 - lib/Net/Amazon/Result/Seller/Listing.pm | 146 - lib/Template.pm | 961 ---- lib/Template/Base.pm | 314 -- lib/Template/Config.pm | 467 -- lib/Template/Constants.pm | 287 -- lib/Template/Context.pm | 1570 ------ lib/Template/Directive.pm | 1004 ---- lib/Template/Document.pm | 492 -- lib/Template/Exception.pm | 254 - lib/Template/FAQ.pod | 329 -- lib/Template/Filters.pm | 1448 ------ lib/Template/Grammar.pm | 6179 ---------------------- lib/Template/Iterator.pm | 456 -- lib/Template/Library/HTML.pod | 316 -- lib/Template/Library/PostScript.pod | 78 - lib/Template/Library/Splash.pod | 1030 ---- lib/Template/Manual.pod | 180 - lib/Template/Manual/Config.pod | 2122 -------- lib/Template/Manual/Credits.pod | 188 - lib/Template/Manual/Directives.pod | 2179 -------- lib/Template/Manual/Filters.pod | 529 -- lib/Template/Manual/Internals.pod | 556 -- lib/Template/Manual/Intro.pod | 295 -- lib/Template/Manual/Plugins.pod | 552 -- lib/Template/Manual/Refs.pod | 171 - lib/Template/Manual/Syntax.pod | 306 -- lib/Template/Manual/VMethods.pod | 529 -- lib/Template/Manual/Variables.pod | 868 ---- lib/Template/Manual/Views.pod | 642 --- lib/Template/Modules.pod | 448 -- lib/Template/Namespace/Constants.pm | 205 - lib/Template/Parser.pm | 1446 ------ lib/Template/Plugin.pm | 409 -- lib/Template/Plugin/Autoformat.pm | 242 - lib/Template/Plugin/CGI.pm | 168 - lib/Template/Plugin/DBI.pm | 947 ---- lib/Template/Plugin/Datafile.pm | 198 - lib/Template/Plugin/Date.pm | 361 -- lib/Template/Plugin/Directory.pm | 410 -- lib/Template/Plugin/Dumper.pm | 179 - lib/Template/Plugin/File.pm | 416 -- lib/Template/Plugin/Filter.pm | 436 -- lib/Template/Plugin/Format.pm | 124 - lib/Template/Plugin/GD/Constants.pm | 138 - lib/Template/Plugin/GD/Graph/area.pm | 148 - lib/Template/Plugin/GD/Graph/bars.pm | 191 - lib/Template/Plugin/GD/Graph/bars3d.pm | 166 - lib/Template/Plugin/GD/Graph/lines.pm | 178 - lib/Template/Plugin/GD/Graph/lines3d.pm | 166 - lib/Template/Plugin/GD/Graph/linespoints.pm | 158 - lib/Template/Plugin/GD/Graph/mixed.pm | 176 - lib/Template/Plugin/GD/Graph/pie.pm | 141 - lib/Template/Plugin/GD/Graph/pie3d.pm | 145 - lib/Template/Plugin/GD/Graph/points.pm | 155 - lib/Template/Plugin/GD/Image.pm | 184 - lib/Template/Plugin/GD/Polygon.pm | 155 - lib/Template/Plugin/GD/Text.pm | 140 - lib/Template/Plugin/GD/Text/Align.pm | 147 - lib/Template/Plugin/GD/Text/Wrap.pm | 183 - lib/Template/Plugin/HTML.pm | 197 - lib/Template/Plugin/Image.pm | 425 -- lib/Template/Plugin/Iterator.pm | 118 - lib/Template/Plugin/Pod.pm | 116 - lib/Template/Plugin/Procedural.pm | 170 - lib/Template/Plugin/String.pm | 796 --- lib/Template/Plugin/Table.pm | 464 -- lib/Template/Plugin/URL.pm | 236 - lib/Template/Plugin/View.pm | 127 - lib/Template/Plugin/Wrap.pm | 162 - lib/Template/Plugin/XML/DOM.pm | 841 --- lib/Template/Plugin/XML/RSS.pm | 194 - lib/Template/Plugin/XML/Simple.pm | 124 - lib/Template/Plugin/XML/Style.pm | 357 -- lib/Template/Plugin/XML/XPath.pm | 284 -- lib/Template/Plugins.pm | 1041 ---- lib/Template/Provider.pm | 1449 ------ lib/Template/Service.pm | 775 --- lib/Template/Stash.pm | 1040 ---- lib/Template/Stash/Context.pm | 791 --- lib/Template/Stash/XS.pm | 176 - lib/Template/Test.pm | 711 --- lib/Template/Tools/tpage.pod | 76 - lib/Template/Tools/ttree.pod | 332 -- lib/Template/Tutorial.pod | 109 - lib/Template/Tutorial/Datafile.pod | 461 -- lib/Template/Tutorial/Web.pod | 801 --- lib/Template/View.pm | 752 --- lib/Text/Wrap.pm | 106 - lib/URI.pm | 1019 ---- lib/URI/Escape.pm | 218 - lib/URI/Heuristic.pm | 224 - lib/URI/QueryParam.pm | 200 - lib/URI/Split.pm | 96 - lib/URI/URL.pm | 305 -- lib/URI/WithBase.pm | 171 - lib/URI/_foreign.pm | 6 - lib/URI/_generic.pm | 249 - lib/URI/_ldap.pm | 140 - lib/URI/_login.pm | 10 - lib/URI/_query.pm | 81 - lib/URI/_segment.pm | 20 - lib/URI/_server.pm | 106 - lib/URI/_userpass.pm | 51 - lib/URI/data.pm | 139 - lib/URI/file.pm | 329 -- lib/URI/file/Base.pm | 80 - lib/URI/file/FAT.pm | 23 - lib/URI/file/Mac.pm | 120 - lib/URI/file/OS2.pm | 28 - lib/URI/file/QNX.pm | 18 - lib/URI/file/Unix.pm | 55 - lib/URI/file/Win32.pm | 84 - lib/URI/ftp.pm | 45 - lib/URI/gopher.pm | 94 - lib/URI/http.pm | 25 - lib/URI/https.pm | 7 - lib/URI/ldap.pm | 122 - lib/URI/ldapi.pm | 30 - lib/URI/ldaps.pm | 7 - lib/URI/mailto.pm | 72 - lib/URI/mms.pm | 8 - lib/URI/news.pm | 68 - lib/URI/nntp.pm | 6 - lib/URI/pop.pm | 68 - lib/URI/rlogin.pm | 7 - lib/URI/rsync.pm | 12 - lib/URI/rtsp.pm | 8 - lib/URI/rtspu.pm | 8 - lib/URI/sip.pm | 86 - lib/URI/sips.pm | 7 - lib/URI/snews.pm | 8 - lib/URI/ssh.pm | 9 - lib/URI/telnet.pm | 7 - lib/URI/tn3270.pm | 7 - lib/URI/urn.pm | 97 - lib/URI/urn/isbn.pm | 58 - lib/URI/urn/oid.pm | 18 - lib/XML/Dumper.pm | 897 ---- lib/XML/Simple.pm | 3041 ----------- lib/XML/Stream.pm | 3268 ------------ lib/XML/Stream/Namespace.pm | 190 - lib/XML/Stream/Node.pm | 944 ---- lib/XML/Stream/Parser.pm | 567 --- lib/XML/Stream/Parser/DTD.pm | 769 --- lib/XML/Stream/Tree.pm | 682 --- lib/XML/Stream/XPath.pm | 50 - lib/XML/Stream/XPath/Op.pm | 919 ---- lib/XML/Stream/XPath/Query.pm | 374 -- lib/XML/Stream/XPath/Value.pm | 153 - lib/XXV/MODULES/CONFIG.pm | 2 +- lib/XXV/MODULES/TELNET.pm | 3 +- lib/XXV/OUTPUT/Console.pm | 9 +- lib/XXV/OUTPUT/Html.pm | 6 +- lib/XXV/OUTPUT/Wml.pm | 2 +- 229 files changed, 43 insertions(+), 97319 deletions(-) delete mode 100644 lib/CGI.pm delete mode 100644 lib/CGI/Apache.pm delete mode 100644 lib/CGI/Carp.pm delete mode 100644 lib/CGI/Cookie.pm delete mode 100644 lib/CGI/Fast.pm delete mode 100644 lib/CGI/Pretty.pm delete mode 100644 lib/CGI/Push.pm delete mode 100644 lib/CGI/Switch.pm delete mode 100644 lib/CGI/Util.pm delete mode 100644 lib/Config/Tiny.pm delete mode 100644 lib/Date/Manip.pm delete mode 100644 lib/Digest/HMAC.pm delete mode 100644 lib/Digest/HMAC_MD5.pm delete mode 100644 lib/Digest/HMAC_SHA1.pm delete mode 100644 lib/GD/Graph/Data.pm delete mode 100644 lib/GD/Graph/Error.pm delete mode 100644 lib/GD/Graph/FAQ.pod delete mode 100644 lib/GD/Graph/area.pm delete mode 100644 lib/GD/Graph/axestype3d.pm delete mode 100644 lib/GD/Graph/bars.pm delete mode 100644 lib/GD/Graph/bars3d.pm delete mode 100644 lib/GD/Graph/colour.pm delete mode 100644 lib/GD/Graph/cylinder.pm delete mode 100644 lib/GD/Graph/cylinder3d.pm delete mode 100644 lib/GD/Graph/hbars.pm delete mode 100644 lib/GD/Graph/lines.pm delete mode 100644 lib/GD/Graph/lines3d.pm delete mode 100644 lib/GD/Graph/linespoints.pm delete mode 100644 lib/GD/Graph/mixed.pm delete mode 100644 lib/GD/Graph/pie.pm delete mode 100644 lib/GD/Graph/pie3d.pm delete mode 100644 lib/GD/Graph/points.pm delete mode 100644 lib/GD/Graph/utils.pm delete mode 100644 lib/GD/Graph3d.pm delete mode 100644 lib/HTML/TextToHTML.pm delete mode 100644 lib/MP3/Info.pm delete mode 100644 lib/Net/Amazon.pm delete mode 100644 lib/Net/Amazon/Attribute/Review.pm delete mode 100644 lib/Net/Amazon/Attribute/ReviewSet.pm delete mode 100644 lib/Net/Amazon/Property.pm delete mode 100644 lib/Net/Amazon/Property/Book.pm delete mode 100644 lib/Net/Amazon/Property/DVD.pm delete mode 100644 lib/Net/Amazon/Property/Music.pm delete mode 100644 lib/Net/Amazon/Request.pm delete mode 100644 lib/Net/Amazon/Request/ASIN.pm delete mode 100644 lib/Net/Amazon/Request/Artist.pm delete mode 100644 lib/Net/Amazon/Request/Blended.pm delete mode 100644 lib/Net/Amazon/Request/BrowseNode.pm delete mode 100644 lib/Net/Amazon/Request/Exchange.pm delete mode 100644 lib/Net/Amazon/Request/Keyword.pm delete mode 100644 lib/Net/Amazon/Request/Manufacturer.pm delete mode 100644 lib/Net/Amazon/Request/Power.pm delete mode 100644 lib/Net/Amazon/Request/Seller.pm delete mode 100644 lib/Net/Amazon/Request/Similar.pm delete mode 100644 lib/Net/Amazon/Request/Sort.pm delete mode 100644 lib/Net/Amazon/Request/TextStream.pm delete mode 100644 lib/Net/Amazon/Request/UPC.pm delete mode 100644 lib/Net/Amazon/Request/Wishlist.pm delete mode 100644 lib/Net/Amazon/Response.pm delete mode 100644 lib/Net/Amazon/Response/ASIN.pm delete mode 100644 lib/Net/Amazon/Response/Artist.pm delete mode 100644 lib/Net/Amazon/Response/Blended.pm delete mode 100644 lib/Net/Amazon/Response/BrowseNode.pm delete mode 100644 lib/Net/Amazon/Response/Exchange.pm delete mode 100644 lib/Net/Amazon/Response/Keyword.pm delete mode 100644 lib/Net/Amazon/Response/Manufacturer.pm delete mode 100644 lib/Net/Amazon/Response/Power.pm delete mode 100644 lib/Net/Amazon/Response/Seller.pm delete mode 100644 lib/Net/Amazon/Response/Similar.pm delete mode 100644 lib/Net/Amazon/Response/TextStream.pm delete mode 100644 lib/Net/Amazon/Response/UPC.pm delete mode 100644 lib/Net/Amazon/Response/Wishlist.pm delete mode 100644 lib/Net/Amazon/Result/Seller.pm delete mode 100644 lib/Net/Amazon/Result/Seller/Listing.pm delete mode 100644 lib/Template.pm delete mode 100644 lib/Template/Base.pm delete mode 100644 lib/Template/Config.pm delete mode 100644 lib/Template/Constants.pm delete mode 100644 lib/Template/Context.pm delete mode 100644 lib/Template/Directive.pm delete mode 100644 lib/Template/Document.pm delete mode 100644 lib/Template/Exception.pm delete mode 100644 lib/Template/FAQ.pod delete mode 100644 lib/Template/Filters.pm delete mode 100644 lib/Template/Grammar.pm delete mode 100644 lib/Template/Iterator.pm delete mode 100644 lib/Template/Library/HTML.pod delete mode 100644 lib/Template/Library/PostScript.pod delete mode 100644 lib/Template/Library/Splash.pod delete mode 100644 lib/Template/Manual.pod delete mode 100644 lib/Template/Manual/Config.pod delete mode 100644 lib/Template/Manual/Credits.pod delete mode 100644 lib/Template/Manual/Directives.pod delete mode 100644 lib/Template/Manual/Filters.pod delete mode 100644 lib/Template/Manual/Internals.pod delete mode 100644 lib/Template/Manual/Intro.pod delete mode 100644 lib/Template/Manual/Plugins.pod delete mode 100644 lib/Template/Manual/Refs.pod delete mode 100644 lib/Template/Manual/Syntax.pod delete mode 100644 lib/Template/Manual/VMethods.pod delete mode 100644 lib/Template/Manual/Variables.pod delete mode 100644 lib/Template/Manual/Views.pod delete mode 100644 lib/Template/Modules.pod delete mode 100644 lib/Template/Namespace/Constants.pm delete mode 100644 lib/Template/Parser.pm delete mode 100644 lib/Template/Plugin.pm delete mode 100644 lib/Template/Plugin/Autoformat.pm delete mode 100644 lib/Template/Plugin/CGI.pm delete mode 100644 lib/Template/Plugin/DBI.pm delete mode 100644 lib/Template/Plugin/Datafile.pm delete mode 100644 lib/Template/Plugin/Date.pm delete mode 100644 lib/Template/Plugin/Directory.pm delete mode 100644 lib/Template/Plugin/Dumper.pm delete mode 100644 lib/Template/Plugin/File.pm delete mode 100644 lib/Template/Plugin/Filter.pm delete mode 100644 lib/Template/Plugin/Format.pm delete mode 100644 lib/Template/Plugin/GD/Constants.pm delete mode 100644 lib/Template/Plugin/GD/Graph/area.pm delete mode 100644 lib/Template/Plugin/GD/Graph/bars.pm delete mode 100644 lib/Template/Plugin/GD/Graph/bars3d.pm delete mode 100644 lib/Template/Plugin/GD/Graph/lines.pm delete mode 100644 lib/Template/Plugin/GD/Graph/lines3d.pm delete mode 100644 lib/Template/Plugin/GD/Graph/linespoints.pm delete mode 100644 lib/Template/Plugin/GD/Graph/mixed.pm delete mode 100644 lib/Template/Plugin/GD/Graph/pie.pm delete mode 100644 lib/Template/Plugin/GD/Graph/pie3d.pm delete mode 100644 lib/Template/Plugin/GD/Graph/points.pm delete mode 100644 lib/Template/Plugin/GD/Image.pm delete mode 100644 lib/Template/Plugin/GD/Polygon.pm delete mode 100644 lib/Template/Plugin/GD/Text.pm delete mode 100644 lib/Template/Plugin/GD/Text/Align.pm delete mode 100644 lib/Template/Plugin/GD/Text/Wrap.pm delete mode 100644 lib/Template/Plugin/HTML.pm delete mode 100644 lib/Template/Plugin/Image.pm delete mode 100644 lib/Template/Plugin/Iterator.pm delete mode 100644 lib/Template/Plugin/Pod.pm delete mode 100644 lib/Template/Plugin/Procedural.pm delete mode 100644 lib/Template/Plugin/String.pm delete mode 100644 lib/Template/Plugin/Table.pm delete mode 100644 lib/Template/Plugin/URL.pm delete mode 100644 lib/Template/Plugin/View.pm delete mode 100644 lib/Template/Plugin/Wrap.pm delete mode 100644 lib/Template/Plugin/XML/DOM.pm delete mode 100644 lib/Template/Plugin/XML/RSS.pm delete mode 100644 lib/Template/Plugin/XML/Simple.pm delete mode 100644 lib/Template/Plugin/XML/Style.pm delete mode 100644 lib/Template/Plugin/XML/XPath.pm delete mode 100644 lib/Template/Plugins.pm delete mode 100644 lib/Template/Provider.pm delete mode 100644 lib/Template/Service.pm delete mode 100644 lib/Template/Stash.pm delete mode 100644 lib/Template/Stash/Context.pm delete mode 100644 lib/Template/Stash/XS.pm delete mode 100644 lib/Template/Test.pm delete mode 100644 lib/Template/Tools/tpage.pod delete mode 100644 lib/Template/Tools/ttree.pod delete mode 100644 lib/Template/Tutorial.pod delete mode 100644 lib/Template/Tutorial/Datafile.pod delete mode 100644 lib/Template/Tutorial/Web.pod delete mode 100644 lib/Template/View.pm delete mode 100644 lib/Text/Wrap.pm delete mode 100644 lib/URI.pm delete mode 100644 lib/URI/Escape.pm delete mode 100644 lib/URI/Heuristic.pm delete mode 100644 lib/URI/QueryParam.pm delete mode 100644 lib/URI/Split.pm delete mode 100644 lib/URI/URL.pm delete mode 100644 lib/URI/WithBase.pm delete mode 100644 lib/URI/_foreign.pm delete mode 100644 lib/URI/_generic.pm delete mode 100644 lib/URI/_ldap.pm delete mode 100644 lib/URI/_login.pm delete mode 100644 lib/URI/_query.pm delete mode 100644 lib/URI/_segment.pm delete mode 100644 lib/URI/_server.pm delete mode 100644 lib/URI/_userpass.pm delete mode 100644 lib/URI/data.pm delete mode 100644 lib/URI/file.pm delete mode 100644 lib/URI/file/Base.pm delete mode 100644 lib/URI/file/FAT.pm delete mode 100644 lib/URI/file/Mac.pm delete mode 100644 lib/URI/file/OS2.pm delete mode 100644 lib/URI/file/QNX.pm delete mode 100644 lib/URI/file/Unix.pm delete mode 100644 lib/URI/file/Win32.pm delete mode 100644 lib/URI/ftp.pm delete mode 100644 lib/URI/gopher.pm delete mode 100644 lib/URI/http.pm delete mode 100644 lib/URI/https.pm delete mode 100644 lib/URI/ldap.pm delete mode 100644 lib/URI/ldapi.pm delete mode 100644 lib/URI/ldaps.pm delete mode 100644 lib/URI/mailto.pm delete mode 100644 lib/URI/mms.pm delete mode 100644 lib/URI/news.pm delete mode 100644 lib/URI/nntp.pm delete mode 100644 lib/URI/pop.pm delete mode 100644 lib/URI/rlogin.pm delete mode 100644 lib/URI/rsync.pm delete mode 100644 lib/URI/rtsp.pm delete mode 100644 lib/URI/rtspu.pm delete mode 100644 lib/URI/sip.pm delete mode 100644 lib/URI/sips.pm delete mode 100644 lib/URI/snews.pm delete mode 100644 lib/URI/ssh.pm delete mode 100644 lib/URI/telnet.pm delete mode 100644 lib/URI/tn3270.pm delete mode 100644 lib/URI/urn.pm delete mode 100644 lib/URI/urn/isbn.pm delete mode 100644 lib/URI/urn/oid.pm delete mode 100644 lib/XML/Dumper.pm delete mode 100644 lib/XML/Simple.pm delete mode 100644 lib/XML/Stream.pm delete mode 100644 lib/XML/Stream/Namespace.pm delete mode 100644 lib/XML/Stream/Node.pm delete mode 100644 lib/XML/Stream/Parser.pm delete mode 100644 lib/XML/Stream/Parser/DTD.pm delete mode 100644 lib/XML/Stream/Tree.pm delete mode 100644 lib/XML/Stream/XPath.pm delete mode 100644 lib/XML/Stream/XPath/Op.pm delete mode 100644 lib/XML/Stream/XPath/Query.pm delete mode 100644 lib/XML/Stream/XPath/Value.pm (limited to 'lib') diff --git a/lib/Bundle/Xxv.pm b/lib/Bundle/Xxv.pm index 411e679..a881441 100644 --- a/lib/Bundle/Xxv.pm +++ b/lib/Bundle/Xxv.pm @@ -2,7 +2,7 @@ package Bundle::Xxv; use strict; use warnings; -$VERSION = '0.04'; +$VERSION = '1.0'; 1; @@ -20,55 +20,38 @@ Bundle::Xxv - A bundle to install various xxv related modules =head1 CONTENTS -Test::Simple - Test package to test varios funktion -DBI - Database package for perl -DBD::mysql - Database driver to connect over DBI +CGI +Compress::Zlib Config::Tiny -Event - the great famos Event libary -MIME::Base64 - Code library to encrypt and decrypt Strings -Time::HiRes - High Resolutin timer -Locale::gettext - Localization in perl -Net::Telnet -URI -URI::file -URI::URL -Compress::Zlib - for compressed output -HTML::Tagset -HTML::Parser -HTML::Form -HTTP::Status -HTTP::Daemon -HTTP::Request -LWP::UserAgent -LWP -WWW::Mechanize - for Robot Module -Data::Random -WWW::Mechanize::FormFiller -GD - GD Image library -Digest::SHA1 -Digest::HMAC_MD5 +Data::Dumper +Date::Manip +DBD::mysql +DBI Digest::MD5 -Net::IP -Net::DNS -XML::Parser -XML::RSS - create an rss feed -Math::BigInt::FastCalc -Authen::SASL -XML::Stream -Net::XMPP - create an Jabber message -Proc::Killfam - killall for Perl -Proc::ProcessTable -Term::ReadLine::Gnu - Better Support for telnet interface -Template -SOAP::Lite -MP3::Icecast -MP3::Info -CGI -LWP::Simple -Net::Amazon +Digest::HMAC_MD5 +Event +GD +Getopt::Long +HTML::TextToHTML +HTML::TreeBuilder +JSON +LWP::Simple +LWP::UserAgent +Locale::gettext +MIME::Base64 +MP3::Info +Net::Amazon Net::Amazon::Request::Artist -JSON - Parse and convert to JSON (JavaScript Object Notation) - +Net::Telnet +Net::XMPP +SOAP::Lite +SOAP::Transport::HTTP +Template +Time::Local +Time::HiRes +URI::Escape +XML::RSS +XML::Simple =head1 DESCRIPTION diff --git a/lib/CGI.pm b/lib/CGI.pm deleted file mode 100644 index 148b861..0000000 --- a/lib/CGI.pm +++ /dev/null @@ -1,7318 +0,0 @@ -package CGI; -require 5.004; -use Carp 'croak'; - -# See the bottom of this file for the POD documentation. Search for the -# string '=head'. - -# You can run this file through either pod2man or pod2html to produce pretty -# documentation in manual or html file format (these utilities are part of the -# Perl 5 distribution). - -# Copyright 1995-1998 Lincoln D. Stein. All rights reserved. -# It may be used and modified freely, but I do request that this copyright -# notice remain attached to the file. You may modify this module as you -# wish, but if you redistribute a modified version, please attach a note -# listing the modifications you have made. - -# The most recent version and complete docs are available at: -# http://stein.cshl.org/WWW/software/CGI/ - -$CGI::revision = '$Id: CGI.pm,v 1.165 2004/04/12 20:37:26 lstein Exp $'; -$CGI::VERSION=3.05; - -# HARD-CODED LOCATION FOR FILE UPLOAD TEMPORARY FILES. -# UNCOMMENT THIS ONLY IF YOU KNOW WHAT YOU'RE DOING. -# $CGITempFile::TMPDIRECTORY = '/usr/tmp'; -use CGI::Util qw(rearrange make_attributes unescape escape expires ebcdic2ascii ascii2ebcdic); - -#use constant XHTML_DTD => ['-//W3C//DTD XHTML Basic 1.0//EN', -# 'http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd']; - -use constant XHTML_DTD => ['-//W3C//DTD XHTML 1.0 Transitional//EN', - 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd']; - -{ - local $^W = 0; - $TAINTED = substr("$0$^X",0,0); -} - -$MOD_PERL = 0; # no mod_perl by default -@SAVED_SYMBOLS = (); - -# >>>>> Here are some globals that you might want to adjust <<<<<< -sub initialize_globals { - # Set this to 1 to enable copious autoloader debugging messages - $AUTOLOAD_DEBUG = 0; - - # Set this to 1 to generate XTML-compatible output - $XHTML = 1; - - # Change this to the preferred DTD to print in start_html() - # or use default_dtd('text of DTD to use'); - $DEFAULT_DTD = [ '-//W3C//DTD HTML 4.01 Transitional//EN', - 'http://www.w3.org/TR/html4/loose.dtd' ] ; - - # Set this to 1 to enable NOSTICKY scripts - # or: - # 1) use CGI qw(-nosticky) - # 2) $CGI::nosticky(1) - $NOSTICKY = 0; - - # Set this to 1 to enable NPH scripts - # or: - # 1) use CGI qw(-nph) - # 2) CGI::nph(1) - # 3) print header(-nph=>1) - $NPH = 0; - - # Set this to 1 to enable debugging from @ARGV - # Set to 2 to enable debugging from STDIN - $DEBUG = 1; - - # Set this to 1 to make the temporary files created - # during file uploads safe from prying eyes - # or do... - # 1) use CGI qw(:private_tempfiles) - # 2) CGI::private_tempfiles(1); - $PRIVATE_TEMPFILES = 0; - - # Set this to 1 to cause files uploaded in multipart documents - # to be closed, instead of caching the file handle - # or: - # 1) use CGI qw(:close_upload_files) - # 2) $CGI::close_upload_files(1); - # Uploads with many files run out of file handles. - # Also, for performance, since the file is already on disk, - # it can just be renamed, instead of read and written. - $CLOSE_UPLOAD_FILES = 0; - - # Set this to a positive value to limit the size of a POSTing - # to a certain number of bytes: - $POST_MAX = -1; - - # Change this to 1 to disable uploads entirely: - $DISABLE_UPLOADS = 0; - - # Automatically determined -- don't change - $EBCDIC = 0; - - # Change this to 1 to suppress redundant HTTP headers - $HEADERS_ONCE = 0; - - # separate the name=value pairs by semicolons rather than ampersands - $USE_PARAM_SEMICOLONS = 1; - - # Do not include undefined params parsed from query string - # use CGI qw(-no_undef_params); - $NO_UNDEF_PARAMS = 0; - - # Other globals that you shouldn't worry about. - undef $Q; - $BEEN_THERE = 0; - $DTD_PUBLIC_IDENTIFIER = ""; - undef @QUERY_PARAM; - undef %EXPORT; - undef $QUERY_CHARSET; - undef %QUERY_FIELDNAMES; - - # prevent complaints by mod_perl - 1; -} - -# ------------------ START OF THE LIBRARY ------------ - -*end_form = \&endform; - -# make mod_perlhappy -initialize_globals(); - -# FIGURE OUT THE OS WE'RE RUNNING UNDER -# Some systems support the $^O variable. If not -# available then require() the Config library -unless ($OS) { - unless ($OS = $^O) { - require Config; - $OS = $Config::Config{'osname'}; - } -} -if ($OS =~ /^MSWin/i) { - $OS = 'WINDOWS'; -} elsif ($OS =~ /^VMS/i) { - $OS = 'VMS'; -} elsif ($OS =~ /^dos/i) { - $OS = 'DOS'; -} elsif ($OS =~ /^MacOS/i) { - $OS = 'MACINTOSH'; -} elsif ($OS =~ /^os2/i) { - $OS = 'OS2'; -} elsif ($OS =~ /^epoc/i) { - $OS = 'EPOC'; -} elsif ($OS =~ /^cygwin/i) { - $OS = 'CYGWIN'; -} else { - $OS = 'UNIX'; -} - -# Some OS logic. Binary mode enabled on DOS, NT and VMS -$needs_binmode = $OS=~/^(WINDOWS|DOS|OS2|MSWin|CYGWIN)/; - -# This is the default class for the CGI object to use when all else fails. -$DefaultClass = 'CGI' unless defined $CGI::DefaultClass; - -# This is where to look for autoloaded routines. -$AutoloadClass = $DefaultClass unless defined $CGI::AutoloadClass; - -# The path separator is a slash, backslash or semicolon, depending -# on the paltform. -$SL = { - UNIX => '/', OS2 => '\\', EPOC => '/', CYGWIN => '/', - WINDOWS => '\\', DOS => '\\', MACINTOSH => ':', VMS => '/' - }->{$OS}; - -# This no longer seems to be necessary -# Turn on NPH scripts by default when running under IIS server! -# $NPH++ if defined($ENV{'SERVER_SOFTWARE'}) && $ENV{'SERVER_SOFTWARE'}=~/IIS/; -$IIS++ if defined($ENV{'SERVER_SOFTWARE'}) && $ENV{'SERVER_SOFTWARE'}=~/IIS/; - -# Turn on special checking for Doug MacEachern's modperl -if (exists $ENV{MOD_PERL}) { - eval "require mod_perl"; - # mod_perl handlers may run system() on scripts using CGI.pm; - # Make sure so we don't get fooled by inherited $ENV{MOD_PERL} - if (defined $mod_perl::VERSION) { - if ($mod_perl::VERSION >= 1.99) { - $MOD_PERL = 2; - require Apache::Response; - require Apache::RequestRec; - require Apache::RequestUtil; - require APR::Pool; - } else { - $MOD_PERL = 1; - require Apache; - } - } -} - -# Turn on special checking for ActiveState's PerlEx -$PERLEX++ if defined($ENV{'GATEWAY_INTERFACE'}) && $ENV{'GATEWAY_INTERFACE'} =~ /^CGI-PerlEx/; - -# Define the CRLF sequence. I can't use a simple "\r\n" because the meaning -# of "\n" is different on different OS's (sometimes it generates CRLF, sometimes LF -# and sometimes CR). The most popular VMS web server -# doesn't accept CRLF -- instead it wants a LR. EBCDIC machines don't -# use ASCII, so \015\012 means something different. I find this all -# really annoying. -$EBCDIC = "\t" ne "\011"; -if ($OS eq 'VMS') { - $CRLF = "\n"; -} elsif ($EBCDIC) { - $CRLF= "\r\n"; -} else { - $CRLF = "\015\012"; -} - -if ($needs_binmode) { - $CGI::DefaultClass->binmode(\*main::STDOUT); - $CGI::DefaultClass->binmode(\*main::STDIN); - $CGI::DefaultClass->binmode(\*main::STDERR); -} - -%EXPORT_TAGS = ( - ':html2'=>['h1'..'h6',qw/p br hr ol ul li dl dt dd menu code var strong em - tt u i b blockquote pre img a address cite samp dfn html head - base body Link nextid title meta kbd start_html end_html - input Select option comment charset escapeHTML/], - ':html3'=>[qw/div table caption th td TR Tr sup Sub strike applet Param - embed basefont style span layer ilayer font frameset frame script small big Area Map/], - ':html4'=>[qw/abbr acronym bdo col colgroup del fieldset iframe - ins label legend noframes noscript object optgroup Q - thead tbody tfoot/], - ':netscape'=>[qw/blink fontsize center/], - ':form'=>[qw/textfield textarea filefield password_field hidden checkbox checkbox_group - submit reset defaults radio_group popup_menu button autoEscape - scrolling_list image_button start_form end_form startform endform - start_multipart_form end_multipart_form isindex tmpFileName uploadInfo URL_ENCODED MULTIPART/], - ':cgi'=>[qw/param upload path_info path_translated url self_url script_name cookie Dump - raw_cookie request_method query_string Accept user_agent remote_host content_type - remote_addr referer server_name server_software server_port server_protocol virtual_port - virtual_host remote_ident auth_type http append - save_parameters restore_parameters param_fetch - remote_user user_name header redirect import_names put - Delete Delete_all url_param cgi_error/], - ':ssl' => [qw/https/], - ':cgi-lib' => [qw/ReadParse PrintHeader HtmlTop HtmlBot SplitParam Vars/], - ':html' => [qw/:html2 :html3 :html4 :netscape/], - ':standard' => [qw/:html2 :html3 :html4 :form :cgi/], - ':push' => [qw/multipart_init multipart_start multipart_end multipart_final/], - ':all' => [qw/:html2 :html3 :netscape :form :cgi :internal :html4/] - ); - -# to import symbols into caller -sub import { - my $self = shift; - - # This causes modules to clash. - undef %EXPORT_OK; - undef %EXPORT; - - $self->_setup_symbols(@_); - my ($callpack, $callfile, $callline) = caller; - - # To allow overriding, search through the packages - # Till we find one in which the correct subroutine is defined. - my @packages = ($self,@{"$self\:\:ISA"}); - foreach $sym (keys %EXPORT) { - my $pck; - my $def = ${"$self\:\:AutoloadClass"} || $DefaultClass; - foreach $pck (@packages) { - if (defined(&{"$pck\:\:$sym"})) { - $def = $pck; - last; - } - } - *{"${callpack}::$sym"} = \&{"$def\:\:$sym"}; - } -} - -sub compile { - my $pack = shift; - $pack->_setup_symbols('-compile',@_); -} - -sub expand_tags { - my($tag) = @_; - return ("start_$1","end_$1") if $tag=~/^(?:\*|start_|end_)(.+)/; - my(@r); - return ($tag) unless $EXPORT_TAGS{$tag}; - foreach (@{$EXPORT_TAGS{$tag}}) { - push(@r,&expand_tags($_)); - } - return @r; -} - -#### Method: new -# The new routine. This will check the current environment -# for an existing query string, and initialize itself, if so. -#### -sub new { - my($class,@initializer) = @_; - my $self = {}; - - bless $self,ref $class || $class || $DefaultClass; - if (ref($initializer[0]) - && (UNIVERSAL::isa($initializer[0],'Apache') - || - UNIVERSAL::isa($initializer[0],'Apache::RequestRec') - )) { - $self->r(shift @initializer); - } - if (ref($initializer[0]) - && (UNIVERSAL::isa($initializer[0],'CODE'))) { - $self->upload_hook(shift @initializer, shift @initializer); - } - if ($MOD_PERL) { - $self->r(Apache->request) unless $self->r; - my $r = $self->r; - if ($MOD_PERL == 1) { - $r->register_cleanup(\&CGI::_reset_globals); - } - else { - # XXX: once we have the new API - # will do a real PerlOptions -SetupEnv check - $r->subprocess_env unless exists $ENV{REQUEST_METHOD}; - $r->pool->cleanup_register(\&CGI::_reset_globals); - } - undef $NPH; - } - $self->_reset_globals if $PERLEX; - $self->init(@initializer); - return $self; -} - -# We provide a DESTROY method so that we can ensure that -# temporary files are closed (via Fh->DESTROY) before they -# are unlinked (via CGITempFile->DESTROY) because it is not -# possible to unlink an open file on Win32. We explicitly -# call DESTROY on each, rather than just undefing them and -# letting Perl DESTROY them by garbage collection, in case the -# user is still holding any reference to them as well. -sub DESTROY { - my $self = shift; - foreach my $href (values %{$self->{'.tmpfiles'}}) { - $href->{hndl}->DESTROY if defined $href->{hndl}; - $href->{name}->DESTROY if defined $href->{name}; - } -} - -sub r { - my $self = shift; - my $r = $self->{'.r'}; - $self->{'.r'} = shift if @_; - $r; -} - -sub upload_hook { - my ($self,$hook,$data) = self_or_default(@_); - $self->{'.upload_hook'} = $hook; - $self->{'.upload_data'} = $data; -} - -#### Method: param -# Returns the value(s)of a named parameter. -# If invoked in a list context, returns the -# entire list. Otherwise returns the first -# member of the list. -# If name is not provided, return a list of all -# the known parameters names available. -# If more than one argument is provided, the -# second and subsequent arguments are used to -# set the value of the parameter. -#### -sub param { - my($self,@p) = self_or_default(@_); - return $self->all_parameters unless @p; - my($name,$value,@other); - - # For compatibility between old calling style and use_named_parameters() style, - # we have to special case for a single parameter present. - if (@p > 1) { - ($name,$value,@other) = rearrange([NAME,[DEFAULT,VALUE,VALUES]],@p); - my(@values); - - if (substr($p[0],0,1) eq '-') { - @values = defined($value) ? (ref($value) && ref($value) eq 'ARRAY' ? @{$value} : $value) : (); - } else { - foreach ($value,@other) { - push(@values,$_) if defined($_); - } - } - # If values is provided, then we set it. - if (@values) { - $self->add_parameter($name); - $self->{$name}=[@values]; - } - } else { - $name = $p[0]; - } - - return unless defined($name) && $self->{$name}; - return wantarray ? @{$self->{$name}} : $self->{$name}->[0]; -} - -sub self_or_default { - return @_ if defined($_[0]) && (!ref($_[0])) &&($_[0] eq 'CGI'); - unless (defined($_[0]) && - (ref($_[0]) eq 'CGI' || UNIVERSAL::isa($_[0],'CGI')) # slightly optimized for common case - ) { - $Q = $CGI::DefaultClass->new unless defined($Q); - unshift(@_,$Q); - } - return wantarray ? @_ : $Q; -} - -sub self_or_CGI { - local $^W=0; # prevent a warning - if (defined($_[0]) && - (substr(ref($_[0]),0,3) eq 'CGI' - || UNIVERSAL::isa($_[0],'CGI'))) { - return @_; - } else { - return ($DefaultClass,@_); - } -} - -######################################## -# THESE METHODS ARE MORE OR LESS PRIVATE -# GO TO THE __DATA__ SECTION TO SEE MORE -# PUBLIC METHODS -######################################## - -# Initialize the query object from the environment. -# If a parameter list is found, this object will be set -# to an associative array in which parameter names are keys -# and the values are stored as lists -# If a keyword list is found, this method creates a bogus -# parameter list with the single parameter 'keywords'. - -sub init { - my $self = shift; - my($query_string,$meth,$content_length,$fh,@lines) = ('','','',''); - - my $initializer = shift; # for backward compatibility - local($/) = "\n"; - - # set autoescaping on by default - $self->{'escape'} = 1; - - # if we get called more than once, we want to initialize - # ourselves from the original query (which may be gone - # if it was read from STDIN originally.) - if (defined(@QUERY_PARAM) && !defined($initializer)) { - foreach (@QUERY_PARAM) { - $self->param('-name'=>$_,'-value'=>$QUERY_PARAM{$_}); - } - $self->charset($QUERY_CHARSET); - $self->{'.fieldnames'} = {%QUERY_FIELDNAMES}; - return; - } - - $meth=$ENV{'REQUEST_METHOD'} if defined($ENV{'REQUEST_METHOD'}); - $content_length = defined($ENV{'CONTENT_LENGTH'}) ? $ENV{'CONTENT_LENGTH'} : 0; - - $fh = to_filehandle($initializer) if $initializer; - - # set charset to the safe ISO-8859-1 - $self->charset('ISO-8859-1'); - - METHOD: { - - # avoid unreasonably large postings - if (($POST_MAX > 0) && ($content_length > $POST_MAX)) { - # quietly read and discard the post - my $buffer; - my $max = $content_length; - while ($max > 0 && - (my $bytes = $MOD_PERL - ? $self->r->read($buffer,$max < 10000 ? $max : 10000) - : read(STDIN,$buffer,$max < 10000 ? $max : 10000) - )) { - $self->cgi_error("413 Request entity too large"); - last METHOD; - } - } - - # Process multipart postings, but only if the initializer is - # not defined. - if ($meth eq 'POST' - && defined($ENV{'CONTENT_TYPE'}) - && $ENV{'CONTENT_TYPE'}=~m|^multipart/form-data| - && !defined($initializer) - ) { - my($boundary) = $ENV{'CONTENT_TYPE'} =~ /boundary=\"?([^\";,]+)\"?/; - $self->read_multipart($boundary,$content_length); - last METHOD; - } - - # If initializer is defined, then read parameters - # from it. - if (defined($initializer)) { - if (UNIVERSAL::isa($initializer,'CGI')) { - $query_string = $initializer->query_string; - last METHOD; - } - if (ref($initializer) && ref($initializer) eq 'HASH') { - foreach (keys %$initializer) { - $self->param('-name'=>$_,'-value'=>$initializer->{$_}); - } - last METHOD; - } - - if (defined($fh) && ($fh ne '')) { - while (<$fh>) { - chomp; - last if /^=/; - push(@lines,$_); - } - # massage back into standard format - if ("@lines" =~ /=/) { - $query_string=join("&",@lines); - } else { - $query_string=join("+",@lines); - } - last METHOD; - } - - if (defined($fh) && ($fh ne '')) { - while (<$fh>) { - chomp; - last if /^=/; - push(@lines,$_); - } - # massage back into standard format - if ("@lines" =~ /=/) { - $query_string=join("&",@lines); - } else { - $query_string=join("+",@lines); - } - last METHOD; - } - - # last chance -- treat it as a string - $initializer = $$initializer if ref($initializer) eq 'SCALAR'; - $query_string = $initializer; - - last METHOD; - } - - # If method is GET or HEAD, fetch the query from - # the environment. - if ($meth=~/^(GET|HEAD)$/) { - if ($MOD_PERL) { - $query_string = $self->r->args; - } else { - $query_string = $ENV{'QUERY_STRING'} if defined $ENV{'QUERY_STRING'}; - $query_string ||= $ENV{'REDIRECT_QUERY_STRING'} if defined $ENV{'REDIRECT_QUERY_STRING'}; - } - last METHOD; - } - - if ($meth eq 'POST') { - $self->read_from_client(\$query_string,$content_length,0) - if $content_length > 0; - # Some people want to have their cake and eat it too! - # Uncomment this line to have the contents of the query string - # APPENDED to the POST data. - # $query_string .= (length($query_string) ? '&' : '') . $ENV{'QUERY_STRING'} if defined $ENV{'QUERY_STRING'}; - last METHOD; - } - - # If $meth is not of GET, POST or HEAD, assume we're being debugged offline. - # Check the command line and then the standard input for data. - # We use the shellwords package in order to behave the way that - # UN*X programmers expect. - if ($DEBUG) - { - my $cmdline_ret = read_from_cmdline(); - $query_string = $cmdline_ret->{'query_string'}; - if (defined($cmdline_ret->{'subpath'})) - { - $self->path_info($cmdline_ret->{'subpath'}); - } - } - } - -# YL: Begin Change for XML handler 10/19/2001 - if ($meth eq 'POST' - && defined($ENV{'CONTENT_TYPE'}) - && $ENV{'CONTENT_TYPE'} !~ m|^application/x-www-form-urlencoded| - && $ENV{'CONTENT_TYPE'} !~ m|^multipart/form-data| ) { - my($param) = 'POSTDATA' ; - $self->add_parameter($param) ; - push (@{$self->{$param}},$query_string); - undef $query_string ; - } -# YL: End Change for XML handler 10/19/2001 - - # We now have the query string in hand. We do slightly - # different things for keyword lists and parameter lists. - if (defined $query_string && length $query_string) { - if ($query_string =~ /[&=;]/) { - $self->parse_params($query_string); - } else { - $self->add_parameter('keywords'); - $self->{'keywords'} = [$self->parse_keywordlist($query_string)]; - } - } - - # Special case. Erase everything if there is a field named - # .defaults. - if ($self->param('.defaults')) { - $self->delete_all(); - } - - # Associative array containing our defined fieldnames - $self->{'.fieldnames'} = {}; - foreach ($self->param('.cgifields')) { - $self->{'.fieldnames'}->{$_}++; - } - - # Clear out our default submission button flag if present - $self->delete('.submit'); - $self->delete('.cgifields'); - - $self->save_request unless defined $initializer; -} - -# FUNCTIONS TO OVERRIDE: -# Turn a string into a filehandle -sub to_filehandle { - my $thingy = shift; - return undef unless $thingy; - return $thingy if UNIVERSAL::isa($thingy,'GLOB'); - return $thingy if UNIVERSAL::isa($thingy,'FileHandle'); - if (!ref($thingy)) { - my $caller = 1; - while (my $package = caller($caller++)) { - my($tmp) = $thingy=~/[\':]/ ? $thingy : "$package\:\:$thingy"; - return $tmp if defined(fileno($tmp)); - } - } - return undef; -} - -# send output to the browser -sub put { - my($self,@p) = self_or_default(@_); - $self->print(@p); -} - -# print to standard output (for overriding in mod_perl) -sub print { - shift; - CORE::print(@_); -} - -# get/set last cgi_error -sub cgi_error { - my ($self,$err) = self_or_default(@_); - $self->{'.cgi_error'} = $err if defined $err; - return $self->{'.cgi_error'}; -} - -sub save_request { - my($self) = @_; - # We're going to play with the package globals now so that if we get called - # again, we initialize ourselves in exactly the same way. This allows - # us to have several of these objects. - @QUERY_PARAM = $self->param; # save list of parameters - foreach (@QUERY_PARAM) { - next unless defined $_; - $QUERY_PARAM{$_}=$self->{$_}; - } - $QUERY_CHARSET = $self->charset; - %QUERY_FIELDNAMES = %{$self->{'.fieldnames'}}; -} - -sub parse_params { - my($self,$tosplit) = @_; - my(@pairs) = split(/[&;]/,$tosplit); - my($param,$value); - foreach (@pairs) { - ($param,$value) = split('=',$_,2); - next unless defined $param; - next if $NO_UNDEF_PARAMS and not defined $value; - $value = '' unless defined $value; - $param = unescape($param); - $value = unescape($value); - $self->add_parameter($param); - push (@{$self->{$param}},$value); - } -} - -sub add_parameter { - my($self,$param)=@_; - return unless defined $param; - push (@{$self->{'.parameters'}},$param) - unless defined($self->{$param}); -} - -sub all_parameters { - my $self = shift; - return () unless defined($self) && $self->{'.parameters'}; - return () unless @{$self->{'.parameters'}}; - return @{$self->{'.parameters'}}; -} - -# put a filehandle into binary mode (DOS) -sub binmode { - return unless defined($_[1]) && defined fileno($_[1]); - CORE::binmode($_[1]); -} - -sub _make_tag_func { - my ($self,$tagname) = @_; - my $func = qq( - sub $tagname { - my (\$q,\$a,\@rest) = self_or_default(\@_); - my(\$attr) = ''; - if (ref(\$a) && ref(\$a) eq 'HASH') { - my(\@attr) = make_attributes(\$a,\$q->{'escape'}); - \$attr = " \@attr" if \@attr; - } else { - unshift \@rest,\$a if defined \$a; - } - ); - if ($tagname=~/start_(\w+)/i) { - $func .= qq! return "<\L$1\E\$attr>";} !; - } elsif ($tagname=~/end_(\w+)/i) { - $func .= qq! return "<\L/$1\E>"; } !; - } else { - $func .= qq# - return \$XHTML ? "\L<$tagname\E\$attr />" : "\L<$tagname\E\$attr>" unless \@rest; - my(\$tag,\$untag) = ("\L<$tagname\E\$attr>","\L\E"); - my \@result = map { "\$tag\$_\$untag" } - (ref(\$rest[0]) eq 'ARRAY') ? \@{\$rest[0]} : "\@rest"; - return "\@result"; - }#; - } -return $func; -} - -sub AUTOLOAD { - print STDERR "CGI::AUTOLOAD for $AUTOLOAD\n" if $CGI::AUTOLOAD_DEBUG; - my $func = &_compile; - goto &$func; -} - -sub _compile { - my($func) = $AUTOLOAD; - my($pack,$func_name); - { - local($1,$2); # this fixes an obscure variable suicide problem. - $func=~/(.+)::([^:]+)$/; - ($pack,$func_name) = ($1,$2); - $pack=~s/::SUPER$//; # fix another obscure problem - $pack = ${"$pack\:\:AutoloadClass"} || $CGI::DefaultClass - unless defined(${"$pack\:\:AUTOLOADED_ROUTINES"}); - - my($sub) = \%{"$pack\:\:SUBS"}; - unless (%$sub) { - my($auto) = \${"$pack\:\:AUTOLOADED_ROUTINES"}; - eval "package $pack; $$auto"; - croak("$AUTOLOAD: $@") if $@; - $$auto = ''; # Free the unneeded storage (but don't undef it!!!) - } - my($code) = $sub->{$func_name}; - - $code = "sub $AUTOLOAD { }" if (!$code and $func_name eq 'DESTROY'); - if (!$code) { - (my $base = $func_name) =~ s/^(start_|end_)//i; - if ($EXPORT{':any'} || - $EXPORT{'-any'} || - $EXPORT{$base} || - (%EXPORT_OK || grep(++$EXPORT_OK{$_},&expand_tags(':html'))) - && $EXPORT_OK{$base}) { - $code = $CGI::DefaultClass->_make_tag_func($func_name); - } - } - croak("Undefined subroutine $AUTOLOAD\n") unless $code; - eval "package $pack; $code"; - if ($@) { - $@ =~ s/ at .*\n//; - croak("$AUTOLOAD: $@"); - } - } - CORE::delete($sub->{$func_name}); #free storage - return "$pack\:\:$func_name"; -} - -sub _selected { - my $self = shift; - my $value = shift; - return '' unless $value; - return $XHTML ? qq( selected="selected") : qq( selected); -} - -sub _checked { - my $self = shift; - my $value = shift; - return '' unless $value; - return $XHTML ? qq( checked="checked") : qq( checked); -} - -sub _reset_globals { initialize_globals(); } - -sub _setup_symbols { - my $self = shift; - my $compile = 0; - - # to avoid reexporting unwanted variables - undef %EXPORT; - - foreach (@_) { - $HEADERS_ONCE++, next if /^[:-]unique_headers$/; - $NPH++, next if /^[:-]nph$/; - $NOSTICKY++, next if /^[:-]nosticky$/; - $DEBUG=0, next if /^[:-]no_?[Dd]ebug$/; - $DEBUG=2, next if /^[:-][Dd]ebug$/; - $USE_PARAM_SEMICOLONS++, next if /^[:-]newstyle_urls$/; - $XHTML++, next if /^[:-]xhtml$/; - $XHTML=0, next if /^[:-]no_?xhtml$/; - $USE_PARAM_SEMICOLONS=0, next if /^[:-]oldstyle_urls$/; - $PRIVATE_TEMPFILES++, next if /^[:-]private_tempfiles$/; - $CLOSE_UPLOAD_FILES++, next if /^[:-]close_upload_files$/; - $EXPORT{$_}++, next if /^[:-]any$/; - $compile++, next if /^[:-]compile$/; - $NO_UNDEF_PARAMS++, next if /^[:-]no_undef_params$/; - - # This is probably extremely evil code -- to be deleted some day. - if (/^[-]autoload$/) { - my($pkg) = caller(1); - *{"${pkg}::AUTOLOAD"} = sub { - my($routine) = $AUTOLOAD; - $routine =~ s/^.*::/CGI::/; - &$routine; - }; - next; - } - - foreach (&expand_tags($_)) { - tr/a-zA-Z0-9_//cd; # don't allow weird function names - $EXPORT{$_}++; - } - } - _compile_all(keys %EXPORT) if $compile; - @SAVED_SYMBOLS = @_; -} - -sub charset { - my ($self,$charset) = self_or_default(@_); - $self->{'.charset'} = $charset if defined $charset; - $self->{'.charset'}; -} - -############################################################################### -################# THESE FUNCTIONS ARE AUTOLOADED ON DEMAND #################### -############################################################################### -$AUTOLOADED_ROUTINES = ''; # get rid of -w warning -$AUTOLOADED_ROUTINES=<<'END_OF_AUTOLOAD'; - -%SUBS = ( - -'URL_ENCODED'=> <<'END_OF_FUNC', -sub URL_ENCODED { 'application/x-www-form-urlencoded'; } -END_OF_FUNC - -'MULTIPART' => <<'END_OF_FUNC', -sub MULTIPART { 'multipart/form-data'; } -END_OF_FUNC - -'SERVER_PUSH' => <<'END_OF_FUNC', -sub SERVER_PUSH { 'multipart/x-mixed-replace;boundary="' . shift() . '"'; } -END_OF_FUNC - -'new_MultipartBuffer' => <<'END_OF_FUNC', -# Create a new multipart buffer -sub new_MultipartBuffer { - my($self,$boundary,$length) = @_; - return MultipartBuffer->new($self,$boundary,$length); -} -END_OF_FUNC - -'read_from_client' => <<'END_OF_FUNC', -# Read data from a file handle -sub read_from_client { - my($self, $buff, $len, $offset) = @_; - local $^W=0; # prevent a warning - return $MOD_PERL - ? $self->r->read($$buff, $len, $offset) - : read(\*STDIN, $$buff, $len, $offset); -} -END_OF_FUNC - -'delete' => <<'END_OF_FUNC', -#### Method: delete -# Deletes the named parameter entirely. -#### -sub delete { - my($self,@p) = self_or_default(@_); - my(@names) = rearrange([NAME],@p); - my @to_delete = ref($names[0]) eq 'ARRAY' ? @$names[0] : @names; - my %to_delete; - foreach my $name (@to_delete) - { - CORE::delete $self->{$name}; - CORE::delete $self->{'.fieldnames'}->{$name}; - $to_delete{$name}++; - } - @{$self->{'.parameters'}}=grep { !exists($to_delete{$_}) } $self->param(); - return; -} -END_OF_FUNC - -#### Method: import_names -# Import all parameters into the given namespace. -# Assumes namespace 'Q' if not specified -#### -'import_names' => <<'END_OF_FUNC', -sub import_names { - my($self,$namespace,$delete) = self_or_default(@_); - $namespace = 'Q' unless defined($namespace); - die "Can't import names into \"main\"\n" if \%{"${namespace}::"} == \%::; - if ($delete || $MOD_PERL || exists $ENV{'FCGI_ROLE'}) { - # can anyone find an easier way to do this? - foreach (keys %{"${namespace}::"}) { - local *symbol = "${namespace}::${_}"; - undef $symbol; - undef @symbol; - undef %symbol; - } - } - my($param,@value,$var); - foreach $param ($self->param) { - # protect against silly names - ($var = $param)=~tr/a-zA-Z0-9_/_/c; - $var =~ s/^(?=\d)/_/; - local *symbol = "${namespace}::$var"; - @value = $self->param($param); - @symbol = @value; - $symbol = $value[0]; - } -} -END_OF_FUNC - -#### Method: keywords -# Keywords acts a bit differently. Calling it in a list context -# returns the list of keywords. -# Calling it in a scalar context gives you the size of the list. -#### -'keywords' => <<'END_OF_FUNC', -sub keywords { - my($self,@values) = self_or_default(@_); - # If values is provided, then we set it. - $self->{'keywords'}=[@values] if @values; - my(@result) = defined($self->{'keywords'}) ? @{$self->{'keywords'}} : (); - @result; -} -END_OF_FUNC - -# These are some tie() interfaces for compatibility -# with Steve Brenner's cgi-lib.pl routines -'Vars' => <<'END_OF_FUNC', -sub Vars { - my $q = shift; - my %in; - tie(%in,CGI,$q); - return %in if wantarray; - return \%in; -} -END_OF_FUNC - -# These are some tie() interfaces for compatibility -# with Steve Brenner's cgi-lib.pl routines -'ReadParse' => <<'END_OF_FUNC', -sub ReadParse { - local(*in); - if (@_) { - *in = $_[0]; - } else { - my $pkg = caller(); - *in=*{"${pkg}::in"}; - } - tie(%in,CGI); - return scalar(keys %in); -} -END_OF_FUNC - -'PrintHeader' => <<'END_OF_FUNC', -sub PrintHeader { - my($self) = self_or_default(@_); - return $self->header(); -} -END_OF_FUNC - -'HtmlTop' => <<'END_OF_FUNC', -sub HtmlTop { - my($self,@p) = self_or_default(@_); - return $self->start_html(@p); -} -END_OF_FUNC - -'HtmlBot' => <<'END_OF_FUNC', -sub HtmlBot { - my($self,@p) = self_or_default(@_); - return $self->end_html(@p); -} -END_OF_FUNC - -'SplitParam' => <<'END_OF_FUNC', -sub SplitParam { - my ($param) = @_; - my (@params) = split ("\0", $param); - return (wantarray ? @params : $params[0]); -} -END_OF_FUNC - -'MethGet' => <<'END_OF_FUNC', -sub MethGet { - return request_method() eq 'GET'; -} -END_OF_FUNC - -'MethPost' => <<'END_OF_FUNC', -sub MethPost { - return request_method() eq 'POST'; -} -END_OF_FUNC - -'TIEHASH' => <<'END_OF_FUNC', -sub TIEHASH { - my $class = shift; - my $arg = $_[0]; - if (ref($arg) && UNIVERSAL::isa($arg,'CGI')) { - return $arg; - } - return $Q ||= $class->new(@_); -} -END_OF_FUNC - -'STORE' => <<'END_OF_FUNC', -sub STORE { - my $self = shift; - my $tag = shift; - my $vals = shift; - my @vals = index($vals,"\0")!=-1 ? split("\0",$vals) : $vals; - $self->param(-name=>$tag,-value=>\@vals); -} -END_OF_FUNC - -'FETCH' => <<'END_OF_FUNC', -sub FETCH { - return $_[0] if $_[1] eq 'CGI'; - return undef unless defined $_[0]->param($_[1]); - return join("\0",$_[0]->param($_[1])); -} -END_OF_FUNC - -'FIRSTKEY' => <<'END_OF_FUNC', -sub FIRSTKEY { - $_[0]->{'.iterator'}=0; - $_[0]->{'.parameters'}->[$_[0]->{'.iterator'}++]; -} -END_OF_FUNC - -'NEXTKEY' => <<'END_OF_FUNC', -sub NEXTKEY { - $_[0]->{'.parameters'}->[$_[0]->{'.iterator'}++]; -} -END_OF_FUNC - -'EXISTS' => <<'END_OF_FUNC', -sub EXISTS { - exists $_[0]->{$_[1]}; -} -END_OF_FUNC - -'DELETE' => <<'END_OF_FUNC', -sub DELETE { - $_[0]->delete($_[1]); -} -END_OF_FUNC - -'CLEAR' => <<'END_OF_FUNC', -sub CLEAR { - %{$_[0]}=(); -} -#### -END_OF_FUNC - -#### -# Append a new value to an existing query -#### -'append' => <<'EOF', -sub append { - my($self,@p) = @_; - my($name,$value) = rearrange([NAME,[VALUE,VALUES]],@p); - my(@values) = defined($value) ? (ref($value) ? @{$value} : $value) : (); - if (@values) { - $self->add_parameter($name); - push(@{$self->{$name}},@values); - } - return $self->param($name); -} -EOF - -#### Method: delete_all -# Delete all parameters -#### -'delete_all' => <<'EOF', -sub delete_all { - my($self) = self_or_default(@_); - my @param = $self->param(); - $self->delete(@param); -} -EOF - -'Delete' => <<'EOF', -sub Delete { - my($self,@p) = self_or_default(@_); - $self->delete(@p); -} -EOF - -'Delete_all' => <<'EOF', -sub Delete_all { - my($self,@p) = self_or_default(@_); - $self->delete_all(@p); -} -EOF - -#### Method: autoescape -# If you want to turn off the autoescaping features, -# call this method with undef as the argument -'autoEscape' => <<'END_OF_FUNC', -sub autoEscape { - my($self,$escape) = self_or_default(@_); - my $d = $self->{'escape'}; - $self->{'escape'} = $escape; - $d; -} -END_OF_FUNC - - -#### Method: version -# Return the current version -#### -'version' => <<'END_OF_FUNC', -sub version { - return $VERSION; -} -END_OF_FUNC - -#### Method: url_param -# Return a parameter in the QUERY_STRING, regardless of -# whether this was a POST or a GET -#### -'url_param' => <<'END_OF_FUNC', -sub url_param { - my ($self,@p) = self_or_default(@_); - my $name = shift(@p); - return undef unless exists($ENV{QUERY_STRING}); - unless (exists($self->{'.url_param'})) { - $self->{'.url_param'}={}; # empty hash - if ($ENV{QUERY_STRING} =~ /=/) { - my(@pairs) = split(/[&;]/,$ENV{QUERY_STRING}); - my($param,$value); - foreach (@pairs) { - ($param,$value) = split('=',$_,2); - $param = unescape($param); - $value = unescape($value); - push(@{$self->{'.url_param'}->{$param}},$value); - } - } else { - $self->{'.url_param'}->{'keywords'} = [$self->parse_keywordlist($ENV{QUERY_STRING})]; - } - } - return keys %{$self->{'.url_param'}} unless defined($name); - return () unless $self->{'.url_param'}->{$name}; - return wantarray ? @{$self->{'.url_param'}->{$name}} - : $self->{'.url_param'}->{$name}->[0]; -} -END_OF_FUNC - -#### Method: Dump -# Returns a string in which all the known parameter/value -# pairs are represented as nested lists, mainly for the purposes -# of debugging. -#### -'Dump' => <<'END_OF_FUNC', -sub Dump { - my($self) = self_or_default(@_); - my($param,$value,@result); - return '' unless $self->param; - push(@result,""); - return join("\n",@result); -} -END_OF_FUNC - -#### Method as_string -# -# synonym for "dump" -#### -'as_string' => <<'END_OF_FUNC', -sub as_string { - &Dump(@_); -} -END_OF_FUNC - -#### Method: save -# Write values out to a filehandle in such a way that they can -# be reinitialized by the filehandle form of the new() method -#### -'save' => <<'END_OF_FUNC', -sub save { - my($self,$filehandle) = self_or_default(@_); - $filehandle = to_filehandle($filehandle); - my($param); - local($,) = ''; # set print field separator back to a sane value - local($\) = ''; # set output line separator to a sane value - foreach $param ($self->param) { - my($escaped_param) = escape($param); - my($value); - foreach $value ($self->param($param)) { - print $filehandle "$escaped_param=",escape("$value"),"\n"; - } - } - foreach (keys %{$self->{'.fieldnames'}}) { - print $filehandle ".cgifields=",escape("$_"),"\n"; - } - print $filehandle "=\n"; # end of record -} -END_OF_FUNC - - -#### Method: save_parameters -# An alias for save() that is a better name for exportation. -# Only intended to be used with the function (non-OO) interface. -#### -'save_parameters' => <<'END_OF_FUNC', -sub save_parameters { - my $fh = shift; - return save(to_filehandle($fh)); -} -END_OF_FUNC - -#### Method: restore_parameters -# A way to restore CGI parameters from an initializer. -# Only intended to be used with the function (non-OO) interface. -#### -'restore_parameters' => <<'END_OF_FUNC', -sub restore_parameters { - $Q = $CGI::DefaultClass->new(@_); -} -END_OF_FUNC - -#### Method: multipart_init -# Return a Content-Type: style header for server-push -# This has to be NPH on most web servers, and it is advisable to set $| = 1 -# -# Many thanks to Ed Jordan for this -# contribution, updated by Andrew Benham (adsb@bigfoot.com) -#### -'multipart_init' => <<'END_OF_FUNC', -sub multipart_init { - my($self,@p) = self_or_default(@_); - my($boundary,@other) = rearrange([BOUNDARY],@p); - $boundary = $boundary || '------- =_aaaaaaaaaa0'; - $self->{'separator'} = "$CRLF--$boundary$CRLF"; - $self->{'final_separator'} = "$CRLF--$boundary--$CRLF"; - $type = SERVER_PUSH($boundary); - return $self->header( - -nph => 0, - -type => $type, - (map { split "=", $_, 2 } @other), - ) . "WARNING: YOUR BROWSER DOESN'T SUPPORT THIS SERVER-PUSH TECHNOLOGY." . $self->multipart_end; -} -END_OF_FUNC - - -#### Method: multipart_start -# Return a Content-Type: style header for server-push, start of section -# -# Many thanks to Ed Jordan for this -# contribution, updated by Andrew Benham (adsb@bigfoot.com) -#### -'multipart_start' => <<'END_OF_FUNC', -sub multipart_start { - my(@header); - my($self,@p) = self_or_default(@_); - my($type,@other) = rearrange([TYPE],@p); - $type = $type || 'text/html'; - push(@header,"Content-Type: $type"); - - # rearrange() was designed for the HTML portion, so we - # need to fix it up a little. - foreach (@other) { - # Don't use \s because of perl bug 21951 - next unless my($header,$value) = /([^ \r\n\t=]+)=\"?(.+?)\"?$/; - ($_ = $header) =~ s/^(\w)(.*)/$1 . lc ($2) . ': '.$self->unescapeHTML($value)/e; - } - push(@header,@other); - my $header = join($CRLF,@header)."${CRLF}${CRLF}"; - return $header; -} -END_OF_FUNC - - -#### Method: multipart_end -# Return a MIME boundary separator for server-push, end of section -# -# Many thanks to Ed Jordan for this -# contribution -#### -'multipart_end' => <<'END_OF_FUNC', -sub multipart_end { - my($self,@p) = self_or_default(@_); - return $self->{'separator'}; -} -END_OF_FUNC - - -#### Method: multipart_final -# Return a MIME boundary separator for server-push, end of all sections -# -# Contributed by Andrew Benham (adsb@bigfoot.com) -#### -'multipart_final' => <<'END_OF_FUNC', -sub multipart_final { - my($self,@p) = self_or_default(@_); - return $self->{'final_separator'} . "WARNING: YOUR BROWSER DOESN'T SUPPORT THIS SERVER-PUSH TECHNOLOGY." . $CRLF; -} -END_OF_FUNC - - -#### Method: header -# Return a Content-Type: style header -# -#### -'header' => <<'END_OF_FUNC', -sub header { - my($self,@p) = self_or_default(@_); - my(@header); - - return "" if $self->{'.header_printed'}++ and $HEADERS_ONCE; - - my($type,$status,$cookie,$target,$expires,$nph,$charset,$attachment,$p3p,@other) = - rearrange([['TYPE','CONTENT_TYPE','CONTENT-TYPE'], - 'STATUS',['COOKIE','COOKIES'],'TARGET', - 'EXPIRES','NPH','CHARSET', - 'ATTACHMENT','P3P'],@p); - - $nph ||= $NPH; - if (defined $charset) { - $self->charset($charset); - } else { - $charset = $self->charset; - } - - # rearrange() was designed for the HTML portion, so we - # need to fix it up a little. - foreach (@other) { - # Don't use \s because of perl bug 21951 - next unless my($header,$value) = /([^ \r\n\t=]+)=\"?(.+?)\"?$/; - ($_ = $header) =~ s/^(\w)(.*)/"\u$1\L$2" . ': '.$self->unescapeHTML($value)/e; - } - - $type ||= 'text/html' unless defined($type); - $type .= "; charset=$charset" if $type ne '' and $type =~ m!^text/! and $type !~ /\bcharset\b/ and $charset ne ''; - - # Maybe future compatibility. Maybe not. - my $protocol = $ENV{SERVER_PROTOCOL} || 'HTTP/1.0'; - push(@header,$protocol . ' ' . ($status || '200 OK')) if $nph; - push(@header,"Server: " . &server_software()) if $nph; - - push(@header,"Status: $status") if $status; - push(@header,"Window-Target: $target") if $target; - if ($p3p) { - $p3p = join ' ',@$p3p if ref($p3p) eq 'ARRAY'; - push(@header,qq(P3P: policyref="/w3c/p3p.xml", CP="$p3p")); - } - # push all the cookies -- there may be several - if ($cookie) { - my(@cookie) = ref($cookie) && ref($cookie) eq 'ARRAY' ? @{$cookie} : $cookie; - foreach (@cookie) { - my $cs = UNIVERSAL::isa($_,'CGI::Cookie') ? $_->as_string : $_; - push(@header,"Set-Cookie: $cs") if $cs ne ''; - } - } - # if the user indicates an expiration time, then we need - # both an Expires and a Date header (so that the browser is - # uses OUR clock) - push(@header,"Expires: " . expires($expires,'http')) - if $expires; - push(@header,"Date: " . expires(0,'http')) if $expires || $cookie || $nph; - push(@header,"Pragma: no-cache") if $self->cache(); - push(@header,"Content-Disposition: attachment; filename=\"$attachment\"") if $attachment; - push(@header,map {ucfirst $_} @other); - push(@header,"Content-Type: $type") if $type ne ''; - my $header = join($CRLF,@header)."${CRLF}${CRLF}"; - if ($MOD_PERL and not $nph) { - $self->r->send_cgi_header($header); - return ''; - } - return $header; -} -END_OF_FUNC - - -#### Method: cache -# Control whether header() will produce the no-cache -# Pragma directive. -#### -'cache' => <<'END_OF_FUNC', -sub cache { - my($self,$new_value) = self_or_default(@_); - $new_value = '' unless $new_value; - if ($new_value ne '') { - $self->{'cache'} = $new_value; - } - return $self->{'cache'}; -} -END_OF_FUNC - - -#### Method: redirect -# Return a Location: style header -# -#### -'redirect' => <<'END_OF_FUNC', -sub redirect { - my($self,@p) = self_or_default(@_); - my($url,$target,$status,$cookie,$nph,@other) = - rearrange([[LOCATION,URI,URL],TARGET,STATUS,['COOKIE','COOKIES'],NPH],@p); - $status = '302 Moved' unless defined $status; - $url ||= $self->self_url; - my(@o); - foreach (@other) { tr/\"//d; push(@o,split("=",$_,2)); } - unshift(@o, - '-Status' => $status, - '-Location'=> $url, - '-nph' => $nph); - unshift(@o,'-Target'=>$target) if $target; - unshift(@o,'-Type'=>''); - my @unescaped; - unshift(@unescaped,'-Cookie'=>$cookie) if $cookie; - return $self->header((map {$self->unescapeHTML($_)} @o),@unescaped); -} -END_OF_FUNC - - -#### Method: start_html -# Canned HTML header -# -# Parameters: -# $title -> (optional) The title for this HTML document (-title) -# $author -> (optional) e-mail address of the author (-author) -# $base -> (optional) if set to true, will enter the BASE address of this document -# for resolving relative references (-base) -# $xbase -> (optional) alternative base at some remote location (-xbase) -# $target -> (optional) target window to load all links into (-target) -# $script -> (option) Javascript code (-script) -# $no_script -> (option) Javascript -END - ; - my($other) = @other ? " @other" : ''; - push(@result,""); - return join("\n",@result); -} -END_OF_FUNC - -### Method: _style -# internal method for generating a CSS style section -#### -'_style' => <<'END_OF_FUNC', -sub _style { - my ($self,$style) = @_; - my (@result); - my $type = 'text/css'; - - my $cdata_start = $XHTML ? "\n\n" : " -->\n"; - - my @s = ref($style) eq 'ARRAY' ? @$style : $style; - - for my $s (@s) { - if (ref($s)) { - my($src,$code,$verbatim,$stype,$foo,@other) = - rearrange([qw(SRC CODE VERBATIM TYPE FOO)], - ('-foo'=>'bar', - ref($s) eq 'ARRAY' ? @$s : %$s)); - $type = $stype if $stype; - my $other = @other ? join ' ',@other : ''; - - if (ref($src) eq "ARRAY") # Check to see if the $src variable is an array reference - { # If it is, push a LINK tag for each one - foreach $src (@$src) - { - push(@result,$XHTML ? qq() - : qq()) if $src; - } - } - else - { # Otherwise, push the single -src, if it exists. - push(@result,$XHTML ? qq() - : qq() - ) if $src; - } - if ($verbatim) { - my @v = ref($verbatim) eq 'ARRAY' ? @$verbatim : $verbatim; - push(@result, "") foreach @v; - } - my @c = ref($code) eq 'ARRAY' ? @$code : $code if $code; - push(@result,style({'type'=>$type},"$cdata_start\n$_\n$cdata_end")) foreach @c; - - } else { - my $src = $s; - push(@result,$XHTML ? qq() - : qq()); - } - } - @result; -} -END_OF_FUNC - -'_script' => <<'END_OF_FUNC', -sub _script { - my ($self,$script) = @_; - my (@result); - - my (@scripts) = ref($script) eq 'ARRAY' ? @$script : ($script); - foreach $script (@scripts) { - my($src,$code,$language); - if (ref($script)) { # script is a hash - ($src,$code,$language, $type) = - rearrange([SRC,CODE,LANGUAGE,TYPE], - '-foo'=>'bar', # a trick to allow the '-' to be omitted - ref($script) eq 'ARRAY' ? @$script : %$script); - # User may not have specified language - $language ||= 'JavaScript'; - unless (defined $type) { - $type = lc $language; - # strip '1.2' from 'javascript1.2' - $type =~ s/^(\D+).*$/text\/$1/; - } - } else { - ($src,$code,$language, $type) = ('',$script,'JavaScript', 'text/javascript'); - } - - my $comment = '//'; # javascript by default - $comment = '#' if $type=~/perl|tcl/i; - $comment = "'" if $type=~/vbscript/i; - - my ($cdata_start,$cdata_end); - if ($XHTML) { - $cdata_start = "$comment"; - } else { - $cdata_start = "\n\n"; - } - my(@satts); - push(@satts,'src'=>$src) if $src; - push(@satts,'language'=>$language) unless defined $type; - push(@satts,'type'=>$type); - $code = "$cdata_start$code$cdata_end" if defined $code; - push(@result,script({@satts},$code || '')); - } - @result; -} -END_OF_FUNC - -#### Method: end_html -# End an HTML document. -# Trivial method for completeness. Just returns "" -#### -'end_html' => <<'END_OF_FUNC', -sub end_html { - return ""; -} -END_OF_FUNC - - -################################ -# METHODS USED IN BUILDING FORMS -################################ - -#### Method: isindex -# Just prints out the isindex tag. -# Parameters: -# $action -> optional URL of script to run -# Returns: -# A string containing a tag -'isindex' => <<'END_OF_FUNC', -sub isindex { - my($self,@p) = self_or_default(@_); - my($action,@other) = rearrange([ACTION],@p); - $action = qq/ action="$action"/ if $action; - my($other) = @other ? " @other" : ''; - return $XHTML ? "" : ""; -} -END_OF_FUNC - - -#### Method: startform -# Start a form -# Parameters: -# $method -> optional submission method to use (GET or POST) -# $action -> optional URL of script to run -# $enctype ->encoding to use (URL_ENCODED or MULTIPART) -'startform' => <<'END_OF_FUNC', -sub startform { - my($self,@p) = self_or_default(@_); - - my($method,$action,$enctype,@other) = - rearrange([METHOD,ACTION,ENCTYPE],@p); - - $method = $self->escapeHTML(lc($method) || 'post'); - $enctype = $self->escapeHTML($enctype || &URL_ENCODED); - if (defined $action) { - $action = $self->escapeHTML($action); - } - else { - $action = $self->escapeHTML($self->url(-absolute=>1,-path=>1)); - if (exists $ENV{QUERY_STRING} && length($ENV{QUERY_STRING})>0) { - $action .= "?".$self->escapeHTML($ENV{QUERY_STRING},1); - } - } - $action = qq(action="$action"); - my($other) = @other ? " @other" : ''; - $self->{'.parametersToAdd'}={}; - return qq/
\n/; -} -END_OF_FUNC - - -#### Method: start_form -# synonym for startform -'start_form' => <<'END_OF_FUNC', -sub start_form { - &startform; -} -END_OF_FUNC - -'end_multipart_form' => <<'END_OF_FUNC', -sub end_multipart_form { - &endform; -} -END_OF_FUNC - -#### Method: start_multipart_form -# synonym for startform -'start_multipart_form' => <<'END_OF_FUNC', -sub start_multipart_form { - my($self,@p) = self_or_default(@_); - if (defined($param[0]) && substr($param[0],0,1) eq '-') { - my(%p) = @p; - $p{'-enctype'}=&MULTIPART; - return $self->startform(%p); - } else { - my($method,$action,@other) = - rearrange([METHOD,ACTION],@p); - return $self->startform($method,$action,&MULTIPART,@other); - } -} -END_OF_FUNC - - -#### Method: endform -# End a form -'endform' => <<'END_OF_FUNC', -sub endform { - my($self,@p) = self_or_default(@_); - if ( $NOSTICKY ) { - return wantarray ? ("
") : "\n"; - } else { - return wantarray ? ("
",$self->get_fields,"
","") : - "
".$self->get_fields ."
\n"; - } -} -END_OF_FUNC - - -'_textfield' => <<'END_OF_FUNC', -sub _textfield { - my($self,$tag,@p) = self_or_default(@_); - my($name,$default,$size,$maxlength,$override,@other) = - rearrange([NAME,[DEFAULT,VALUE,VALUES],SIZE,MAXLENGTH,[OVERRIDE,FORCE]],@p); - - my $current = $override ? $default : - (defined($self->param($name)) ? $self->param($name) : $default); - - $current = defined($current) ? $self->escapeHTML($current,1) : ''; - $name = defined($name) ? $self->escapeHTML($name) : ''; - my($s) = defined($size) ? qq/ size="$size"/ : ''; - my($m) = defined($maxlength) ? qq/ maxlength="$maxlength"/ : ''; - my($other) = @other ? " @other" : ''; - # this entered at cristy's request to fix problems with file upload fields - # and WebTV -- not sure it won't break stuff - my($value) = $current ne '' ? qq(value="$current") : ''; - return $XHTML ? qq() - : qq(); -} -END_OF_FUNC - -#### Method: textfield -# Parameters: -# $name -> Name of the text field -# $default -> Optional default value of the field if not -# already defined. -# $size -> Optional width of field in characaters. -# $maxlength -> Optional maximum number of characters. -# Returns: -# A string containing a field -# -'textfield' => <<'END_OF_FUNC', -sub textfield { - my($self,@p) = self_or_default(@_); - $self->_textfield('text',@p); -} -END_OF_FUNC - - -#### Method: filefield -# Parameters: -# $name -> Name of the file upload field -# $size -> Optional width of field in characaters. -# $maxlength -> Optional maximum number of characters. -# Returns: -# A string containing a field -# -'filefield' => <<'END_OF_FUNC', -sub filefield { - my($self,@p) = self_or_default(@_); - $self->_textfield('file',@p); -} -END_OF_FUNC - - -#### Method: password -# Create a "secret password" entry field -# Parameters: -# $name -> Name of the field -# $default -> Optional default value of the field if not -# already defined. -# $size -> Optional width of field in characters. -# $maxlength -> Optional maximum characters that can be entered. -# Returns: -# A string containing a field -# -'password_field' => <<'END_OF_FUNC', -sub password_field { - my ($self,@p) = self_or_default(@_); - $self->_textfield('password',@p); -} -END_OF_FUNC - -#### Method: textarea -# Parameters: -# $name -> Name of the text field -# $default -> Optional default value of the field if not -# already defined. -# $rows -> Optional number of rows in text area -# $columns -> Optional number of columns in text area -# Returns: -# A string containing a tag -# -'textarea' => <<'END_OF_FUNC', -sub textarea { - my($self,@p) = self_or_default(@_); - - my($name,$default,$rows,$cols,$override,@other) = - rearrange([NAME,[DEFAULT,VALUE],ROWS,[COLS,COLUMNS],[OVERRIDE,FORCE]],@p); - - my($current)= $override ? $default : - (defined($self->param($name)) ? $self->param($name) : $default); - - $name = defined($name) ? $self->escapeHTML($name) : ''; - $current = defined($current) ? $self->escapeHTML($current) : ''; - my($r) = $rows ? qq/ rows="$rows"/ : ''; - my($c) = $cols ? qq/ cols="$cols"/ : ''; - my($other) = @other ? " @other" : ''; - return qq{}; -} -END_OF_FUNC - - -#### Method: button -# Create a javascript button. -# Parameters: -# $name -> (optional) Name for the button. (-name) -# $value -> (optional) Value of the button when selected (and visible name) (-value) -# $onclick -> (optional) Text of the JavaScript to run when the button is -# clicked. -# Returns: -# A string containing a tag -#### -'button' => <<'END_OF_FUNC', -sub button { - my($self,@p) = self_or_default(@_); - - my($label,$value,$script,@other) = rearrange([NAME,[VALUE,LABEL], - [ONCLICK,SCRIPT]],@p); - - $label=$self->escapeHTML($label); - $value=$self->escapeHTML($value,1); - $script=$self->escapeHTML($script); - - my($name) = ''; - $name = qq/ name="$label"/ if $label; - $value = $value || $label; - my($val) = ''; - $val = qq/ value="$value"/ if $value; - $script = qq/ onclick="$script"/ if $script; - my($other) = @other ? " @other" : ''; - return $XHTML ? qq() - : qq(); -} -END_OF_FUNC - - -#### Method: submit -# Create a "submit query" button. -# Parameters: -# $name -> (optional) Name for the button. -# $value -> (optional) Value of the button when selected (also doubles as label). -# $label -> (optional) Label printed on the button(also doubles as the value). -# Returns: -# A string containing a tag -#### -'submit' => <<'END_OF_FUNC', -sub submit { - my($self,@p) = self_or_default(@_); - - my($label,$value,@other) = rearrange([NAME,[VALUE,LABEL]],@p); - - $label=$self->escapeHTML($label); - $value=$self->escapeHTML($value,1); - - my $name = $NOSTICKY ? '' : ' name=".submit"'; - $name = qq/ name="$label"/ if defined($label); - $value = defined($value) ? $value : $label; - my $val = ''; - $val = qq/ value="$value"/ if defined($value); - my($other) = @other ? " @other" : ''; - return $XHTML ? qq() - : qq(); -} -END_OF_FUNC - - -#### Method: reset -# Create a "reset" button. -# Parameters: -# $name -> (optional) Name for the button. -# Returns: -# A string containing a tag -#### -'reset' => <<'END_OF_FUNC', -sub reset { - my($self,@p) = self_or_default(@_); - my($label,$value,@other) = rearrange(['NAME',['VALUE','LABEL']],@p); - $label=$self->escapeHTML($label); - $value=$self->escapeHTML($value,1); - my ($name) = ' name=".reset"'; - $name = qq/ name="$label"/ if defined($label); - $value = defined($value) ? $value : $label; - my($val) = ''; - $val = qq/ value="$value"/ if defined($value); - my($other) = @other ? " @other" : ''; - return $XHTML ? qq() - : qq(); -} -END_OF_FUNC - - -#### Method: defaults -# Create a "defaults" button. -# Parameters: -# $name -> (optional) Name for the button. -# Returns: -# A string containing a tag -# -# Note: this button has a special meaning to the initialization script, -# and tells it to ERASE the current query string so that your defaults -# are used again! -#### -'defaults' => <<'END_OF_FUNC', -sub defaults { - my($self,@p) = self_or_default(@_); - - my($label,@other) = rearrange([[NAME,VALUE]],@p); - - $label=$self->escapeHTML($label,1); - $label = $label || "Defaults"; - my($value) = qq/ value="$label"/; - my($other) = @other ? " @other" : ''; - return $XHTML ? qq() - : qq//; -} -END_OF_FUNC - - -#### Method: comment -# Create an HTML -# Parameters: a string -'comment' => <<'END_OF_FUNC', -sub comment { - my($self,@p) = self_or_CGI(@_); - return ""; -} -END_OF_FUNC - -#### Method: checkbox -# Create a checkbox that is not logically linked to any others. -# The field value is "on" when the button is checked. -# Parameters: -# $name -> Name of the checkbox -# $checked -> (optional) turned on by default if true -# $value -> (optional) value of the checkbox, 'on' by default -# $label -> (optional) a user-readable label printed next to the box. -# Otherwise the checkbox name is used. -# Returns: -# A string containing a field -#### -'checkbox' => <<'END_OF_FUNC', -sub checkbox { - my($self,@p) = self_or_default(@_); - - my($name,$checked,$value,$label,$override,@other) = - rearrange([NAME,[CHECKED,SELECTED,ON],VALUE,LABEL,[OVERRIDE,FORCE]],@p); - - $value = defined $value ? $value : 'on'; - - if (!$override && ($self->{'.fieldnames'}->{$name} || - defined $self->param($name))) { - $checked = grep($_ eq $value,$self->param($name)) ? $self->_checked(1) : ''; - } else { - $checked = $self->_checked($checked); - } - my($the_label) = defined $label ? $label : $name; - $name = $self->escapeHTML($name); - $value = $self->escapeHTML($value,1); - $the_label = $self->escapeHTML($the_label); - my($other) = @other ? " @other" : ''; - $self->register_parameter($name); - return $XHTML ? qq{$the_label} - : qq{$the_label}; -} -END_OF_FUNC - - -#### Method: checkbox_group -# Create a list of logically-linked checkboxes. -# Parameters: -# $name -> Common name for all the check boxes -# $values -> A pointer to a regular array containing the -# values for each checkbox in the group. -# $defaults -> (optional) -# 1. If a pointer to a regular array of checkbox values, -# then this will be used to decide which -# checkboxes to turn on by default. -# 2. If a scalar, will be assumed to hold the -# value of a single checkbox in the group to turn on. -# $linebreak -> (optional) Set to true to place linebreaks -# between the buttons. -# $labels -> (optional) -# A pointer to an associative array of labels to print next to each checkbox -# in the form $label{'value'}="Long explanatory label". -# Otherwise the provided values are used as the labels. -# Returns: -# An ARRAY containing a series of fields -#### -'checkbox_group' => <<'END_OF_FUNC', -sub checkbox_group { - my($self,@p) = self_or_default(@_); - - my($name,$values,$defaults,$linebreak,$labels,$attributes,$rows,$columns, - $rowheaders,$colheaders,$override,$nolabels,@other) = - rearrange([NAME,[VALUES,VALUE],[DEFAULTS,DEFAULT], - LINEBREAK,LABELS,ATTRIBUTES,ROWS,[COLUMNS,COLS], - ROWHEADERS,COLHEADERS, - [OVERRIDE,FORCE],NOLABELS],@p); - - my($checked,$break,$result,$label); - - my(%checked) = $self->previous_or_default($name,$defaults,$override); - - if ($linebreak) { - $break = $XHTML ? "
" : "
"; - } - else { - $break = ''; - } - $name=$self->escapeHTML($name); - - # Create the elements - my(@elements,@values); - - @values = $self->_set_values_and_labels($values,\$labels,$name); - - my($other) = @other ? " @other" : ''; - foreach (@values) { - $checked = $self->_checked($checked{$_}); - $label = ''; - unless (defined($nolabels) && $nolabels) { - $label = $_; - $label = $labels->{$_} if defined($labels) && defined($labels->{$_}); - $label = $self->escapeHTML($label); - } - my $attribs = $self->_set_attributes($_, $attributes); - $_ = $self->escapeHTML($_,1); - push(@elements,$XHTML ? qq(${label}${break}) - : qq/${label}${break}/); - } - $self->register_parameter($name); - return wantarray ? @elements : join(' ',@elements) - unless defined($columns) || defined($rows); - $rows = 1 if $rows && $rows < 1; - $cols = 1 if $cols && $cols < 1; - return _tableize($rows,$columns,$rowheaders,$colheaders,@elements); -} -END_OF_FUNC - -# Escape HTML -- used internally -'escapeHTML' => <<'END_OF_FUNC', -sub escapeHTML { - # hack to work around earlier hacks - push @_,$_[0] if @_==1 && $_[0] eq 'CGI'; - my ($self,$toencode,$newlinestoo) = CGI::self_or_default(@_); - return undef unless defined($toencode); - return $toencode if ref($self) && !$self->{'escape'}; - $toencode =~ s{&}{&}gso; - $toencode =~ s{<}{<}gso; - $toencode =~ s{>}{>}gso; - if ($DTD_PUBLIC_IDENTIFIER =~ /[^X]HTML 3\.2/i) { - # $quot; was accidentally omitted from the HTML 3.2 DTD -- see - # / - # . - $toencode =~ s{"}{"}gso; - } - else { - $toencode =~ s{"}{"}gso; - } - my $latin = uc $self->{'.charset'} eq 'ISO-8859-1' || - uc $self->{'.charset'} eq 'WINDOWS-1252'; - if ($latin) { # bug in some browsers - $toencode =~ s{'}{'}gso; - $toencode =~ s{\x8b}{‹}gso; - $toencode =~ s{\x9b}{›}gso; - if (defined $newlinestoo && $newlinestoo) { - $toencode =~ s{\012}{ }gso; - $toencode =~ s{\015}{ }gso; - } - } - return $toencode; -} -END_OF_FUNC - -# unescape HTML -- used internally -'unescapeHTML' => <<'END_OF_FUNC', -sub unescapeHTML { - # hack to work around earlier hacks - push @_,$_[0] if @_==1 && $_[0] eq 'CGI'; - my ($self,$string) = CGI::self_or_default(@_); - return undef unless defined($string); - my $latin = defined $self->{'.charset'} ? $self->{'.charset'} =~ /^(ISO-8859-1|WINDOWS-1252)$/i - : 1; - # thanks to Randal Schwartz for the correct solution to this one - $string=~ s[&(.*?);]{ - local $_ = $1; - /^amp$/i ? "&" : - /^quot$/i ? '"' : - /^gt$/i ? ">" : - /^lt$/i ? "<" : - /^#(\d+)$/ && $latin ? chr($1) : - /^#x([0-9a-f]+)$/i && $latin ? chr(hex($1)) : - $_ - }gex; - return $string; -} -END_OF_FUNC - -# Internal procedure - don't use -'_tableize' => <<'END_OF_FUNC', -sub _tableize { - my($rows,$columns,$rowheaders,$colheaders,@elements) = @_; - $rowheaders = [] unless defined $rowheaders; - $colheaders = [] unless defined $colheaders; - my($result); - - if (defined($columns)) { - $rows = int(0.99 + @elements/$columns) unless defined($rows); - } - if (defined($rows)) { - $columns = int(0.99 + @elements/$rows) unless defined($columns); - } - - # rearrange into a pretty table - $result = ""; - my($row,$column); - unshift(@$colheaders,'') if @$colheaders && @$rowheaders; - $result .= "" if @{$colheaders}; - foreach (@{$colheaders}) { - $result .= ""; - } - for ($row=0;$row<$rows;$row++) { - $result .= ""; - $result .= "" if @$rowheaders; - for ($column=0;$column<$columns;$column++) { - $result .= "" - if defined($elements[$column*$rows + $row]); - } - $result .= ""; - } - $result .= "
$_
$rowheaders->[$row]" . $elements[$column*$rows + $row] . "
"; - return $result; -} -END_OF_FUNC - - -#### Method: radio_group -# Create a list of logically-linked radio buttons. -# Parameters: -# $name -> Common name for all the buttons. -# $values -> A pointer to a regular array containing the -# values for each button in the group. -# $default -> (optional) Value of the button to turn on by default. Pass '-' -# to turn _nothing_ on. -# $linebreak -> (optional) Set to true to place linebreaks -# between the buttons. -# $labels -> (optional) -# A pointer to an associative array of labels to print next to each checkbox -# in the form $label{'value'}="Long explanatory label". -# Otherwise the provided values are used as the labels. -# Returns: -# An ARRAY containing a series of fields -#### -'radio_group' => <<'END_OF_FUNC', -sub radio_group { - my($self,@p) = self_or_default(@_); - - my($name,$values,$default,$linebreak,$labels,$attributes, - $rows,$columns,$rowheaders,$colheaders,$override,$nolabels,@other) = - rearrange([NAME,[VALUES,VALUE],DEFAULT,LINEBREAK,LABELS,ATTRIBUTES, - ROWS,[COLUMNS,COLS], - ROWHEADERS,COLHEADERS, - [OVERRIDE,FORCE],NOLABELS],@p); - my($result,$checked); - - if (!$override && defined($self->param($name))) { - $checked = $self->param($name); - } else { - $checked = $default; - } - my(@elements,@values); - @values = $self->_set_values_and_labels($values,\$labels,$name); - - # If no check array is specified, check the first by default - $checked = $values[0] unless defined($checked) && $checked ne ''; - $name=$self->escapeHTML($name); - - my($other) = @other ? " @other" : ''; - foreach (@values) { - my($checkit) = $checked eq $_ ? qq/ checked="checked"/ : ''; - my($break); - if ($linebreak) { - $break = $XHTML ? "
" : "
"; - } - else { - $break = ''; - } - my($label)=''; - unless (defined($nolabels) && $nolabels) { - $label = $_; - $label = $labels->{$_} if defined($labels) && defined($labels->{$_}); - $label = $self->escapeHTML($label,1); - } - my $attribs = $self->_set_attributes($_, $attributes); - $_=$self->escapeHTML($_); - push(@elements,$XHTML ? qq(${label}${break}) - : qq/${label}${break}/); - } - $self->register_parameter($name); - return wantarray ? @elements : join(' ',@elements) - unless defined($columns) || defined($rows); - return _tableize($rows,$columns,$rowheaders,$colheaders,@elements); -} -END_OF_FUNC - - -#### Method: popup_menu -# Create a popup menu. -# Parameters: -# $name -> Name for all the menu -# $values -> A pointer to a regular array containing the -# text of each menu item. -# $default -> (optional) Default item to display -# $labels -> (optional) -# A pointer to an associative array of labels to print next to each checkbox -# in the form $label{'value'}="Long explanatory label". -# Otherwise the provided values are used as the labels. -# Returns: -# A string containing the definition of a popup menu. -#### -'popup_menu' => <<'END_OF_FUNC', -sub popup_menu { - my($self,@p) = self_or_default(@_); - - my($name,$values,$default,$labels,$attributes,$override,@other) = - rearrange([NAME,[VALUES,VALUE],[DEFAULT,DEFAULTS],LABELS, - ATTRIBUTES,[OVERRIDE,FORCE]],@p); - my($result,$selected); - - if (!$override && defined($self->param($name))) { - $selected = $self->param($name); - } else { - $selected = $default; - } - $name=$self->escapeHTML($name); - my($other) = @other ? " @other" : ''; - - my(@values); - @values = $self->_set_values_and_labels($values,\$labels,$name); - - $result = qq/"; - return $result; -} -END_OF_FUNC - - -#### Method: optgroup -# Create a optgroup. -# Parameters: -# $name -> Label for the group -# $values -> A pointer to a regular array containing the -# values for each option line in the group. -# $labels -> (optional) -# A pointer to an associative array of labels to print next to each item -# in the form $label{'value'}="Long explanatory label". -# Otherwise the provided values are used as the labels. -# $labeled -> (optional) -# A true value indicates the value should be used as the label attribute -# in the option elements. -# The label attribute specifies the option label presented to the user. -# This defaults to the content of the \n/; - foreach (@values) { - if (/_set_attributes($_, $attributes); - my($label) = $_; - $label = $labels->{$_} if defined($labels) && defined($labels->{$_}); - $label=$self->escapeHTML($label); - my($value)=$self->escapeHTML($_,1); - $result .= $labeled ? $novals ? "$label\n" - : "$label\n" - : $novals ? "$label\n" - : "$label\n"; - } - } - $result .= ""; - return $result; -} -END_OF_FUNC - - -#### Method: scrolling_list -# Create a scrolling list. -# Parameters: -# $name -> name for the list -# $values -> A pointer to a regular array containing the -# values for each option line in the list. -# $defaults -> (optional) -# 1. If a pointer to a regular array of options, -# then this will be used to decide which -# lines to turn on by default. -# 2. Otherwise holds the value of the single line to turn on. -# $size -> (optional) Size of the list. -# $multiple -> (optional) If set, allow multiple selections. -# $labels -> (optional) -# A pointer to an associative array of labels to print next to each checkbox -# in the form $label{'value'}="Long explanatory label". -# Otherwise the provided values are used as the labels. -# Returns: -# A string containing the definition of a scrolling list. -#### -'scrolling_list' => <<'END_OF_FUNC', -sub scrolling_list { - my($self,@p) = self_or_default(@_); - my($name,$values,$defaults,$size,$multiple,$labels,$attributes,$override,@other) - = rearrange([NAME,[VALUES,VALUE],[DEFAULTS,DEFAULT], - SIZE,MULTIPLE,LABELS,ATTRIBUTES,[OVERRIDE,FORCE]],@p); - - my($result,@values); - @values = $self->_set_values_and_labels($values,\$labels,$name); - - $size = $size || scalar(@values); - - my(%selected) = $self->previous_or_default($name,$defaults,$override); - my($is_multiple) = $multiple ? qq/ multiple="multiple"/ : ''; - my($has_size) = $size ? qq/ size="$size"/: ''; - my($other) = @other ? " @other" : ''; - - $name=$self->escapeHTML($name); - $result = qq/"; - $self->register_parameter($name); - return $result; -} -END_OF_FUNC - - -#### Method: hidden -# Parameters: -# $name -> Name of the hidden field -# @default -> (optional) Initial values of field (may be an array) -# or -# $default->[initial values of field] -# Returns: -# A string containing a -#### -'hidden' => <<'END_OF_FUNC', -sub hidden { - my($self,@p) = self_or_default(@_); - - # this is the one place where we departed from our standard - # calling scheme, so we have to special-case (darn) - my(@result,@value); - my($name,$default,$override,@other) = - rearrange([NAME,[DEFAULT,VALUE,VALUES],[OVERRIDE,FORCE]],@p); - - my $do_override = 0; - if ( ref($p[0]) || substr($p[0],0,1) eq '-') { - @value = ref($default) ? @{$default} : $default; - $do_override = $override; - } else { - foreach ($default,$override,@other) { - push(@value,$_) if defined($_); - } - } - - # use previous values if override is not set - my @prev = $self->param($name); - @value = @prev if !$do_override && @prev; - - $name=$self->escapeHTML($name); - foreach (@value) { - $_ = defined($_) ? $self->escapeHTML($_,1) : ''; - push @result,$XHTML ? qq() - : qq(); - } - return wantarray ? @result : join('',@result); -} -END_OF_FUNC - - -#### Method: image_button -# Parameters: -# $name -> Name of the button -# $src -> URL of the image source -# $align -> Alignment style (TOP, BOTTOM or MIDDLE) -# Returns: -# A string containing a -#### -'image_button' => <<'END_OF_FUNC', -sub image_button { - my($self,@p) = self_or_default(@_); - - my($name,$src,$alignment,@other) = - rearrange([NAME,SRC,ALIGN],@p); - - my($align) = $alignment ? " align=\U\"$alignment\"" : ''; - my($other) = @other ? " @other" : ''; - $name=$self->escapeHTML($name); - return $XHTML ? qq() - : qq//; -} -END_OF_FUNC - - -#### Method: self_url -# Returns a URL containing the current script and all its -# param/value pairs arranged as a query. You can use this -# to create a link that, when selected, will reinvoke the -# script with all its state information preserved. -#### -'self_url' => <<'END_OF_FUNC', -sub self_url { - my($self,@p) = self_or_default(@_); - return $self->url('-path_info'=>1,'-query'=>1,'-full'=>1,@p); -} -END_OF_FUNC - - -# This is provided as a synonym to self_url() for people unfortunate -# enough to have incorporated it into their programs already! -'state' => <<'END_OF_FUNC', -sub state { - &self_url; -} -END_OF_FUNC - - -#### Method: url -# Like self_url, but doesn't return the query string part of -# the URL. -#### -'url' => <<'END_OF_FUNC', -sub url { - my($self,@p) = self_or_default(@_); - my ($relative,$absolute,$full,$path_info,$query,$base) = - rearrange(['RELATIVE','ABSOLUTE','FULL',['PATH','PATH_INFO'],['QUERY','QUERY_STRING'],'BASE'],@p); - my $url; - $full++ if $base || !($relative || $absolute); - - my $path = $self->path_info; - my $script_name = $self->script_name; - - # for compatibility with Apache's MultiViews - if (exists($ENV{REQUEST_URI})) { - my $index; - $script_name = unescape($ENV{REQUEST_URI}); - $script_name =~ s/\?.+$//s; # strip query string - # and path - if (exists($ENV{PATH_INFO})) { - my $encoded_path = unescape($ENV{PATH_INFO}); - $script_name =~ s/\Q$encoded_path\E$//i; - } - } - - if ($full) { - my $protocol = $self->protocol(); - $url = "$protocol://"; - my $vh = http('x_forwarded_host') || http('host'); - if ($vh) { - $url .= $vh; - } else { - $url .= server_name(); - my $port = $self->server_port; - $url .= ":" . $port - unless (lc($protocol) eq 'http' && $port == 80) - || (lc($protocol) eq 'https' && $port == 443); - } - return $url if $base; - $url .= $script_name; - } elsif ($relative) { - ($url) = $script_name =~ m!([^/]+)$!; - } elsif ($absolute) { - $url = $script_name; - } - - $url .= $path if $path_info and defined $path; - $url .= "?" . $self->query_string if $query and $self->query_string; - $url = '' unless defined $url; - $url =~ s/([^a-zA-Z0-9_.%;&?\/\\:+=~-])/sprintf("%%%02X",ord($1))/eg; - return $url; -} - -END_OF_FUNC - -#### Method: cookie -# Set or read a cookie from the specified name. -# Cookie can then be passed to header(). -# Usual rules apply to the stickiness of -value. -# Parameters: -# -name -> name for this cookie (optional) -# -value -> value of this cookie (scalar, array or hash) -# -path -> paths for which this cookie is valid (optional) -# -domain -> internet domain in which this cookie is valid (optional) -# -secure -> if true, cookie only passed through secure channel (optional) -# -expires -> expiry date in format Wdy, DD-Mon-YYYY HH:MM:SS GMT (optional) -#### -'cookie' => <<'END_OF_FUNC', -sub cookie { - my($self,@p) = self_or_default(@_); - my($name,$value,$path,$domain,$secure,$expires) = - rearrange([NAME,[VALUE,VALUES],PATH,DOMAIN,SECURE,EXPIRES],@p); - - require CGI::Cookie; - - # if no value is supplied, then we retrieve the - # value of the cookie, if any. For efficiency, we cache the parsed - # cookies in our state variables. - unless ( defined($value) ) { - $self->{'.cookies'} = CGI::Cookie->fetch - unless $self->{'.cookies'}; - - # If no name is supplied, then retrieve the names of all our cookies. - return () unless $self->{'.cookies'}; - return keys %{$self->{'.cookies'}} unless $name; - return () unless $self->{'.cookies'}->{$name}; - return $self->{'.cookies'}->{$name}->value if defined($name) && $name ne ''; - } - - # If we get here, we're creating a new cookie - return undef unless defined($name) && $name ne ''; # this is an error - - my @param; - push(@param,'-name'=>$name); - push(@param,'-value'=>$value); - push(@param,'-domain'=>$domain) if $domain; - push(@param,'-path'=>$path) if $path; - push(@param,'-expires'=>$expires) if $expires; - push(@param,'-secure'=>$secure) if $secure; - - return new CGI::Cookie(@param); -} -END_OF_FUNC - -'parse_keywordlist' => <<'END_OF_FUNC', -sub parse_keywordlist { - my($self,$tosplit) = @_; - $tosplit = unescape($tosplit); # unescape the keywords - $tosplit=~tr/+/ /; # pluses to spaces - my(@keywords) = split(/\s+/,$tosplit); - return @keywords; -} -END_OF_FUNC - -'param_fetch' => <<'END_OF_FUNC', -sub param_fetch { - my($self,@p) = self_or_default(@_); - my($name) = rearrange([NAME],@p); - unless (exists($self->{$name})) { - $self->add_parameter($name); - $self->{$name} = []; - } - - return $self->{$name}; -} -END_OF_FUNC - -############################################### -# OTHER INFORMATION PROVIDED BY THE ENVIRONMENT -############################################### - -#### Method: path_info -# Return the extra virtual path information provided -# after the URL (if any) -#### -'path_info' => <<'END_OF_FUNC', -sub path_info { - my ($self,$info) = self_or_default(@_); - if (defined($info)) { - $info = "/$info" if $info ne '' && substr($info,0,1) ne '/'; - $self->{'.path_info'} = $info; - } elsif (! defined($self->{'.path_info'}) ) { - $self->{'.path_info'} = defined($ENV{'PATH_INFO'}) ? - $ENV{'PATH_INFO'} : ''; - - # hack to fix broken path info in IIS - $self->{'.path_info'} =~ s/^\Q$ENV{'SCRIPT_NAME'}\E// if $IIS; - - } - return $self->{'.path_info'}; -} -END_OF_FUNC - - -#### Method: request_method -# Returns 'POST', 'GET', 'PUT' or 'HEAD' -#### -'request_method' => <<'END_OF_FUNC', -sub request_method { - return $ENV{'REQUEST_METHOD'}; -} -END_OF_FUNC - -#### Method: content_type -# Returns the content_type string -#### -'content_type' => <<'END_OF_FUNC', -sub content_type { - return $ENV{'CONTENT_TYPE'}; -} -END_OF_FUNC - -#### Method: path_translated -# Return the physical path information provided -# by the URL (if any) -#### -'path_translated' => <<'END_OF_FUNC', -sub path_translated { - return $ENV{'PATH_TRANSLATED'}; -} -END_OF_FUNC - - -#### Method: query_string -# Synthesize a query string from our current -# parameters -#### -'query_string' => <<'END_OF_FUNC', -sub query_string { - my($self) = self_or_default(@_); - my($param,$value,@pairs); - foreach $param ($self->param) { - my($eparam) = escape($param); - foreach $value ($self->param($param)) { - $value = escape($value); - next unless defined $value; - push(@pairs,"$eparam=$value"); - } - } - foreach (keys %{$self->{'.fieldnames'}}) { - push(@pairs,".cgifields=".escape("$_")); - } - return join($USE_PARAM_SEMICOLONS ? ';' : '&',@pairs); -} -END_OF_FUNC - - -#### Method: accept -# Without parameters, returns an array of the -# MIME types the browser accepts. -# With a single parameter equal to a MIME -# type, will return undef if the browser won't -# accept it, 1 if the browser accepts it but -# doesn't give a preference, or a floating point -# value between 0.0 and 1.0 if the browser -# declares a quantitative score for it. -# This handles MIME type globs correctly. -#### -'Accept' => <<'END_OF_FUNC', -sub Accept { - my($self,$search) = self_or_CGI(@_); - my(%prefs,$type,$pref,$pat); - - my(@accept) = split(',',$self->http('accept')); - - foreach (@accept) { - ($pref) = /q=(\d\.\d+|\d+)/; - ($type) = m#(\S+/[^;]+)#; - next unless $type; - $prefs{$type}=$pref || 1; - } - - return keys %prefs unless $search; - - # if a search type is provided, we may need to - # perform a pattern matching operation. - # The MIME types use a glob mechanism, which - # is easily translated into a perl pattern match - - # First return the preference for directly supported - # types: - return $prefs{$search} if $prefs{$search}; - - # Didn't get it, so try pattern matching. - foreach (keys %prefs) { - next unless /\*/; # not a pattern match - ($pat = $_) =~ s/([^\w*])/\\$1/g; # escape meta characters - $pat =~ s/\*/.*/g; # turn it into a pattern - return $prefs{$_} if $search=~/$pat/; - } -} -END_OF_FUNC - - -#### Method: user_agent -# If called with no parameters, returns the user agent. -# If called with one parameter, does a pattern match (case -# insensitive) on the user agent. -#### -'user_agent' => <<'END_OF_FUNC', -sub user_agent { - my($self,$match)=self_or_CGI(@_); - return $self->http('user_agent') unless $match; - return $self->http('user_agent') =~ /$match/i; -} -END_OF_FUNC - - -#### Method: raw_cookie -# Returns the magic cookies for the session. -# The cookies are not parsed or altered in any way, i.e. -# cookies are returned exactly as given in the HTTP -# headers. If a cookie name is given, only that cookie's -# value is returned, otherwise the entire raw cookie -# is returned. -#### -'raw_cookie' => <<'END_OF_FUNC', -sub raw_cookie { - my($self,$key) = self_or_CGI(@_); - - require CGI::Cookie; - - if (defined($key)) { - $self->{'.raw_cookies'} = CGI::Cookie->raw_fetch - unless $self->{'.raw_cookies'}; - - return () unless $self->{'.raw_cookies'}; - return () unless $self->{'.raw_cookies'}->{$key}; - return $self->{'.raw_cookies'}->{$key}; - } - return $self->http('cookie') || $ENV{'COOKIE'} || ''; -} -END_OF_FUNC - -#### Method: virtual_host -# Return the name of the virtual_host, which -# is not always the same as the server -###### -'virtual_host' => <<'END_OF_FUNC', -sub virtual_host { - my $vh = http('x_forwarded_host') || http('host') || server_name(); - $vh =~ s/:\d+$//; # get rid of port number - return $vh; -} -END_OF_FUNC - -#### Method: remote_host -# Return the name of the remote host, or its IP -# address if unavailable. If this variable isn't -# defined, it returns "localhost" for debugging -# purposes. -#### -'remote_host' => <<'END_OF_FUNC', -sub remote_host { - return $ENV{'REMOTE_HOST'} || $ENV{'REMOTE_ADDR'} - || 'localhost'; -} -END_OF_FUNC - - -#### Method: remote_addr -# Return the IP addr of the remote host. -#### -'remote_addr' => <<'END_OF_FUNC', -sub remote_addr { - return $ENV{'REMOTE_ADDR'} || '127.0.0.1'; -} -END_OF_FUNC - - -#### Method: script_name -# Return the partial URL to this script for -# self-referencing scripts. Also see -# self_url(), which returns a URL with all state information -# preserved. -#### -'script_name' => <<'END_OF_FUNC', -sub script_name { - return $ENV{'SCRIPT_NAME'} if defined($ENV{'SCRIPT_NAME'}); - # These are for debugging - return "/$0" unless $0=~/^\//; - return $0; -} -END_OF_FUNC - - -#### Method: referer -# Return the HTTP_REFERER: useful for generating -# a GO BACK button. -#### -'referer' => <<'END_OF_FUNC', -sub referer { - my($self) = self_or_CGI(@_); - return $self->http('referer'); -} -END_OF_FUNC - - -#### Method: server_name -# Return the name of the server -#### -'server_name' => <<'END_OF_FUNC', -sub server_name { - return $ENV{'SERVER_NAME'} || 'localhost'; -} -END_OF_FUNC - -#### Method: server_software -# Return the name of the server software -#### -'server_software' => <<'END_OF_FUNC', -sub server_software { - return $ENV{'SERVER_SOFTWARE'} || 'cmdline'; -} -END_OF_FUNC - -#### Method: virtual_port -# Return the server port, taking virtual hosts into account -#### -'virtual_port' => <<'END_OF_FUNC', -sub virtual_port { - my($self) = self_or_default(@_); - my $vh = $self->http('x_forwarded_host') || $self->http('host'); - if ($vh) { - return ($vh =~ /:(\d+)$/)[0] || '80'; - } else { - return $self->server_port(); - } -} -END_OF_FUNC - -#### Method: server_port -# Return the tcp/ip port the server is running on -#### -'server_port' => <<'END_OF_FUNC', -sub server_port { - return $ENV{'SERVER_PORT'} || 80; # for debugging -} -END_OF_FUNC - -#### Method: server_protocol -# Return the protocol (usually HTTP/1.0) -#### -'server_protocol' => <<'END_OF_FUNC', -sub server_protocol { - return $ENV{'SERVER_PROTOCOL'} || 'HTTP/1.0'; # for debugging -} -END_OF_FUNC - -#### Method: http -# Return the value of an HTTP variable, or -# the list of variables if none provided -#### -'http' => <<'END_OF_FUNC', -sub http { - my ($self,$parameter) = self_or_CGI(@_); - return $ENV{$parameter} if $parameter=~/^HTTP/; - $parameter =~ tr/-/_/; - return $ENV{"HTTP_\U$parameter\E"} if $parameter; - my(@p); - foreach (keys %ENV) { - push(@p,$_) if /^HTTP/; - } - return @p; -} -END_OF_FUNC - -#### Method: https -# Return the value of HTTPS -#### -'https' => <<'END_OF_FUNC', -sub https { - local($^W)=0; - my ($self,$parameter) = self_or_CGI(@_); - return $ENV{HTTPS} unless $parameter; - return $ENV{$parameter} if $parameter=~/^HTTPS/; - $parameter =~ tr/-/_/; - return $ENV{"HTTPS_\U$parameter\E"} if $parameter; - my(@p); - foreach (keys %ENV) { - push(@p,$_) if /^HTTPS/; - } - return @p; -} -END_OF_FUNC - -#### Method: protocol -# Return the protocol (http or https currently) -#### -'protocol' => <<'END_OF_FUNC', -sub protocol { - local($^W)=0; - my $self = shift; - return 'https' if uc($self->https()) eq 'ON'; - return 'https' if $self->server_port == 443; - my $prot = $self->server_protocol; - my($protocol,$version) = split('/',$prot); - return "\L$protocol\E"; -} -END_OF_FUNC - -#### Method: remote_ident -# Return the identity of the remote user -# (but only if his host is running identd) -#### -'remote_ident' => <<'END_OF_FUNC', -sub remote_ident { - return $ENV{'REMOTE_IDENT'}; -} -END_OF_FUNC - - -#### Method: auth_type -# Return the type of use verification/authorization in use, if any. -#### -'auth_type' => <<'END_OF_FUNC', -sub auth_type { - return $ENV{'AUTH_TYPE'}; -} -END_OF_FUNC - - -#### Method: remote_user -# Return the authorization name used for user -# verification. -#### -'remote_user' => <<'END_OF_FUNC', -sub remote_user { - return $ENV{'REMOTE_USER'}; -} -END_OF_FUNC - - -#### Method: user_name -# Try to return the remote user's name by hook or by -# crook -#### -'user_name' => <<'END_OF_FUNC', -sub user_name { - my ($self) = self_or_CGI(@_); - return $self->http('from') || $ENV{'REMOTE_IDENT'} || $ENV{'REMOTE_USER'}; -} -END_OF_FUNC - -#### Method: nosticky -# Set or return the NOSTICKY global flag -#### -'nosticky' => <<'END_OF_FUNC', -sub nosticky { - my ($self,$param) = self_or_CGI(@_); - $CGI::NOSTICKY = $param if defined($param); - return $CGI::NOSTICKY; -} -END_OF_FUNC - -#### Method: nph -# Set or return the NPH global flag -#### -'nph' => <<'END_OF_FUNC', -sub nph { - my ($self,$param) = self_or_CGI(@_); - $CGI::NPH = $param if defined($param); - return $CGI::NPH; -} -END_OF_FUNC - -#### Method: private_tempfiles -# Set or return the private_tempfiles global flag -#### -'private_tempfiles' => <<'END_OF_FUNC', -sub private_tempfiles { - my ($self,$param) = self_or_CGI(@_); - $CGI::PRIVATE_TEMPFILES = $param if defined($param); - return $CGI::PRIVATE_TEMPFILES; -} -END_OF_FUNC -#### Method: close_upload_files -# Set or return the close_upload_files global flag -#### -'close_upload_files' => <<'END_OF_FUNC', -sub close_upload_files { - my ($self,$param) = self_or_CGI(@_); - $CGI::CLOSE_UPLOAD_FILES = $param if defined($param); - return $CGI::CLOSE_UPLOAD_FILES; -} -END_OF_FUNC - - -#### Method: default_dtd -# Set or return the default_dtd global -#### -'default_dtd' => <<'END_OF_FUNC', -sub default_dtd { - my ($self,$param,$param2) = self_or_CGI(@_); - if (defined $param2 && defined $param) { - $CGI::DEFAULT_DTD = [ $param, $param2 ]; - } elsif (defined $param) { - $CGI::DEFAULT_DTD = $param; - } - return $CGI::DEFAULT_DTD; -} -END_OF_FUNC - -# -------------- really private subroutines ----------------- -'previous_or_default' => <<'END_OF_FUNC', -sub previous_or_default { - my($self,$name,$defaults,$override) = @_; - my(%selected); - - if (!$override && ($self->{'.fieldnames'}->{$name} || - defined($self->param($name)) ) ) { - grep($selected{$_}++,$self->param($name)); - } elsif (defined($defaults) && ref($defaults) && - (ref($defaults) eq 'ARRAY')) { - grep($selected{$_}++,@{$defaults}); - } else { - $selected{$defaults}++ if defined($defaults); - } - - return %selected; -} -END_OF_FUNC - -'register_parameter' => <<'END_OF_FUNC', -sub register_parameter { - my($self,$param) = @_; - $self->{'.parametersToAdd'}->{$param}++; -} -END_OF_FUNC - -'get_fields' => <<'END_OF_FUNC', -sub get_fields { - my($self) = @_; - return $self->CGI::hidden('-name'=>'.cgifields', - '-values'=>[keys %{$self->{'.parametersToAdd'}}], - '-override'=>1); -} -END_OF_FUNC - -'read_from_cmdline' => <<'END_OF_FUNC', -sub read_from_cmdline { - my($input,@words); - my($query_string); - my($subpath); - if ($DEBUG && @ARGV) { - @words = @ARGV; - } elsif ($DEBUG > 1) { - require "shellwords.pl"; - print STDERR "(offline mode: enter name=value pairs on standard input; press ^D or ^Z when done)\n"; - chomp(@lines = ); # remove newlines - $input = join(" ",@lines); - @words = &shellwords($input); - } - foreach (@words) { - s/\\=/%3D/g; - s/\\&/%26/g; - } - - if ("@words"=~/=/) { - $query_string = join('&',@words); - } else { - $query_string = join('+',@words); - } - if ($query_string =~ /^(.*?)\?(.*)$/) - { - $query_string = $2; - $subpath = $1; - } - return { 'query_string' => $query_string, 'subpath' => $subpath }; -} -END_OF_FUNC - -##### -# subroutine: read_multipart -# -# Read multipart data and store it into our parameters. -# An interesting feature is that if any of the parts is a file, we -# create a temporary file and open up a filehandle on it so that the -# caller can read from it if necessary. -##### -'read_multipart' => <<'END_OF_FUNC', -sub read_multipart { - my($self,$boundary,$length) = @_; - my($buffer) = $self->new_MultipartBuffer($boundary,$length); - return unless $buffer; - my(%header,$body); - my $filenumber = 0; - while (!$buffer->eof) { - %header = $buffer->readHeader; - - unless (%header) { - $self->cgi_error("400 Bad request (malformed multipart POST)"); - return; - } - - my($param)= $header{'Content-Disposition'}=~/ name="([^;]*)"/; - $param .= $TAINTED; - - # Bug: Netscape doesn't escape quotation marks in file names!!! - my($filename) = $header{'Content-Disposition'}=~/ filename="([^;]*)"/; - # Test for Opera's multiple upload feature - my($multipart) = ( defined( $header{'Content-Type'} ) && - $header{'Content-Type'} =~ /multipart\/mixed/ ) ? - 1 : 0; - - # add this parameter to our list - $self->add_parameter($param); - - # If no filename specified, then just read the data and assign it - # to our parameter list. - if ( ( !defined($filename) || $filename eq '' ) && !$multipart ) { - my($value) = $buffer->readBody; - $value .= $TAINTED; - push(@{$self->{$param}},$value); - next; - } - - my ($tmpfile,$tmp,$filehandle); - UPLOADS: { - # If we get here, then we are dealing with a potentially large - # uploaded form. Save the data to a temporary file, then open - # the file for reading. - - # skip the file if uploads disabled - if ($DISABLE_UPLOADS) { - while (defined($data = $buffer->read)) { } - last UPLOADS; - } - - # set the filename to some recognizable value - if ( ( !defined($filename) || $filename eq '' ) && $multipart ) { - $filename = "multipart/mixed"; - } - - # choose a relatively unpredictable tmpfile sequence number - my $seqno = unpack("%16C*",join('',localtime,values %ENV)); - for (my $cnt=10;$cnt>0;$cnt--) { - next unless $tmpfile = new CGITempFile($seqno); - $tmp = $tmpfile->as_string; - last if defined($filehandle = Fh->new($filename,$tmp,$PRIVATE_TEMPFILES)); - $seqno += int rand(100); - } - die "CGI open of tmpfile: $!\n" unless defined $filehandle; - $CGI::DefaultClass->binmode($filehandle) if $CGI::needs_binmode - && defined fileno($filehandle); - - # if this is an multipart/mixed attachment, save the header - # together with the body for later parsing with an external - # MIME parser module - if ( $multipart ) { - foreach ( keys %header ) { - print $filehandle "$_: $header{$_}${CRLF}"; - } - print $filehandle "${CRLF}"; - } - - my ($data); - local($\) = ''; - my $totalbytes; - while (defined($data = $buffer->read)) { - if (defined $self->{'.upload_hook'}) - { - $totalbytes += length($data); - &{$self->{'.upload_hook'}}($filename ,$data, $totalbytes, $self->{'.upload_data'}); - } - print $filehandle $data; - } - - # back up to beginning of file - seek($filehandle,0,0); - - ## Close the filehandle if requested this allows a multipart MIME - ## upload to contain many files, and we won't die due to too many - ## open file handles. The user can access the files using the hash - ## below. - close $filehandle if $CLOSE_UPLOAD_FILES; - $CGI::DefaultClass->binmode($filehandle) if $CGI::needs_binmode; - - # Save some information about the uploaded file where we can get - # at it later. - $self->{'.tmpfiles'}->{fileno($filehandle)}= { - hndl => $filehandle, - name => $tmpfile, - info => {%header}, - }; - push(@{$self->{$param}},$filehandle); - } - } -} -END_OF_FUNC - -'upload' =><<'END_OF_FUNC', -sub upload { - my($self,$param_name) = self_or_default(@_); - my @param = grep(ref && fileno($_), $self->param($param_name)); - return unless @param; - return wantarray ? @param : $param[0]; -} -END_OF_FUNC - -'tmpFileName' => <<'END_OF_FUNC', -sub tmpFileName { - my($self,$filename) = self_or_default(@_); - return $self->{'.tmpfiles'}->{fileno($filename)}->{name} ? - $self->{'.tmpfiles'}->{fileno($filename)}->{name}->as_string - : ''; -} -END_OF_FUNC - -'uploadInfo' => <<'END_OF_FUNC', -sub uploadInfo { - my($self,$filename) = self_or_default(@_); - return $self->{'.tmpfiles'}->{fileno($filename)}->{info}; -} -END_OF_FUNC - -# internal routine, don't use -'_set_values_and_labels' => <<'END_OF_FUNC', -sub _set_values_and_labels { - my $self = shift; - my ($v,$l,$n) = @_; - $$l = $v if ref($v) eq 'HASH' && !ref($$l); - return $self->param($n) if !defined($v); - return $v if !ref($v); - return ref($v) eq 'HASH' ? keys %$v : @$v; -} -END_OF_FUNC - -# internal routine, don't use -'_set_attributes' => <<'END_OF_FUNC', -sub _set_attributes { - my $self = shift; - my($element, $attributes) = @_; - return '' unless defined($attributes->{$element}); - $attribs = ' '; - foreach my $attrib (keys %{$attributes->{$element}}) { - (my $clean_attrib = $attrib) =~ s/^-//; - $attribs .= "@{[lc($clean_attrib)]}=\"$attributes->{$element}{$attrib}\" "; - } - $attribs =~ s/ $//; - return $attribs; -} -END_OF_FUNC - -'_compile_all' => <<'END_OF_FUNC', -sub _compile_all { - foreach (@_) { - next if defined(&$_); - $AUTOLOAD = "CGI::$_"; - _compile(); - } -} -END_OF_FUNC - -); -END_OF_AUTOLOAD -; - -######################################################### -# Globals and stubs for other packages that we use. -######################################################### - -################### Fh -- lightweight filehandle ############### -package Fh; -use overload - '""' => \&asString, - 'cmp' => \&compare, - 'fallback'=>1; - -$FH='fh00000'; - -*Fh::AUTOLOAD = \&CGI::AUTOLOAD; - -$AUTOLOADED_ROUTINES = ''; # prevent -w error -$AUTOLOADED_ROUTINES=<<'END_OF_AUTOLOAD'; -%SUBS = ( -'asString' => <<'END_OF_FUNC', -sub asString { - my $self = shift; - # get rid of package name - (my $i = $$self) =~ s/^\*(\w+::fh\d{5})+//; - $i =~ s/%(..)/ chr(hex($1)) /eg; - return $i.$CGI::TAINTED; -# BEGIN DEAD CODE -# This was an extremely clever patch that allowed "use strict refs". -# Unfortunately it relied on another bug that caused leaky file descriptors. -# The underlying bug has been fixed, so this no longer works. However -# "strict refs" still works for some reason. -# my $self = shift; -# return ${*{$self}{SCALAR}}; -# END DEAD CODE -} -END_OF_FUNC - -'compare' => <<'END_OF_FUNC', -sub compare { - my $self = shift; - my $value = shift; - return "$self" cmp $value; -} -END_OF_FUNC - -'new' => <<'END_OF_FUNC', -sub new { - my($pack,$name,$file,$delete) = @_; - _setup_symbols(@SAVED_SYMBOLS) if @SAVED_SYMBOLS; - require Fcntl unless defined &Fcntl::O_RDWR; - (my $safename = $name) =~ s/([':%])/ sprintf '%%%02X', ord $1 /eg; - my $fv = ++$FH . $safename; - my $ref = \*{"Fh::$fv"}; - $file =~ m!^([a-zA-Z0-9_ \'\":/.\$\\-]+)$! || return; - my $safe = $1; - sysopen($ref,$safe,Fcntl::O_RDWR()|Fcntl::O_CREAT()|Fcntl::O_EXCL(),0600) || return; - unlink($safe) if $delete; - CORE::delete $Fh::{$fv}; - return bless $ref,$pack; -} -END_OF_FUNC - -'DESTROY' => <<'END_OF_FUNC', -sub DESTROY { - my $self = shift; - close $self; -} -END_OF_FUNC - -); -END_OF_AUTOLOAD - -######################## MultipartBuffer #################### -package MultipartBuffer; - -use constant DEBUG => 0; - -# how many bytes to read at a time. We use -# a 4K buffer by default. -$INITIAL_FILLUNIT = 1024 * 4; -$TIMEOUT = 240*60; # 4 hour timeout for big files -$SPIN_LOOP_MAX = 2000; # bug fix for some Netscape servers -$CRLF=$CGI::CRLF; - -#reuse the autoload function -*MultipartBuffer::AUTOLOAD = \&CGI::AUTOLOAD; - -# avoid autoloader warnings -sub DESTROY {} - -############################################################################### -################# THESE FUNCTIONS ARE AUTOLOADED ON DEMAND #################### -############################################################################### -$AUTOLOADED_ROUTINES = ''; # prevent -w error -$AUTOLOADED_ROUTINES=<<'END_OF_AUTOLOAD'; -%SUBS = ( - -'new' => <<'END_OF_FUNC', -sub new { - my($package,$interface,$boundary,$length) = @_; - $FILLUNIT = $INITIAL_FILLUNIT; - $CGI::DefaultClass->binmode($IN); # if $CGI::needs_binmode; # just do it always - - # If the user types garbage into the file upload field, - # then Netscape passes NOTHING to the server (not good). - # We may hang on this read in that case. So we implement - # a read timeout. If nothing is ready to read - # by then, we return. - - # Netscape seems to be a little bit unreliable - # about providing boundary strings. - my $boundary_read = 0; - if ($boundary) { - - # Under the MIME spec, the boundary consists of the - # characters "--" PLUS the Boundary string - - # BUG: IE 3.01 on the Macintosh uses just the boundary -- not - # the two extra hyphens. We do a special case here on the user-agent!!!! - $boundary = "--$boundary" unless CGI::user_agent('MSIE\s+3\.0[12];\s*Mac|DreamPassport'); - - } else { # otherwise we find it ourselves - my($old); - ($old,$/) = ($/,$CRLF); # read a CRLF-delimited line - $boundary = ; # BUG: This won't work correctly under mod_perl - $length -= length($boundary); - chomp($boundary); # remove the CRLF - $/ = $old; # restore old line separator - $boundary_read++; - } - - my $self = {LENGTH=>$length, - BOUNDARY=>$boundary, - INTERFACE=>$interface, - BUFFER=>'', - }; - - $FILLUNIT = length($boundary) - if length($boundary) > $FILLUNIT; - - my $retval = bless $self,ref $package || $package; - - # Read the preamble and the topmost (boundary) line plus the CRLF. - unless ($boundary_read) { - while ($self->read(0)) { } - } - die "Malformed multipart POST: data truncated\n" if $self->eof; - - return $retval; -} -END_OF_FUNC - -'readHeader' => <<'END_OF_FUNC', -sub readHeader { - my($self) = @_; - my($end); - my($ok) = 0; - my($bad) = 0; - - local($CRLF) = "\015\012" if $CGI::OS eq 'VMS' || $CGI::EBCDIC; - - do { - $self->fillBuffer($FILLUNIT); - $ok++ if ($end = index($self->{BUFFER},"${CRLF}${CRLF}")) >= 0; - $ok++ if $self->{BUFFER} eq ''; - $bad++ if !$ok && $self->{LENGTH} <= 0; - # this was a bad idea - # $FILLUNIT *= 2 if length($self->{BUFFER}) >= $FILLUNIT; - } until $ok || $bad; - return () if $bad; - - #EBCDIC NOTE: translate header into EBCDIC, but watch out for continuation lines! - - my($header) = substr($self->{BUFFER},0,$end+2); - substr($self->{BUFFER},0,$end+4) = ''; - my %return; - - if ($CGI::EBCDIC) { - warn "untranslated header=$header\n" if DEBUG; - $header = CGI::Util::ascii2ebcdic($header); - warn "translated header=$header\n" if DEBUG; - } - - # See RFC 2045 Appendix A and RFC 822 sections 3.4.8 - # (Folding Long Header Fields), 3.4.3 (Comments) - # and 3.4.5 (Quoted-Strings). - - my $token = '[-\w!\#$%&\'*+.^_\`|{}~]'; - $header=~s/$CRLF\s+/ /og; # merge continuation lines - - while ($header=~/($token+):\s+([^$CRLF]*)/mgox) { - my ($field_name,$field_value) = ($1,$2); - $field_name =~ s/\b(\w)/uc($1)/eg; #canonicalize - $return{$field_name}=$field_value; - } - return %return; -} -END_OF_FUNC - -# This reads and returns the body as a single scalar value. -'readBody' => <<'END_OF_FUNC', -sub readBody { - my($self) = @_; - my($data); - my($returnval)=''; - - #EBCDIC NOTE: want to translate returnval into EBCDIC HERE - - while (defined($data = $self->read)) { - $returnval .= $data; - } - - if ($CGI::EBCDIC) { - warn "untranslated body=$returnval\n" if DEBUG; - $returnval = CGI::Util::ascii2ebcdic($returnval); - warn "translated body=$returnval\n" if DEBUG; - } - return $returnval; -} -END_OF_FUNC - -# This will read $bytes or until the boundary is hit, whichever happens -# first. After the boundary is hit, we return undef. The next read will -# skip over the boundary and begin reading again; -'read' => <<'END_OF_FUNC', -sub read { - my($self,$bytes) = @_; - - # default number of bytes to read - $bytes = $bytes || $FILLUNIT; - - # Fill up our internal buffer in such a way that the boundary - # is never split between reads. - $self->fillBuffer($bytes); - - my $boundary_start = $CGI::EBCDIC ? CGI::Util::ebcdic2ascii($self->{BOUNDARY}) : $self->{BOUNDARY}; - my $boundary_end = $CGI::EBCDIC ? CGI::Util::ebcdic2ascii($self->{BOUNDARY}.'--') : $self->{BOUNDARY}.'--'; - - # Find the boundary in the buffer (it may not be there). - my $start = index($self->{BUFFER},$boundary_start); - - warn "boundary=$self->{BOUNDARY} length=$self->{LENGTH} start=$start\n" if DEBUG; - # protect against malformed multipart POST operations - die "Malformed multipart POST\n" unless ($start >= 0) || ($self->{LENGTH} > 0); - - - #EBCDIC NOTE: want to translate boundary search into ASCII here. - - # If the boundary begins the data, then skip past it - # and return undef. - if ($start == 0) { - - # clear us out completely if we've hit the last boundary. - if (index($self->{BUFFER},$boundary_end)==0) { - $self->{BUFFER}=''; - $self->{LENGTH}=0; - return undef; - } - - # just remove the boundary. - substr($self->{BUFFER},0,length($boundary_start))=''; - $self->{BUFFER} =~ s/^\012\015?//; - return undef; - } - - my $bytesToReturn; - if ($start > 0) { # read up to the boundary - $bytesToReturn = $start-2 > $bytes ? $bytes : $start; - } else { # read the requested number of bytes - # leave enough bytes in the buffer to allow us to read - # the boundary. Thanks to Kevin Hendrick for finding - # this one. - $bytesToReturn = $bytes - (length($boundary_start)+1); - } - - my $returnval=substr($self->{BUFFER},0,$bytesToReturn); - substr($self->{BUFFER},0,$bytesToReturn)=''; - - # If we hit the boundary, remove the CRLF from the end. - return ($bytesToReturn==$start) - ? substr($returnval,0,-2) : $returnval; -} -END_OF_FUNC - - -# This fills up our internal buffer in such a way that the -# boundary is never split between reads -'fillBuffer' => <<'END_OF_FUNC', -sub fillBuffer { - my($self,$bytes) = @_; - return unless $self->{LENGTH}; - - my($boundaryLength) = length($self->{BOUNDARY}); - my($bufferLength) = length($self->{BUFFER}); - my($bytesToRead) = $bytes - $bufferLength + $boundaryLength + 2; - $bytesToRead = $self->{LENGTH} if $self->{LENGTH} < $bytesToRead; - - # Try to read some data. We may hang here if the browser is screwed up. - my $bytesRead = $self->{INTERFACE}->read_from_client(\$self->{BUFFER}, - $bytesToRead, - $bufferLength); - warn "bytesToRead=$bytesToRead, bufferLength=$bufferLength, buffer=$self->{BUFFER}\n" if DEBUG; - $self->{BUFFER} = '' unless defined $self->{BUFFER}; - - # An apparent bug in the Apache server causes the read() - # to return zero bytes repeatedly without blocking if the - # remote user aborts during a file transfer. I don't know how - # they manage this, but the workaround is to abort if we get - # more than SPIN_LOOP_MAX consecutive zero reads. - if ($bytesRead == 0) { - die "CGI.pm: Server closed socket during multipart read (client aborted?).\n" - if ($self->{ZERO_LOOP_COUNTER}++ >= $SPIN_LOOP_MAX); - } else { - $self->{ZERO_LOOP_COUNTER}=0; - } - - $self->{LENGTH} -= $bytesRead; -} -END_OF_FUNC - - -# Return true when we've finished reading -'eof' => <<'END_OF_FUNC' -sub eof { - my($self) = @_; - return 1 if (length($self->{BUFFER}) == 0) - && ($self->{LENGTH} <= 0); - undef; -} -END_OF_FUNC - -); -END_OF_AUTOLOAD - -#################################################################################### -################################## TEMPORARY FILES ################################# -#################################################################################### -package CGITempFile; - -sub find_tempdir { - undef $TMPDIRECTORY; - $SL = $CGI::SL; - $MAC = $CGI::OS eq 'MACINTOSH'; - my ($vol) = $MAC ? MacPerl::Volumes() =~ /:(.*)/ : ""; - unless ($TMPDIRECTORY) { - @TEMP=("${SL}usr${SL}tmp","${SL}var${SL}tmp", - "C:${SL}temp","${SL}tmp","${SL}temp", - "${vol}${SL}Temporary Items", - "${SL}WWW_ROOT", "${SL}SYS\$SCRATCH", - "C:${SL}system${SL}temp"); - unshift(@TEMP,$ENV{'TMPDIR'}) if defined $ENV{'TMPDIR'}; - - # this feature was supposed to provide per-user tmpfiles, but - # it is problematic. - # unshift(@TEMP,(getpwuid($<))[7].'/tmp') if $CGI::OS eq 'UNIX'; - # Rob: getpwuid() is unfortunately UNIX specific. On brain dead OS'es this - # : can generate a 'getpwuid() not implemented' exception, even though - # : it's never called. Found under DOS/Win with the DJGPP perl port. - # : Refer to getpwuid() only at run-time if we're fortunate and have UNIX. - # unshift(@TEMP,(eval {(getpwuid($>))[7]}).'/tmp') if $CGI::OS eq 'UNIX' and $> != 0; - - foreach (@TEMP) { - do {$TMPDIRECTORY = $_; last} if -d $_ && -w _; - } - } - $TMPDIRECTORY = $MAC ? "" : "." unless $TMPDIRECTORY; -} - -find_tempdir(); - -$MAXTRIES = 5000; - -# cute feature, but overload implementation broke it -# %OVERLOAD = ('""'=>'as_string'); -*CGITempFile::AUTOLOAD = \&CGI::AUTOLOAD; - -sub DESTROY { - my($self) = @_; - $$self =~ m!^([a-zA-Z0-9_ \'\":/.\$\\-]+)$! || return; - my $safe = $1; # untaint operation - unlink $safe; # get rid of the file -} - -############################################################################### -################# THESE FUNCTIONS ARE AUTOLOADED ON DEMAND #################### -############################################################################### -$AUTOLOADED_ROUTINES = ''; # prevent -w error -$AUTOLOADED_ROUTINES=<<'END_OF_AUTOLOAD'; -%SUBS = ( - -'new' => <<'END_OF_FUNC', -sub new { - my($package,$sequence) = @_; - my $filename; - find_tempdir() unless -w $TMPDIRECTORY; - for (my $i = 0; $i < $MAXTRIES; $i++) { - last if ! -f ($filename = sprintf("${TMPDIRECTORY}${SL}CGItemp%d",$sequence++)); - } - # check that it is a more-or-less valid filename - return unless $filename =~ m!^([a-zA-Z0-9_ \'\":/.\$\\-]+)$!; - # this used to untaint, now it doesn't - # $filename = $1; - return bless \$filename; -} -END_OF_FUNC - -'as_string' => <<'END_OF_FUNC' -sub as_string { - my($self) = @_; - return $$self; -} -END_OF_FUNC - -); -END_OF_AUTOLOAD - -package CGI; - -# We get a whole bunch of warnings about "possibly uninitialized variables" -# when running with the -w switch. Touch them all once to get rid of the -# warnings. This is ugly and I hate it. -if ($^W) { - $CGI::CGI = ''; - $CGI::CGI=<'words', - -values=>['eenie','meenie','minie','moe'], - -defaults=>['eenie','minie']), p, - "What's your favorite color? ", - popup_menu(-name=>'color', - -values=>['red','green','blue','chartreuse']),p, - submit, - end_form, - hr; - - if (param()) { - print "Your name is",em(param('name')),p, - "The keywords are: ",em(join(", ",param('words'))),p, - "Your favorite color is ",em(param('color')), - hr; - } - -=head1 ABSTRACT - -This perl library uses perl5 objects to make it easy to create Web -fill-out forms and parse their contents. This package defines CGI -objects, entities that contain the values of the current query string -and other state variables. Using a CGI object's methods, you can -examine keywords and parameters passed to your script, and create -forms whose initial values are taken from the current query (thereby -preserving state information). The module provides shortcut functions -that produce boilerplate HTML, reducing typing and coding errors. It -also provides functionality for some of the more advanced features of -CGI scripting, including support for file uploads, cookies, cascading -style sheets, server push, and frames. - -CGI.pm also provides a simple function-oriented programming style for -those who don't need its object-oriented features. - -The current version of CGI.pm is available at - - http://www.genome.wi.mit.edu/ftp/pub/software/WWW/cgi_docs.html - ftp://ftp-genome.wi.mit.edu/pub/software/WWW/ - -=head1 DESCRIPTION - -=head2 PROGRAMMING STYLE - -There are two styles of programming with CGI.pm, an object-oriented -style and a function-oriented style. In the object-oriented style you -create one or more CGI objects and then use object methods to create -the various elements of the page. Each CGI object starts out with the -list of named parameters that were passed to your CGI script by the -server. You can modify the objects, save them to a file or database -and recreate them. Because each object corresponds to the "state" of -the CGI script, and because each object's parameter list is -independent of the others, this allows you to save the state of the -script and restore it later. - -For example, using the object oriented style, here is how you create -a simple "Hello World" HTML page: - - #!/usr/local/bin/perl -w - use CGI; # load CGI routines - $q = new CGI; # create new CGI object - print $q->header, # create the HTTP header - $q->start_html('hello world'), # start the HTML - $q->h1('hello world'), # level 1 header - $q->end_html; # end the HTML - -In the function-oriented style, there is one default CGI object that -you rarely deal with directly. Instead you just call functions to -retrieve CGI parameters, create HTML tags, manage cookies, and so -on. This provides you with a cleaner programming interface, but -limits you to using one CGI object at a time. The following example -prints the same page, but uses the function-oriented interface. -The main differences are that we now need to import a set of functions -into our name space (usually the "standard" functions), and we don't -need to create the CGI object. - - #!/usr/local/bin/perl - use CGI qw/:standard/; # load standard CGI routines - print header, # create the HTTP header - start_html('hello world'), # start the HTML - h1('hello world'), # level 1 header - end_html; # end the HTML - -The examples in this document mainly use the object-oriented style. -See HOW TO IMPORT FUNCTIONS for important information on -function-oriented programming in CGI.pm - -=head2 CALLING CGI.PM ROUTINES - -Most CGI.pm routines accept several arguments, sometimes as many as 20 -optional ones! To simplify this interface, all routines use a named -argument calling style that looks like this: - - print $q->header(-type=>'image/gif',-expires=>'+3d'); - -Each argument name is preceded by a dash. Neither case nor order -matters in the argument list. -type, -Type, and -TYPE are all -acceptable. In fact, only the first argument needs to begin with a -dash. If a dash is present in the first argument, CGI.pm assumes -dashes for the subsequent ones. - -Several routines are commonly called with just one argument. In the -case of these routines you can provide the single argument without an -argument name. header() happens to be one of these routines. In this -case, the single argument is the document type. - - print $q->header('text/html'); - -Other such routines are documented below. - -Sometimes named arguments expect a scalar, sometimes a reference to an -array, and sometimes a reference to a hash. Often, you can pass any -type of argument and the routine will do whatever is most appropriate. -For example, the param() routine is used to set a CGI parameter to a -single or a multi-valued value. The two cases are shown below: - - $q->param(-name=>'veggie',-value=>'tomato'); - $q->param(-name=>'veggie',-value=>['tomato','tomahto','potato','potahto']); - -A large number of routines in CGI.pm actually aren't specifically -defined in the module, but are generated automatically as needed. -These are the "HTML shortcuts," routines that generate HTML tags for -use in dynamically-generated pages. HTML tags have both attributes -(the attribute="value" pairs within the tag itself) and contents (the -part between the opening and closing pairs.) To distinguish between -attributes and contents, CGI.pm uses the convention of passing HTML -attributes as a hash reference as the first argument, and the -contents, if any, as any subsequent arguments. It works out like -this: - - Code Generated HTML - ---- -------------- - h1()

- h1('some','contents');

some contents

- h1({-align=>left});

- h1({-align=>left},'contents');

contents

- -HTML tags are described in more detail later. - -Many newcomers to CGI.pm are puzzled by the difference between the -calling conventions for the HTML shortcuts, which require curly braces -around the HTML tag attributes, and the calling conventions for other -routines, which manage to generate attributes without the curly -brackets. Don't be confused. As a convenience the curly braces are -optional in all but the HTML shortcuts. If you like, you can use -curly braces when calling any routine that takes named arguments. For -example: - - print $q->header( {-type=>'image/gif',-expires=>'+3d'} ); - -If you use the B<-w> switch, you will be warned that some CGI.pm argument -names conflict with built-in Perl functions. The most frequent of -these is the -values argument, used to create multi-valued menus, -radio button clusters and the like. To get around this warning, you -have several choices: - -=over 4 - -=item 1. - -Use another name for the argument, if one is available. -For example, -value is an alias for -values. - -=item 2. - -Change the capitalization, e.g. -Values - -=item 3. - -Put quotes around the argument name, e.g. '-values' - -=back - -Many routines will do something useful with a named argument that it -doesn't recognize. For example, you can produce non-standard HTTP -header fields by providing them as named arguments: - - print $q->header(-type => 'text/html', - -cost => 'Three smackers', - -annoyance_level => 'high', - -complaints_to => 'bit bucket'); - -This will produce the following nonstandard HTTP header: - - HTTP/1.0 200 OK - Cost: Three smackers - Annoyance-level: high - Complaints-to: bit bucket - Content-type: text/html - -Notice the way that underscores are translated automatically into -hyphens. HTML-generating routines perform a different type of -translation. - -This feature allows you to keep up with the rapidly changing HTTP and -HTML "standards". - -=head2 CREATING A NEW QUERY OBJECT (OBJECT-ORIENTED STYLE): - - $query = new CGI; - -This will parse the input (from both POST and GET methods) and store -it into a perl5 object called $query. - -=head2 CREATING A NEW QUERY OBJECT FROM AN INPUT FILE - - $query = new CGI(INPUTFILE); - -If you provide a file handle to the new() method, it will read -parameters from the file (or STDIN, or whatever). The file can be in -any of the forms describing below under debugging (i.e. a series of -newline delimited TAG=VALUE pairs will work). Conveniently, this type -of file is created by the save() method (see below). Multiple records -can be saved and restored. - -Perl purists will be pleased to know that this syntax accepts -references to file handles, or even references to filehandle globs, -which is the "official" way to pass a filehandle: - - $query = new CGI(\*STDIN); - -You can also initialize the CGI object with a FileHandle or IO::File -object. - -If you are using the function-oriented interface and want to -initialize CGI state from a file handle, the way to do this is with -B. This will (re)initialize the -default CGI object from the indicated file handle. - - open (IN,"test.in") || die; - restore_parameters(IN); - close IN; - -You can also initialize the query object from an associative array -reference: - - $query = new CGI( {'dinosaur'=>'barney', - 'song'=>'I love you', - 'friends'=>[qw/Jessica George Nancy/]} - ); - -or from a properly formatted, URL-escaped query string: - - $query = new CGI('dinosaur=barney&color=purple'); - -or from a previously existing CGI object (currently this clones the -parameter list, but none of the other object-specific fields, such as -autoescaping): - - $old_query = new CGI; - $new_query = new CGI($old_query); - -To create an empty query, initialize it from an empty string or hash: - - $empty_query = new CGI(""); - - -or- - - $empty_query = new CGI({}); - -=head2 FETCHING A LIST OF KEYWORDS FROM THE QUERY: - - @keywords = $query->keywords - -If the script was invoked as the result of an search, the -parsed keywords can be obtained as an array using the keywords() method. - -=head2 FETCHING THE NAMES OF ALL THE PARAMETERS PASSED TO YOUR SCRIPT: - - @names = $query->param - -If the script was invoked with a parameter list -(e.g. "name1=value1&name2=value2&name3=value3"), the param() method -will return the parameter names as a list. If the script was invoked -as an script and contains a string without ampersands -(e.g. "value1+value2+value3") , there will be a single parameter named -"keywords" containing the "+"-delimited keywords. - -NOTE: As of version 1.5, the array of parameter names returned will -be in the same order as they were submitted by the browser. -Usually this order is the same as the order in which the -parameters are defined in the form (however, this isn't part -of the spec, and so isn't guaranteed). - -=head2 FETCHING THE VALUE OR VALUES OF A SINGLE NAMED PARAMETER: - - @values = $query->param('foo'); - - -or- - - $value = $query->param('foo'); - -Pass the param() method a single argument to fetch the value of the -named parameter. If the parameter is multivalued (e.g. from multiple -selections in a scrolling list), you can ask to receive an array. Otherwise -the method will return a single value. - -If a value is not given in the query string, as in the queries -"name1=&name2=" or "name1&name2", it will be returned as an empty -string. This feature is new in 2.63. - - -If the parameter does not exist at all, then param() will return undef -in a scalar context, and the empty list in a list context. - - -=head2 SETTING THE VALUE(S) OF A NAMED PARAMETER: - - $query->param('foo','an','array','of','values'); - -This sets the value for the named parameter 'foo' to an array of -values. This is one way to change the value of a field AFTER -the script has been invoked once before. (Another way is with -the -override parameter accepted by all methods that generate -form elements.) - -param() also recognizes a named parameter style of calling described -in more detail later: - - $query->param(-name=>'foo',-values=>['an','array','of','values']); - - -or- - - $query->param(-name=>'foo',-value=>'the value'); - -=head2 APPENDING ADDITIONAL VALUES TO A NAMED PARAMETER: - - $query->append(-name=>'foo',-values=>['yet','more','values']); - -This adds a value or list of values to the named parameter. The -values are appended to the end of the parameter if it already exists. -Otherwise the parameter is created. Note that this method only -recognizes the named argument calling syntax. - -=head2 IMPORTING ALL PARAMETERS INTO A NAMESPACE: - - $query->import_names('R'); - -This creates a series of variables in the 'R' namespace. For example, -$R::foo, @R:foo. For keyword lists, a variable @R::keywords will appear. -If no namespace is given, this method will assume 'Q'. -WARNING: don't import anything into 'main'; this is a major security -risk!!!! - -NOTE 1: Variable names are transformed as necessary into legal Perl -variable names. All non-legal characters are transformed into -underscores. If you need to keep the original names, you should use -the param() method instead to access CGI variables by name. - -NOTE 2: In older versions, this method was called B. As of version 2.20, -this name has been removed completely to avoid conflict with the built-in -Perl module B operator. - -=head2 DELETING A PARAMETER COMPLETELY: - - $query->delete('foo','bar','baz'); - -This completely clears a list of parameters. It sometimes useful for -resetting parameters that you don't want passed down between script -invocations. - -If you are using the function call interface, use "Delete()" instead -to avoid conflicts with Perl's built-in delete operator. - -=head2 DELETING ALL PARAMETERS: - - $query->delete_all(); - -This clears the CGI object completely. It might be useful to ensure -that all the defaults are taken when you create a fill-out form. - -Use Delete_all() instead if you are using the function call interface. - -=head2 DIRECT ACCESS TO THE PARAMETER LIST: - - $q->param_fetch('address')->[1] = '1313 Mockingbird Lane'; - unshift @{$q->param_fetch(-name=>'address')},'George Munster'; - -If you need access to the parameter list in a way that isn't covered -by the methods above, you can obtain a direct reference to it by -calling the B method with the name of the . This -will return an array reference to the named parameters, which you then -can manipulate in any way you like. - -You can also use a named argument style using the B<-name> argument. - -=head2 FETCHING THE PARAMETER LIST AS A HASH: - - $params = $q->Vars; - print $params->{'address'}; - @foo = split("\0",$params->{'foo'}); - %params = $q->Vars; - - use CGI ':cgi-lib'; - $params = Vars; - -Many people want to fetch the entire parameter list as a hash in which -the keys are the names of the CGI parameters, and the values are the -parameters' values. The Vars() method does this. Called in a scalar -context, it returns the parameter list as a tied hash reference. -Changing a key changes the value of the parameter in the underlying -CGI parameter list. Called in a list context, it returns the -parameter list as an ordinary hash. This allows you to read the -contents of the parameter list, but not to change it. - -When using this, the thing you must watch out for are multivalued CGI -parameters. Because a hash cannot distinguish between scalar and -list context, multivalued parameters will be returned as a packed -string, separated by the "\0" (null) character. You must split this -packed string in order to get at the individual values. This is the -convention introduced long ago by Steve Brenner in his cgi-lib.pl -module for Perl version 4. - -If you wish to use Vars() as a function, import the I<:cgi-lib> set of -function calls (also see the section on CGI-LIB compatibility). - -=head2 SAVING THE STATE OF THE SCRIPT TO A FILE: - - $query->save(FILEHANDLE) - -This will write the current state of the form to the provided -filehandle. You can read it back in by providing a filehandle -to the new() method. Note that the filehandle can be a file, a pipe, -or whatever! - -The format of the saved file is: - - NAME1=VALUE1 - NAME1=VALUE1' - NAME2=VALUE2 - NAME3=VALUE3 - = - -Both name and value are URL escaped. Multi-valued CGI parameters are -represented as repeated names. A session record is delimited by a -single = symbol. You can write out multiple records and read them -back in with several calls to B. You can do this across several -sessions by opening the file in append mode, allowing you to create -primitive guest books, or to keep a history of users' queries. Here's -a short example of creating multiple session records: - - use CGI; - - open (OUT,">>test.out") || die; - $records = 5; - foreach (0..$records) { - my $q = new CGI; - $q->param(-name=>'counter',-value=>$_); - $q->save(OUT); - } - close OUT; - - # reopen for reading - open (IN,"test.out") || die; - while (!eof(IN)) { - my $q = new CGI(IN); - print $q->param('counter'),"\n"; - } - -The file format used for save/restore is identical to that used by the -Whitehead Genome Center's data exchange format "Boulderio", and can be -manipulated and even databased using Boulderio utilities. See - - http://stein.cshl.org/boulder/ - -for further details. - -If you wish to use this method from the function-oriented (non-OO) -interface, the exported name for this method is B. - -=head2 RETRIEVING CGI ERRORS - -Errors can occur while processing user input, particularly when -processing uploaded files. When these errors occur, CGI will stop -processing and return an empty parameter list. You can test for -the existence and nature of errors using the I function. -The error messages are formatted as HTTP status codes. You can either -incorporate the error text into an HTML page, or use it as the value -of the HTTP status: - - my $error = $q->cgi_error; - if ($error) { - print $q->header(-status=>$error), - $q->start_html('Problems'), - $q->h2('Request not processed'), - $q->strong($error); - exit 0; - } - -When using the function-oriented interface (see the next section), -errors may only occur the first time you call I. Be ready -for this! - -=head2 USING THE FUNCTION-ORIENTED INTERFACE - -To use the function-oriented interface, you must specify which CGI.pm -routines or sets of routines to import into your script's namespace. -There is a small overhead associated with this importation, but it -isn't much. - - use CGI ; - -The listed methods will be imported into the current package; you can -call them directly without creating a CGI object first. This example -shows how to import the B and B -methods, and then use them directly: - - use CGI 'param','header'; - print header('text/plain'); - $zipcode = param('zipcode'); - -More frequently, you'll import common sets of functions by referring -to the groups by name. All function sets are preceded with a ":" -character as in ":html3" (for tags defined in the HTML 3 standard). - -Here is a list of the function sets you can import: - -=over 4 - -=item B<:cgi> - -Import all CGI-handling methods, such as B, B -and the like. - -=item B<:form> - -Import all fill-out form generating methods, such as B. - -=item B<:html2> - -Import all methods that generate HTML 2.0 standard elements. - -=item B<:html3> - -Import all methods that generate HTML 3.0 elements (such as -, and ). - -=item B<:html4> - -Import all methods that generate HTML 4 elements (such as -, and ). - -=item B<:netscape> - -Import all methods that generate Netscape-specific HTML extensions. - -=item B<:html> - -Import all HTML-generating shortcuts (i.e. 'html2' + 'html3' + -'netscape')... - -=item B<:standard> - -Import "standard" features, 'html2', 'html3', 'html4', 'form' and 'cgi'. - -=item B<:all> - -Import all the available methods. For the full list, see the CGI.pm -code, where the variable %EXPORT_TAGS is defined. - -=back - -If you import a function name that is not part of CGI.pm, the module -will treat it as a new HTML tag and generate the appropriate -subroutine. You can then use it like any other HTML tag. This is to -provide for the rapidly-evolving HTML "standard." For example, say -Microsoft comes out with a new tag called (which causes the -user's desktop to be flooded with a rotating gradient fill until his -machine reboots). You don't need to wait for a new version of CGI.pm -to start using it immediately: - - use CGI qw/:standard :html3 gradient/; - print gradient({-start=>'red',-end=>'blue'}); - -Note that in the interests of execution speed CGI.pm does B use -the standard L syntax for specifying load symbols. This may -change in the future. - -If you import any of the state-maintaining CGI or form-generating -methods, a default CGI object will be created and initialized -automatically the first time you use any of the methods that require -one to be present. This includes B, B, -B and the like. (If you need direct access to the CGI -object, you can find it in the global variable B<$CGI::Q>). By -importing CGI.pm methods, you can create visually elegant scripts: - - use CGI qw/:standard/; - print - header, - start_html('Simple Script'), - h1('Simple Script'), - start_form, - "What's your name? ",textfield('name'),p, - "What's the combination?", - checkbox_group(-name=>'words', - -values=>['eenie','meenie','minie','moe'], - -defaults=>['eenie','moe']),p, - "What's your favorite color?", - popup_menu(-name=>'color', - -values=>['red','green','blue','chartreuse']),p, - submit, - end_form, - hr,"\n"; - - if (param) { - print - "Your name is ",em(param('name')),p, - "The keywords are: ",em(join(", ",param('words'))),p, - "Your favorite color is ",em(param('color')),".\n"; - } - print end_html; - -=head2 PRAGMAS - -In addition to the function sets, there are a number of pragmas that -you can import. Pragmas, which are always preceded by a hyphen, -change the way that CGI.pm functions in various ways. Pragmas, -function sets, and individual functions can all be imported in the -same use() line. For example, the following use statement imports the -standard set of functions and enables debugging mode (pragma --debug): - - use CGI qw/:standard -debug/; - -The current list of pragmas is as follows: - -=over 4 - -=item -any - -When you I, then any method that the query object -doesn't recognize will be interpreted as a new HTML tag. This allows -you to support the next I Netscape or Microsoft HTML -extension. This lets you go wild with new and unsupported tags: - - use CGI qw(-any); - $q=new CGI; - print $q->gradient({speed=>'fast',start=>'red',end=>'blue'}); - -Since using any causes any mistyped method name -to be interpreted as an HTML tag, use it with care or not at -all. - -=item -compile - -This causes the indicated autoloaded methods to be compiled up front, -rather than deferred to later. This is useful for scripts that run -for an extended period of time under FastCGI or mod_perl, and for -those destined to be crunched by Malcom Beattie's Perl compiler. Use -it in conjunction with the methods or method families you plan to use. - - use CGI qw(-compile :standard :html3); - -or even - - use CGI qw(-compile :all); - -Note that using the -compile pragma in this way will always have -the effect of importing the compiled functions into the current -namespace. If you want to compile without importing use the -compile() method instead: - - use CGI(); - CGI->compile(); - -This is particularly useful in a mod_perl environment, in which you -might want to precompile all CGI routines in a startup script, and -then import the functions individually in each mod_perl script. - -=item -nosticky - -This makes CGI.pm not generating the hidden fields .submit -and .cgifields. It is very useful if you don't want to -have the hidden fields appear in the querystring in a GET method. -For example, a search script generated this way will have -a very nice url with search parameters for bookmarking. - -=item -no_undef_params - -This keeps CGI.pm from including undef params in the parameter list. - -=item -no_xhtml - -By default, CGI.pm versions 2.69 and higher emit XHTML -(http://www.w3.org/TR/xhtml1/). The -no_xhtml pragma disables this -feature. Thanks to Michalis Kabrianis for this -feature. - -If start_html()'s -dtd parameter specifies an HTML 2.0 or 3.2 DTD, -XHTML will automatically be disabled without needing to use this -pragma. - -=item -nph - -This makes CGI.pm produce a header appropriate for an NPH (no -parsed header) script. You may need to do other things as well -to tell the server that the script is NPH. See the discussion -of NPH scripts below. - -=item -newstyle_urls - -Separate the name=value pairs in CGI parameter query strings with -semicolons rather than ampersands. For example: - - ?name=fred;age=24;favorite_color=3 - -Semicolon-delimited query strings are always accepted, but will not be -emitted by self_url() and query_string() unless the -newstyle_urls -pragma is specified. - -This became the default in version 2.64. - -=item -oldstyle_urls - -Separate the name=value pairs in CGI parameter query strings with -ampersands rather than semicolons. This is no longer the default. - -=item -autoload - -This overrides the autoloader so that any function in your program -that is not recognized is referred to CGI.pm for possible evaluation. -This allows you to use all the CGI.pm functions without adding them to -your symbol table, which is of concern for mod_perl users who are -worried about memory consumption. I when -I<-autoload> is in effect, you cannot use "poetry mode" -(functions without the parenthesis). Use I rather -than I
, or add something like I -to the top of your script. - -=item -no_debug - -This turns off the command-line processing features. If you want to -run a CGI.pm script from the command line to produce HTML, and you -don't want it to read CGI parameters from the command line or STDIN, -then use this pragma: - - use CGI qw(-no_debug :standard); - -=item -debug - -This turns on full debugging. In addition to reading CGI arguments -from the command-line processing, CGI.pm will pause and try to read -arguments from STDIN, producing the message "(offline mode: enter -name=value pairs on standard input)" features. - -See the section on debugging for more details. - -=item -private_tempfiles - -CGI.pm can process uploaded file. Ordinarily it spools the uploaded -file to a temporary directory, then deletes the file when done. -However, this opens the risk of eavesdropping as described in the file -upload section. Another CGI script author could peek at this data -during the upload, even if it is confidential information. On Unix -systems, the -private_tempfiles pragma will cause the temporary file -to be unlinked as soon as it is opened and before any data is written -into it, reducing, but not eliminating the risk of eavesdropping -(there is still a potential race condition). To make life harder for -the attacker, the program chooses tempfile names by calculating a 32 -bit checksum of the incoming HTTP headers. - -To ensure that the temporary file cannot be read by other CGI scripts, -use suEXEC or a CGI wrapper program to run your script. The temporary -file is created with mode 0600 (neither world nor group readable). - -The temporary directory is selected using the following algorithm: - - 1. if the current user (e.g. "nobody") has a directory named - "tmp" in its home directory, use that (Unix systems only). - - 2. if the environment variable TMPDIR exists, use the location - indicated. - - 3. Otherwise try the locations /usr/tmp, /var/tmp, C:\temp, - /tmp, /temp, ::Temporary Items, and \WWW_ROOT. - -Each of these locations is checked that it is a directory and is -writable. If not, the algorithm tries the next choice. - -=back - -=head2 SPECIAL FORMS FOR IMPORTING HTML-TAG FUNCTIONS - -Many of the methods generate HTML tags. As described below, tag -functions automatically generate both the opening and closing tags. -For example: - - print h1('Level 1 Header'); - -produces - -

Level 1 Header

- -There will be some times when you want to produce the start and end -tags yourself. In this case, you can use the form start_I -and end_I, as in: - - print start_h1,'Level 1 Header',end_h1; - -With a few exceptions (described below), start_I and -end_I functions are not generated automatically when you -I. However, you can specify the tags you want to generate -I functions for by putting an asterisk in front of their -name, or, alternatively, requesting either "start_I" or -"end_I" in the import list. - -Example: - - use CGI qw/:standard *table start_ul/; - -In this example, the following functions are generated in addition to -the standard ones: - -=over 4 - -=item 1. start_table() (generates a
tag) - -=item 2. end_table() (generates a
tag) - -=item 3. start_ul() (generates a
    tag) - -=item 4. end_ul() (generates a
tag) - -=back - -=head1 GENERATING DYNAMIC DOCUMENTS - -Most of CGI.pm's functions deal with creating documents on the fly. -Generally you will produce the HTTP header first, followed by the -document itself. CGI.pm provides functions for generating HTTP -headers of various types as well as for generating HTML. For creating -GIF images, see the GD.pm module. - -Each of these functions produces a fragment of HTML or HTTP which you -can print out directly so that it displays in the browser window, -append to a string, or save to a file for later use. - -=head2 CREATING A STANDARD HTTP HEADER: - -Normally the first thing you will do in any CGI script is print out an -HTTP header. This tells the browser what type of document to expect, -and gives other optional information, such as the language, expiration -date, and whether to cache the document. The header can also be -manipulated for special purposes, such as server push and pay per view -pages. - - print $query->header; - - -or- - - print $query->header('image/gif'); - - -or- - - print $query->header('text/html','204 No response'); - - -or- - - print $query->header(-type=>'image/gif', - -nph=>1, - -status=>'402 Payment required', - -expires=>'+3d', - -cookie=>$cookie, - -charset=>'utf-7', - -attachment=>'foo.gif', - -Cost=>'$2.00'); - -header() returns the Content-type: header. You can provide your own -MIME type if you choose, otherwise it defaults to text/html. An -optional second parameter specifies the status code and a human-readable -message. For example, you can specify 204, "No response" to create a -script that tells the browser to do nothing at all. - -The last example shows the named argument style for passing arguments -to the CGI methods using named parameters. Recognized parameters are -B<-type>, B<-status>, B<-expires>, and B<-cookie>. Any other named -parameters will be stripped of their initial hyphens and turned into -header fields, allowing you to specify any HTTP header you desire. -Internal underscores will be turned into hyphens: - - print $query->header(-Content_length=>3002); - -Most browsers will not cache the output from CGI scripts. Every time -the browser reloads the page, the script is invoked anew. You can -change this behavior with the B<-expires> parameter. When you specify -an absolute or relative expiration interval with this parameter, some -browsers and proxy servers will cache the script's output until the -indicated expiration date. The following forms are all valid for the --expires field: - - +30s 30 seconds from now - +10m ten minutes from now - +1h one hour from now - -1d yesterday (i.e. "ASAP!") - now immediately - +3M in three months - +10y in ten years time - Thursday, 25-Apr-1999 00:40:33 GMT at the indicated time & date - -The B<-cookie> parameter generates a header that tells the browser to provide -a "magic cookie" during all subsequent transactions with your script. -Netscape cookies have a special format that includes interesting attributes -such as expiration time. Use the cookie() method to create and retrieve -session cookies. - -The B<-nph> parameter, if set to a true value, will issue the correct -headers to work with a NPH (no-parse-header) script. This is important -to use with certain servers that expect all their scripts to be NPH. - -The B<-charset> parameter can be used to control the character set -sent to the browser. If not provided, defaults to ISO-8859-1. As a -side effect, this sets the charset() method as well. - -The B<-attachment> parameter can be used to turn the page into an -attachment. Instead of displaying the page, some browsers will prompt -the user to save it to disk. The value of the argument is the -suggested name for the saved file. In order for this to work, you may -have to set the B<-type> to "application/octet-stream". - -The B<-p3p> parameter will add a P3P tag to the outgoing header. The -parameter can be an arrayref or a space-delimited string of P3P tags. -For example: - - print header(-p3p=>[qw(CAO DSP LAW CURa)]); - print header(-p3p=>'CAO DSP LAW CURa'); - -In either case, the outgoing header will be formatted as: - - P3P: policyref="/w3c/p3p.xml" cp="CAO DSP LAW CURa" - -=head2 GENERATING A REDIRECTION HEADER - - print $query->redirect('http://somewhere.else/in/movie/land'); - -Sometimes you don't want to produce a document yourself, but simply -redirect the browser elsewhere, perhaps choosing a URL based on the -time of day or the identity of the user. - -The redirect() function redirects the browser to a different URL. If -you use redirection like this, you should B print out a header as -well. - -You should always use full URLs (including the http: or ftp: part) in -redirection requests. Relative URLs will not work correctly. - -You can also use named arguments: - - print $query->redirect(-uri=>'http://somewhere.else/in/movie/land', - -nph=>1, - -status=>301); - -The B<-nph> parameter, if set to a true value, will issue the correct -headers to work with a NPH (no-parse-header) script. This is important -to use with certain servers, such as Microsoft IIS, which -expect all their scripts to be NPH. - -The B<-status> parameter will set the status of the redirect. HTTP -defines three different possible redirection status codes: - - 301 Moved Permanently - 302 Found - 303 See Other - -The default if not specified is 302, which means "moved temporarily." -You may change the status to another status code if you wish. Be -advised that changing the status to anything other than 301, 302 or -303 will probably break redirection. - -=head2 CREATING THE HTML DOCUMENT HEADER - - print $query->start_html(-title=>'Secrets of the Pyramids', - -author=>'fred@capricorn.org', - -base=>'true', - -target=>'_blank', - -meta=>{'keywords'=>'pharaoh secret mummy', - 'copyright'=>'copyright 1996 King Tut'}, - -style=>{'src'=>'/styles/style1.css'}, - -BGCOLOR=>'blue'); - -After creating the HTTP header, most CGI scripts will start writing -out an HTML document. The start_html() routine creates the top of the -page, along with a lot of optional information that controls the -page's appearance and behavior. - -This method returns a canned HTML header and the opening tag. -All parameters are optional. In the named parameter form, recognized -parameters are -title, -author, -base, -xbase, -dtd, -lang and -target -(see below for the explanation). Any additional parameters you -provide, such as the Netscape unofficial BGCOLOR attribute, are added -to the tag. Additional parameters must be proceeded by a -hyphen. - -The argument B<-xbase> allows you to provide an HREF for the tag -different from the current location, as in - - -xbase=>"http://home.mcom.com/" - -All relative links will be interpreted relative to this tag. - -The argument B<-target> allows you to provide a default target frame -for all the links and fill-out forms on the page. B -See the Netscape documentation on frames for details of how to -manipulate this. - - -target=>"answer_window" - -All relative links will be interpreted relative to this tag. -You add arbitrary meta information to the header with the B<-meta> -argument. This argument expects a reference to an associative array -containing name/value pairs of meta information. These will be turned -into a series of header tags that look something like this: - - - - -To create an HTTP-EQUIV type of tag, use B<-head>, described -below. - -The B<-style> argument is used to incorporate cascading stylesheets -into your code. See the section on CASCADING STYLESHEETS for more -information. - -The B<-lang> argument is used to incorporate a language attribute into -the tag. For example: - - print $q->start_html(-lang=>'fr-CA'); - -The default if not specified is "en-US" for US English, unless the --dtd parameter specifies an HTML 2.0 or 3.2 DTD, in which case the -lang attribute is left off. You can force the lang attribute to left -off in other cases by passing an empty string (-lang=>''). - -The B<-encoding> argument can be used to specify the character set for -XHTML. It defaults to iso-8859-1 if not specified. - -You can place other arbitrary HTML elements to the section with the -B<-head> tag. For example, to place the rarely-used element in the -head section, use this: - - print start_html(-head=>Link({-rel=>'next', - -href=>'http://www.capricorn.com/s2.html'})); - -To incorporate multiple HTML elements into the section, just pass an -array reference: - - print start_html(-head=>[ - Link({-rel=>'next', - -href=>'http://www.capricorn.com/s2.html'}), - Link({-rel=>'previous', - -href=>'http://www.capricorn.com/s1.html'}) - ] - ); - -And here's how to create an HTTP-EQUIV tag: - - print start_html(-head=>meta({-http_equiv => 'Content-Type', - -content => 'text/html'})) - - -JAVASCRIPTING: The B<-script>, B<-noScript>, B<-onLoad>, -B<-onMouseOver>, B<-onMouseOut> and B<-onUnload> parameters are used -to add Netscape JavaScript calls to your pages. B<-script> should -point to a block of text containing JavaScript function definitions. -This block will be placed within a \n"; - warningsToBrowser(1); # re-enable warnings - -Note: In this respect warningsToBrowser() differs fundamentally from -fatalsToBrowser(), which you should never call yourself! - -=head1 OVERRIDING THE NAME OF THE PROGRAM - -CGI::Carp includes the name of the program that generated the error or -warning in the messages written to the log and the browser window. -Sometimes, Perl can get confused about what the actual name of the -executed program was. In these cases, you can override the program -name that CGI::Carp will use for all messages. - -The quick way to do that is to tell CGI::Carp the name of the program -in its use statement. You can do that by adding -"name=cgi_carp_log_name" to your "use" statement. For example: - - use CGI::Carp qw(name=cgi_carp_log_name); - -. If you want to change the program name partway through the program, -you can use the C function instead. It is not -exported by default, you must import it explicitly by saying - - use CGI::Carp qw(set_progname); - -Once you've done that, you can change the logged name of the program -at any time by calling - - set_progname(new_program_name); - -You can set the program back to the default by calling - - set_progname(undef); - -Note that this override doesn't happen until after the program has -compiled, so any compile-time errors will still show up with the -non-overridden program name - -=head1 CHANGE LOG - -1.05 carpout() added and minor corrections by Marc Hedlund - on 11/26/95. - -1.06 fatalsToBrowser() no longer aborts for fatal errors within - eval() statements. - -1.08 set_message() added and carpout() expanded to allow for FileHandle - objects. - -1.09 set_message() now allows users to pass a code REFERENCE for - really custom error messages. croak and carp are now - exported by default. Thanks to Gunther Birznieks for the - patches. - -1.10 Patch from Chris Dean (ctdean@cogit.com) to allow - module to run correctly under mod_perl. - -1.11 Changed order of > and < escapes. - -1.12 Changed die() on line 217 to CORE::die to avoid B<-w> warning. - -1.13 Added cluck() to make the module orthogonal with Carp. - More mod_perl related fixes. - -1.20 Patch from Ilmari Karonen (perl@itz.pp.sci.fi): Added - warningsToBrowser(). Replaced tags with
 in
-     fatalsToBrowser() output.
-
-1.23 ineval() now checks both $^S and inspects the message for the "eval" pattern
-     (hack alert!) in order to accomodate various combinations of Perl and
-     mod_perl.
-
-1.24 Patch from Scott Gifford (sgifford@suspectclass.com): Add support
-     for overriding program name.
-
-1.26 Replaced CORE::GLOBAL::die with the evil $SIG{__DIE__} because the
-     former isn't working in some people's hands.  There is no such thing
-     as reliable exception handling in Perl.
-
-1.27 Replaced tell STDOUT with bytes=tell STDOUT.
-
-=head1 AUTHORS
-
-Copyright 1995-2002, Lincoln D. Stein.  All rights reserved.  
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself.
-
-Address bug reports and comments to: lstein@cshl.org
-
-=head1 SEE ALSO
-
-Carp, CGI::Base, CGI::BasePlus, CGI::Request, CGI::MiniSvr, CGI::Form,
-CGI::Response
-    if (defined($CGI::Carp::PROGNAME)) 
-    {
-      $file = $CGI::Carp::PROGNAME;
-    }
-
-=cut
-
-require 5.000;
-use Exporter;
-#use Carp;
-BEGIN { 
-  require Carp; 
-  *CORE::GLOBAL::die = \&CGI::Carp::die;
-}
-
-use File::Spec;
-
-@ISA = qw(Exporter);
-@EXPORT = qw(confess croak carp);
-@EXPORT_OK = qw(carpout fatalsToBrowser warningsToBrowser wrap set_message set_progname cluck ^name= die);
-
-$main::SIG{__WARN__}=\&CGI::Carp::warn;
-
-$CGI::Carp::VERSION    = '1.28';
-$CGI::Carp::CUSTOM_MSG = undef;
-
-
-# fancy import routine detects and handles 'errorWrap' specially.
-sub import {
-    my $pkg = shift;
-    my(%routines);
-    my(@name);
-  
-    if (@name=grep(/^name=/,@_))
-      {
-        my($n) = (split(/=/,$name[0]))[1];
-        set_progname($n);
-        @_=grep(!/^name=/,@_);
-      }
-
-    grep($routines{$_}++,@_,@EXPORT);
-    $WRAP++ if $routines{'fatalsToBrowser'} || $routines{'wrap'};
-    $WARN++ if $routines{'warningsToBrowser'};
-    my($oldlevel) = $Exporter::ExportLevel;
-    $Exporter::ExportLevel = 1;
-    Exporter::import($pkg,keys %routines);
-    $Exporter::ExportLevel = $oldlevel;
-    $main::SIG{__DIE__} =\&CGI::Carp::die if $routines{'fatalsToBrowser'};
-#    $pkg->export('CORE::GLOBAL','die');
-}
-
-# These are the originals
-sub realwarn { CORE::warn(@_); }
-sub realdie { CORE::die(@_); }
-
-sub id {
-    my $level = shift;
-    my($pack,$file,$line,$sub) = caller($level);
-    my($dev,$dirs,$id) = File::Spec->splitpath($file);
-    return ($file,$line,$id);
-}
-
-sub stamp {
-    my $time = scalar(localtime);
-    my $frame = 0;
-    my ($id,$pack,$file,$dev,$dirs);
-    if (defined($CGI::Carp::PROGNAME)) {
-        $id = $CGI::Carp::PROGNAME;
-    } else {
-        do {
-  	  $id = $file;
-	  ($pack,$file) = caller($frame++);
-        } until !$file;
-    }
-    ($dev,$dirs,$id) = File::Spec->splitpath($id);
-    return "[$time] $id: ";
-}
-
-sub set_progname {
-    $CGI::Carp::PROGNAME = shift;
-    return $CGI::Carp::PROGNAME;
-}
-
-
-sub warn {
-    my $message = shift;
-    my($file,$line,$id) = id(1);
-    $message .= " at $file line $line.\n" unless $message=~/\n$/;
-    _warn($message) if $WARN;
-    my $stamp = stamp;
-    $message=~s/^/$stamp/gm;
-    realwarn $message;
-}
-
-sub _warn {
-    my $msg = shift;
-    if ($EMIT_WARNINGS) {
-	# We need to mangle the message a bit to make it a valid HTML
-	# comment.  This is done by substituting similar-looking ISO
-	# 8859-1 characters for <, > and -.  This is a hack.
-	$msg =~ tr/<>-/\253\273\255/;
-	chomp $msg;
-	print STDOUT "\n";
-    } else {
-	push @WARNINGS, $msg;
-    }
-}
-
-
-# The mod_perl package Apache::Registry loads CGI programs by calling
-# eval.  These evals don't count when looking at the stack backtrace.
-sub _longmess {
-    my $message = Carp::longmess();
-    $message =~ s,eval[^\n]+(ModPerl|Apache)/Registry\w*\.pm.*,,s
-        if exists $ENV{MOD_PERL};
-    return $message;
-}
-
-sub ineval {
-  (exists $ENV{MOD_PERL} ? 0 : $^S) || _longmess() =~ /eval [\{\']/m
-}
-
-sub die {
-  my ($arg,@rest) = @_;
-  realdie ($arg,@rest) if ineval();
-
-  if (!ref($arg)) {
-    $arg = join("", ($arg,@rest));
-    my($file,$line,$id) = id(1);
-    $arg .= " at $file line $line." unless $arg=~/\n$/;
-    &fatalsToBrowser($arg) if $WRAP;
-    if (($arg =~ /\n$/) || !exists($ENV{MOD_PERL})) {
-      my $stamp = stamp;
-      $arg=~s/^/$stamp/gm;
-    }
-    if ($arg !~ /\n$/) {
-      $arg .= "\n";
-    }
-  }
-  realdie $arg;
-}
-
-sub set_message {
-    $CGI::Carp::CUSTOM_MSG = shift;
-    return $CGI::Carp::CUSTOM_MSG;
-}
-
-sub confess { CGI::Carp::die Carp::longmess @_; }
-sub croak   { CGI::Carp::die Carp::shortmess @_; }
-sub carp    { CGI::Carp::warn Carp::shortmess @_; }
-sub cluck   { CGI::Carp::warn Carp::longmess @_; }
-
-# We have to be ready to accept a filehandle as a reference
-# or a string.
-sub carpout {
-    my($in) = @_;
-    my($no) = fileno(to_filehandle($in));
-    realdie("Invalid filehandle $in\n") unless defined $no;
-    
-    open(SAVEERR, ">&STDERR");
-    open(STDERR, ">&$no") or 
-	( print SAVEERR "Unable to redirect STDERR: $!\n" and exit(1) );
-}
-
-sub warningsToBrowser {
-    $EMIT_WARNINGS = @_ ? shift : 1;
-    _warn(shift @WARNINGS) while $EMIT_WARNINGS and @WARNINGS;
-}
-
-# headers
-sub fatalsToBrowser {
-  my($msg) = @_;
-  $msg=~s/&/&/g;
-  $msg=~s/>/>/g;
-  $msg=~s/$ENV{SERVER_ADMIN})] :
-      "this site's webmaster";
-  my ($outer_message) = <Software error:
-
$msg
-

-$outer_message -

-END - ; - - if ($mod_perl) { - require mod_perl; - if ($mod_perl::VERSION >= 1.99) { - $mod_perl = 2; - require Apache::RequestRec; - require Apache::RequestIO; - require Apache::RequestUtil; - require APR::Pool; - require ModPerl::Util; - require Apache::Response; - } - my $r = Apache->request; - # If bytes have already been sent, then - # we print the message out directly. - # Otherwise we make a custom error - # handler to produce the doc for us. - if ($r->bytes_sent) { - $r->print($mess); - $mod_perl == 2 ? ModPerl::Util::exit(0) : $r->exit; - } else { - # MSIE won't display a custom 500 response unless it is >512 bytes! - if ($ENV{HTTP_USER_AGENT} =~ /MSIE/) { - $mess = "\n$mess"; - } - $r->custom_response(500,$mess); - } - } else { - my $bytes_written = eval{tell STDOUT}; - if (defined $bytes_written && $bytes_written > 0) { - print STDOUT $mess; - } - else { - print STDOUT "Content-type: text/html\n\n"; - print STDOUT $mess; - } - } - - warningsToBrowser(1); # emit warnings before dying -} - -# Cut and paste from CGI.pm so that we don't have the overhead of -# always loading the entire CGI module. -sub to_filehandle { - my $thingy = shift; - return undef unless $thingy; - return $thingy if UNIVERSAL::isa($thingy,'GLOB'); - return $thingy if UNIVERSAL::isa($thingy,'FileHandle'); - if (!ref($thingy)) { - my $caller = 1; - while (my $package = caller($caller++)) { - my($tmp) = $thingy=~/[\':]/ ? $thingy : "$package\:\:$thingy"; - return $tmp if defined(fileno($tmp)); - } - } - return undef; -} - -1; diff --git a/lib/CGI/Cookie.pm b/lib/CGI/Cookie.pm deleted file mode 100644 index 27a93c5..0000000 --- a/lib/CGI/Cookie.pm +++ /dev/null @@ -1,478 +0,0 @@ -package CGI::Cookie; - -# See the bottom of this file for the POD documentation. Search for the -# string '=head'. - -# You can run this file through either pod2man or pod2html to produce pretty -# documentation in manual or html file format (these utilities are part of the -# Perl 5 distribution). - -# Copyright 1995-1999, Lincoln D. Stein. All rights reserved. -# It may be used and modified freely, but I do request that this copyright -# notice remain attached to the file. You may modify this module as you -# wish, but if you redistribute a modified version, please attach a note -# listing the modifications you have made. - -$CGI::Cookie::VERSION='1.24'; - -use CGI::Util qw(rearrange unescape escape); -use overload '""' => \&as_string, - 'cmp' => \&compare, - 'fallback'=>1; - -# Turn on special checking for Doug MacEachern's modperl -my $MOD_PERL = 0; -if (exists $ENV{MOD_PERL}) { - eval "require mod_perl"; - if (defined $mod_perl::VERSION) { - if ($mod_perl::VERSION >= 1.99) { - $MOD_PERL = 2; - require Apache::RequestUtil; - } else { - $MOD_PERL = 1; - require Apache; - } - } -} - -# fetch a list of cookies from the environment and -# return as a hash. the cookies are parsed as normal -# escaped URL data. -sub fetch { - my $class = shift; - my $raw_cookie = get_raw_cookie(@_) or return; - return $class->parse($raw_cookie); -} - -# Fetch a list of cookies from the environment or the incoming headers and -# return as a hash. The cookie values are not unescaped or altered in any way. - sub raw_fetch { - my $class = shift; - my $raw_cookie = get_raw_cookie(@_) or return; - my %results; - my($key,$value); - - my(@pairs) = split("; ?",$raw_cookie); - foreach (@pairs) { - s/\s*(.*?)\s*/$1/; - if (/^([^=]+)=(.*)/) { - $key = $1; - $value = $2; - } - else { - $key = $_; - $value = ''; - } - $results{$key} = $value; - } - return \%results unless wantarray; - return %results; -} - -sub get_raw_cookie { - my $r = shift; - $r ||= eval { Apache->request() } if $MOD_PERL; - if ($r) { - $raw_cookie = $r->headers_in->{'Cookie'}; - } else { - if ($MOD_PERL && !exists $ENV{REQUEST_METHOD}) { - die "Run $r->subprocess_env; before calling fetch()"; - } - $raw_cookie = $ENV{HTTP_COOKIE} || $ENV{COOKIE}; - } -} - - -sub parse { - my ($self,$raw_cookie) = @_; - my %results; - - my(@pairs) = split("; ?",$raw_cookie); - foreach (@pairs) { - s/\s*(.*?)\s*/$1/; - my($key,$value) = split("=",$_,2); - - # Some foreign cookies are not in name=value format, so ignore - # them. - next if !defined($value); - my @values = (); - if ($value ne '') { - @values = map unescape($_),split(/[&;]/,$value.'&dmy'); - pop @values; - } - $key = unescape($key); - # A bug in Netscape can cause several cookies with same name to - # appear. The FIRST one in HTTP_COOKIE is the most recent version. - $results{$key} ||= $self->new(-name=>$key,-value=>\@values); - } - return \%results unless wantarray; - return %results; -} - -sub new { - my $class = shift; - $class = ref($class) if ref($class); - my($name,$value,$path,$domain,$secure,$expires) = - rearrange([NAME,[VALUE,VALUES],PATH,DOMAIN,SECURE,EXPIRES],@_); - - # Pull out our parameters. - my @values; - if (ref($value)) { - if (ref($value) eq 'ARRAY') { - @values = @$value; - } elsif (ref($value) eq 'HASH') { - @values = %$value; - } - } else { - @values = ($value); - } - - bless my $self = { - 'name'=>$name, - 'value'=>[@values], - },$class; - - # IE requires the path and domain to be present for some reason. - $path ||= "/"; - # however, this breaks networks which use host tables without fully qualified - # names, so we comment it out. - # $domain = CGI::virtual_host() unless defined $domain; - - $self->path($path) if defined $path; - $self->domain($domain) if defined $domain; - $self->secure($secure) if defined $secure; - $self->expires($expires) if defined $expires; -# $self->max_age($expires) if defined $expires; - return $self; -} - -sub as_string { - my $self = shift; - return "" unless $self->name; - - my(@constant_values,$domain,$path,$expires,$max_age,$secure); - - push(@constant_values,"domain=$domain") if $domain = $self->domain; - push(@constant_values,"path=$path") if $path = $self->path; - push(@constant_values,"expires=$expires") if $expires = $self->expires; - push(@constant_values,"max-age=$max_age") if $max_age = $self->max_age; - push(@constant_values,"secure") if $secure = $self->secure; - - my($key) = escape($self->name); - my($cookie) = join("=",$key,join("&",map escape($_),$self->value)); - return join("; ",$cookie,@constant_values); -} - -sub compare { - my $self = shift; - my $value = shift; - return "$self" cmp $value; -} - -# accessors -sub name { - my $self = shift; - my $name = shift; - $self->{'name'} = $name if defined $name; - return $self->{'name'}; -} - -sub value { - my $self = shift; - my $value = shift; - if (defined $value) { - my @values; - if (ref($value)) { - if (ref($value) eq 'ARRAY') { - @values = @$value; - } elsif (ref($value) eq 'HASH') { - @values = %$value; - } - } else { - @values = ($value); - } - $self->{'value'} = [@values]; - } - return wantarray ? @{$self->{'value'}} : $self->{'value'}->[0] -} - -sub domain { - my $self = shift; - my $domain = shift; - $self->{'domain'} = $domain if defined $domain; - return $self->{'domain'}; -} - -sub secure { - my $self = shift; - my $secure = shift; - $self->{'secure'} = $secure if defined $secure; - return $self->{'secure'}; -} - -sub expires { - my $self = shift; - my $expires = shift; - $self->{'expires'} = CGI::Util::expires($expires,'cookie') if defined $expires; - return $self->{'expires'}; -} - -sub max_age { - my $self = shift; - my $expires = shift; - $self->{'max-age'} = CGI::Util::expire_calc($expires)-time() if defined $expires; - return $self->{'max-age'}; -} - -sub path { - my $self = shift; - my $path = shift; - $self->{'path'} = $path if defined $path; - return $self->{'path'}; -} - -1; - -=head1 NAME - -CGI::Cookie - Interface to Netscape Cookies - -=head1 SYNOPSIS - - use CGI qw/:standard/; - use CGI::Cookie; - - # Create new cookies and send them - $cookie1 = new CGI::Cookie(-name=>'ID',-value=>123456); - $cookie2 = new CGI::Cookie(-name=>'preferences', - -value=>{ font => Helvetica, - size => 12 } - ); - print header(-cookie=>[$cookie1,$cookie2]); - - # fetch existing cookies - %cookies = fetch CGI::Cookie; - $id = $cookies{'ID'}->value; - - # create cookies returned from an external source - %cookies = parse CGI::Cookie($ENV{COOKIE}); - -=head1 DESCRIPTION - -CGI::Cookie is an interface to Netscape (HTTP/1.1) cookies, an -innovation that allows Web servers to store persistent information on -the browser's side of the connection. Although CGI::Cookie is -intended to be used in conjunction with CGI.pm (and is in fact used by -it internally), you can use this module independently. - -For full information on cookies see - - http://www.ics.uci.edu/pub/ietf/http/rfc2109.txt - -=head1 USING CGI::Cookie - -CGI::Cookie is object oriented. Each cookie object has a name and a -value. The name is any scalar value. The value is any scalar or -array value (associative arrays are also allowed). Cookies also have -several optional attributes, including: - -=over 4 - -=item B<1. expiration date> - -The expiration date tells the browser how long to hang on to the -cookie. If the cookie specifies an expiration date in the future, the -browser will store the cookie information in a disk file and return it -to the server every time the user reconnects (until the expiration -date is reached). If the cookie species an expiration date in the -past, the browser will remove the cookie from the disk file. If the -expiration date is not specified, the cookie will persist only until -the user quits the browser. - -=item B<2. domain> - -This is a partial or complete domain name for which the cookie is -valid. The browser will return the cookie to any host that matches -the partial domain name. For example, if you specify a domain name -of ".capricorn.com", then Netscape will return the cookie to -Web servers running on any of the machines "www.capricorn.com", -"ftp.capricorn.com", "feckless.capricorn.com", etc. Domain names -must contain at least two periods to prevent attempts to match -on top level domains like ".edu". If no domain is specified, then -the browser will only return the cookie to servers on the host the -cookie originated from. - -=item B<3. path> - -If you provide a cookie path attribute, the browser will check it -against your script's URL before returning the cookie. For example, -if you specify the path "/cgi-bin", then the cookie will be returned -to each of the scripts "/cgi-bin/tally.pl", "/cgi-bin/order.pl", and -"/cgi-bin/customer_service/complain.pl", but not to the script -"/cgi-private/site_admin.pl". By default, the path is set to "/", so -that all scripts at your site will receive the cookie. - -=item B<4. secure flag> - -If the "secure" attribute is set, the cookie will only be sent to your -script if the CGI request is occurring on a secure channel, such as SSL. - -=back - -=head2 Creating New Cookies - - $c = new CGI::Cookie(-name => 'foo', - -value => 'bar', - -expires => '+3M', - -domain => '.capricorn.com', - -path => '/cgi-bin/database', - -secure => 1 - ); - -Create cookies from scratch with the B method. The B<-name> and -B<-value> parameters are required. The name must be a scalar value. -The value can be a scalar, an array reference, or a hash reference. -(At some point in the future cookies will support one of the Perl -object serialization protocols for full generality). - -B<-expires> accepts any of the relative or absolute date formats -recognized by CGI.pm, for example "+3M" for three months in the -future. See CGI.pm's documentation for details. - -B<-domain> points to a domain name or to a fully qualified host name. -If not specified, the cookie will be returned only to the Web server -that created it. - -B<-path> points to a partial URL on the current server. The cookie -will be returned to all URLs beginning with the specified path. If -not specified, it defaults to '/', which returns the cookie to all -pages at your site. - -B<-secure> if set to a true value instructs the browser to return the -cookie only when a cryptographic protocol is in use. - -=head2 Sending the Cookie to the Browser - -Within a CGI script you can send a cookie to the browser by creating -one or more Set-Cookie: fields in the HTTP header. Here is a typical -sequence: - - my $c = new CGI::Cookie(-name => 'foo', - -value => ['bar','baz'], - -expires => '+3M'); - - print "Set-Cookie: $c\n"; - print "Content-Type: text/html\n\n"; - -To send more than one cookie, create several Set-Cookie: fields. - -If you are using CGI.pm, you send cookies by providing a -cookie -argument to the header() method: - - print header(-cookie=>$c); - -Mod_perl users can set cookies using the request object's header_out() -method: - - $r->headers_out->set('Set-Cookie' => $c); - -Internally, Cookie overloads the "" operator to call its as_string() -method when incorporated into the HTTP header. as_string() turns the -Cookie's internal representation into an RFC-compliant text -representation. You may call as_string() yourself if you prefer: - - print "Set-Cookie: ",$c->as_string,"\n"; - -=head2 Recovering Previous Cookies - - %cookies = fetch CGI::Cookie; - -B returns an associative array consisting of all cookies -returned by the browser. The keys of the array are the cookie names. You -can iterate through the cookies this way: - - %cookies = fetch CGI::Cookie; - foreach (keys %cookies) { - do_something($cookies{$_}); - } - -In a scalar context, fetch() returns a hash reference, which may be more -efficient if you are manipulating multiple cookies. - -CGI.pm uses the URL escaping methods to save and restore reserved characters -in its cookies. If you are trying to retrieve a cookie set by a foreign server, -this escaping method may trip you up. Use raw_fetch() instead, which has the -same semantics as fetch(), but performs no unescaping. - -You may also retrieve cookies that were stored in some external -form using the parse() class method: - - $COOKIES = `cat /usr/tmp/Cookie_stash`; - %cookies = parse CGI::Cookie($COOKIES); - -If you are in a mod_perl environment, you can save some overhead by -passing the request object to fetch() like this: - - CGI::Cookie->fetch($r); - -=head2 Manipulating Cookies - -Cookie objects have a series of accessor methods to get and set cookie -attributes. Each accessor has a similar syntax. Called without -arguments, the accessor returns the current value of the attribute. -Called with an argument, the accessor changes the attribute and -returns its new value. - -=over 4 - -=item B - -Get or set the cookie's name. Example: - - $name = $c->name; - $new_name = $c->name('fred'); - -=item B - -Get or set the cookie's value. Example: - - $value = $c->value; - @new_value = $c->value(['a','b','c','d']); - -B is context sensitive. In a list context it will return -the current value of the cookie as an array. In a scalar context it -will return the B value of a multivalued cookie. - -=item B - -Get or set the cookie's domain. - -=item B - -Get or set the cookie's path. - -=item B - -Get or set the cookie's expiration time. - -=back - - -=head1 AUTHOR INFORMATION - -Copyright 1997-1998, Lincoln D. Stein. All rights reserved. - -This library is free software; you can redistribute it and/or modify -it under the same terms as Perl itself. - -Address bug reports and comments to: lstein@cshl.org - -=head1 BUGS - -This section intentionally left blank. - -=head1 SEE ALSO - -L, L - -=cut diff --git a/lib/CGI/Fast.pm b/lib/CGI/Fast.pm deleted file mode 100644 index 43b8709..0000000 --- a/lib/CGI/Fast.pm +++ /dev/null @@ -1,230 +0,0 @@ -package CGI::Fast; - -# See the bottom of this file for the POD documentation. Search for the -# string '=head'. - -# You can run this file through either pod2man or pod2html to produce pretty -# documentation in manual or html file format (these utilities are part of the -# Perl 5 distribution). - -# Copyright 1995,1996, Lincoln D. Stein. All rights reserved. -# It may be used and modified freely, but I do request that this copyright -# notice remain attached to the file. You may modify this module as you -# wish, but if you redistribute a modified version, please attach a note -# listing the modifications you have made. - -# The most recent version and complete docs are available at: -# http://www.genome.wi.mit.edu/ftp/pub/software/WWW/cgi_docs.html -# ftp://ftp-genome.wi.mit.edu/pub/software/WWW/ -$CGI::Fast::VERSION='1.05'; - -use CGI; -use FCGI; -@ISA = ('CGI'); - -# workaround for known bug in libfcgi -while (($ignore) = each %ENV) { } - -# override the initialization behavior so that -# state is NOT maintained between invocations -sub save_request { - # no-op -} - -# If ENV{FCGI_SOCKET_PATH} is specified, we maintain a FCGI Request handle -# in this package variable. -use vars qw($Ext_Request); -BEGIN { - # If ENV{FCGI_SOCKET_PATH} is given, explicitly open the socket, - # and keep the request handle around from which to call Accept(). - if ($ENV{FCGI_SOCKET_PATH}) { - my $path = $ENV{FCGI_SOCKET_PATH}; - my $backlog = $ENV{FCGI_LISTEN_QUEUE} || 100; - my $socket = FCGI::OpenSocket( $path, $backlog ); - $Ext_Request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, - \%ENV, $socket, 1 ); - } -} - -# New is slightly different in that it calls FCGI's -# accept() method. -sub new { - my ($self, $initializer, @param) = @_; - unless (defined $initializer) { - if ($Ext_Request) { - return undef unless $Ext_Request->Accept() >= 0; - } else { - return undef unless FCGI::accept() >= 0; - } - } - return $CGI::Q = $self->SUPER::new($initializer, @param); -} - -1; - -=head1 NAME - -CGI::Fast - CGI Interface for Fast CGI - -=head1 SYNOPSIS - - use CGI::Fast qw(:standard); - $COUNTER = 0; - while (new CGI::Fast) { - print header; - print start_html("Fast CGI Rocks"); - print - h1("Fast CGI Rocks"), - "Invocation number ",b($COUNTER++), - " PID ",b($$),".", - hr; - print end_html; - } - -=head1 DESCRIPTION - -CGI::Fast is a subclass of the CGI object created by -CGI.pm. It is specialized to work well with the Open Market -FastCGI standard, which greatly speeds up CGI scripts by -turning them into persistently running server processes. Scripts -that perform time-consuming initialization processes, such as -loading large modules or opening persistent database connections, -will see large performance improvements. - -=head1 OTHER PIECES OF THE PUZZLE - -In order to use CGI::Fast you'll need a FastCGI-enabled Web -server. Open Market's server is FastCGI-savvy. There are also -freely redistributable FastCGI modules for NCSA httpd 1.5 and Apache. -FastCGI-enabling modules for Microsoft Internet Information Server and -Netscape Communications Server have been announced. - -In addition, you'll need a version of the Perl interpreter that has -been linked with the FastCGI I/O library. Precompiled binaries are -available for several platforms, including DEC Alpha, HP-UX and -SPARC/Solaris, or you can rebuild Perl from source with patches -provided in the FastCGI developer's kit. The FastCGI Perl interpreter -can be used in place of your normal Perl without ill consequences. - -You can find FastCGI modules for Apache and NCSA httpd, precompiled -Perl interpreters, and the FastCGI developer's kit all at URL: - - http://www.fastcgi.com/ - -=head1 WRITING FASTCGI PERL SCRIPTS - -FastCGI scripts are persistent: one or more copies of the script -are started up when the server initializes, and stay around until -the server exits or they die a natural death. After performing -whatever one-time initialization it needs, the script enters a -loop waiting for incoming connections, processing the request, and -waiting some more. - -A typical FastCGI script will look like this: - - #!/usr/local/bin/perl # must be a FastCGI version of perl! - use CGI::Fast; - &do_some_initialization(); - while ($q = new CGI::Fast) { - &process_request($q); - } - -Each time there's a new request, CGI::Fast returns a -CGI object to your loop. The rest of the time your script -waits in the call to new(). When the server requests that -your script be terminated, new() will return undef. You can -of course exit earlier if you choose. A new version of the -script will be respawned to take its place (this may be -necessary in order to avoid Perl memory leaks in long-running -scripts). - -CGI.pm's default CGI object mode also works. Just modify the loop -this way: - - while (new CGI::Fast) { - &process_request; - } - -Calls to header(), start_form(), etc. will all operate on the -current request. - -=head1 INSTALLING FASTCGI SCRIPTS - -See the FastCGI developer's kit documentation for full details. On -the Apache server, the following line must be added to srm.conf: - - AddType application/x-httpd-fcgi .fcgi - -FastCGI scripts must end in the extension .fcgi. For each script you -install, you must add something like the following to srm.conf: - - FastCgiServer /usr/etc/httpd/fcgi-bin/file_upload.fcgi -processes 2 - -This instructs Apache to launch two copies of file_upload.fcgi at -startup time. - -=head1 USING FASTCGI SCRIPTS AS CGI SCRIPTS - -Any script that works correctly as a FastCGI script will also work -correctly when installed as a vanilla CGI script. However it will -not see any performance benefit. - -=head1 EXTERNAL FASTCGI SERVER INVOCATION - -FastCGI supports a TCP/IP transport mechanism which allows FastCGI scripts to run -external to the webserver, perhaps on a remote machine. To configure the -webserver to connect to an external FastCGI server, you would add the following -to your srm.conf: - - FastCgiExternalServer /usr/etc/httpd/fcgi-bin/file_upload.fcgi -host sputnik:8888 - -Two environment variables affect how the C object is created, -allowing C to be used as an external FastCGI server. (See C -documentation for C for more information.) - -=over - -=item FCGI_SOCKET_PATH - -The address (TCP/IP) or path (UNIX Domain) of the socket the external FastCGI -script to which bind an listen for incoming connections from the web server. - -=item FCGI_LISTEN_QUEUE - -Maximum length of the queue of pending connections. - -=back - -For example: - - #!/usr/local/bin/perl # must be a FastCGI version of perl! - use CGI::Fast; - &do_some_initialization(); - $ENV{FCGI_SOCKET_PATH} = "sputnik:8888"; - $ENV{FCGI_LISTEN_QUEUE} = 100; - while ($q = new CGI::Fast) { - &process_request($q); - } - -=head1 CAVEATS - -I haven't tested this very much. - -=head1 AUTHOR INFORMATION - -Copyright 1996-1998, Lincoln D. Stein. All rights reserved. - -This library is free software; you can redistribute it and/or modify -it under the same terms as Perl itself. - -Address bug reports and comments to: lstein@cshl.org - -=head1 BUGS - -This section intentionally left blank. - -=head1 SEE ALSO - -L, L - -=cut diff --git a/lib/CGI/Pretty.pm b/lib/CGI/Pretty.pm deleted file mode 100644 index d824a02..0000000 --- a/lib/CGI/Pretty.pm +++ /dev/null @@ -1,275 +0,0 @@ -package CGI::Pretty; - -# See the bottom of this file for the POD documentation. Search for the -# string '=head'. - -# You can run this file through either pod2man or pod2html to produce pretty -# documentation in manual or html file format (these utilities are part of the -# Perl 5 distribution). - -use strict; -use CGI (); - -$CGI::Pretty::VERSION = '1.08'; -$CGI::DefaultClass = __PACKAGE__; -$CGI::Pretty::AutoloadClass = 'CGI'; -@CGI::Pretty::ISA = qw( CGI ); - -initialize_globals(); - -sub _prettyPrint { - my $input = shift; - return if !$$input; - return if !$CGI::Pretty::LINEBREAK || !$CGI::Pretty::INDENT; - -# print STDERR "'", $$input, "'\n"; - - foreach my $i ( @CGI::Pretty::AS_IS ) { - if ( $$input =~ m{}si ) { - my ( $a, $b, $c ) = $$input =~ m{(.*)(<$i[\s/>].*?)(.*)}si; - next if !$b; - $a ||= ""; - $c ||= ""; - - _prettyPrint( \$a ) if $a; - _prettyPrint( \$c ) if $c; - - $b ||= ""; - $$input = "$a$b$c"; - return; - } - } - $$input =~ s/$CGI::Pretty::LINEBREAK/$CGI::Pretty::LINEBREAK$CGI::Pretty::INDENT/g; -} - -sub comment { - my($self,@p) = CGI::self_or_CGI(@_); - - my $s = "@p"; - $s =~ s/$CGI::Pretty::LINEBREAK/$CGI::Pretty::LINEBREAK$CGI::Pretty::INDENT/g if $CGI::Pretty::LINEBREAK; - - return $self->SUPER::comment( "$CGI::Pretty::LINEBREAK$CGI::Pretty::INDENT$s$CGI::Pretty::LINEBREAK" ) . $CGI::Pretty::LINEBREAK; -} - -sub _make_tag_func { - my ($self,$tagname) = @_; - - # As Lincoln as noted, the last else clause is VERY hairy, and it - # took me a while to figure out what I was trying to do. - # What it does is look for tags that shouldn't be indented (e.g. PRE) - # and makes sure that when we nest tags, those tags don't get - # indented. - # For an example, try print td( pre( "hello\nworld" ) ); - # If we didn't care about stuff like that, the code would be - # MUCH simpler. BTW: I won't claim to be a regular expression - # guru, so if anybody wants to contribute something that would - # be quicker, easier to read, etc, I would be more than - # willing to put it in - Brian - - my $func = qq" - sub $tagname {"; - - $func .= q' - shift if $_[0] && - (ref($_[0]) && - (substr(ref($_[0]),0,3) eq "CGI" || - UNIVERSAL::isa($_[0],"CGI"))); - my($attr) = ""; - if (ref($_[0]) && ref($_[0]) eq "HASH") { - my(@attr) = make_attributes(shift()||undef,1); - $attr = " @attr" if @attr; - }'; - - if ($tagname=~/start_(\w+)/i) { - $func .= qq! - return "<\L$1\E\$attr>\$CGI::Pretty::LINEBREAK";} !; - } elsif ($tagname=~/end_(\w+)/i) { - $func .= qq! - return "<\L/$1\E>\$CGI::Pretty::LINEBREAK"; } !; - } else { - $func .= qq# - return ( \$CGI::XHTML ? "<\L$tagname\E\$attr />" : "<\L$tagname\E\$attr>" ) . - \$CGI::Pretty::LINEBREAK unless \@_; - my(\$tag,\$untag) = ("<\L$tagname\E\$attr>","\E"); - - my \%ASIS = map { lc("\$_") => 1 } \@CGI::Pretty::AS_IS; - my \@args; - if ( \$CGI::Pretty::LINEBREAK || \$CGI::Pretty::INDENT ) { - if(ref(\$_[0]) eq 'ARRAY') { - \@args = \@{\$_[0]} - } else { - foreach (\@_) { - \$args[0] .= \$_; - \$args[0] .= \$CGI::Pretty::LINEBREAK if \$args[0] !~ /\$CGI::Pretty::LINEBREAK\$/ && 0; - chomp \$args[0] if exists \$ASIS{ "\L$tagname\E" }; - - \$args[0] .= \$" if \$args[0] !~ /\$CGI::Pretty::LINEBREAK\$/ && 1; - } - chop \$args[0]; - } - } - else { - \@args = ref(\$_[0]) eq 'ARRAY' ? \@{\$_[0]} : "\@_"; - } - - my \@result; - if ( exists \$ASIS{ "\L$tagname\E" } ) { - \@result = map { "\$tag\$_\$untag\$CGI::Pretty::LINEBREAK" } - \@args; - } - else { - \@result = map { - chomp; - my \$tmp = \$_; - CGI::Pretty::_prettyPrint( \\\$tmp ); - \$tag . \$CGI::Pretty::LINEBREAK . - \$CGI::Pretty::INDENT . \$tmp . \$CGI::Pretty::LINEBREAK . - \$untag . \$CGI::Pretty::LINEBREAK - } \@args; - } - local \$" = "" if \$CGI::Pretty::LINEBREAK || \$CGI::Pretty::INDENT; - return "\@result"; - }#; - } - - return $func; -} - -sub start_html { - return CGI::start_html( @_ ) . $CGI::Pretty::LINEBREAK; -} - -sub end_html { - return CGI::end_html( @_ ) . $CGI::Pretty::LINEBREAK; -} - -sub new { - my $class = shift; - my $this = $class->SUPER::new( @_ ); - - if ($CGI::MOD_PERL) { - my $r = Apache->request; - if ($CGI::MOD_PERL == 1) { - $r->register_cleanup(\&CGI::Pretty::_reset_globals); - } - else { - $r->pool->cleanup_register(\&CGI::Pretty::_reset_globals); - } - } - $class->_reset_globals if $CGI::PERLEX; - - return bless $this, $class; -} - -sub initialize_globals { - # This is the string used for indentation of tags - $CGI::Pretty::INDENT = "\t"; - - # This is the string used for seperation between tags - $CGI::Pretty::LINEBREAK = $/; - - # These tags are not prettify'd. - @CGI::Pretty::AS_IS = qw( a pre code script textarea td ); - - 1; -} -sub _reset_globals { initialize_globals(); } - -1; - -=head1 NAME - -CGI::Pretty - module to produce nicely formatted HTML code - -=head1 SYNOPSIS - - use CGI::Pretty qw( :html3 ); - - # Print a table with a single data element - print table( TR( td( "foo" ) ) ); - -=head1 DESCRIPTION - -CGI::Pretty is a module that derives from CGI. It's sole function is to -allow users of CGI to output nicely formatted HTML code. - -When using the CGI module, the following code: - print table( TR( td( "foo" ) ) ); - -produces the following output: -
foo
- -If a user were to create a table consisting of many rows and many columns, -the resultant HTML code would be quite difficult to read since it has no -carriage returns or indentation. - -CGI::Pretty fixes this problem. What it does is add a carriage -return and indentation to the HTML code so that one can easily read -it. - - print table( TR( td( "foo" ) ) ); - -now produces the following output: - - - - -
- foo -
- - -=head2 Tags that won't be formatted - -The and
 tags are not formatted.  If these tags were formatted, the
-user would see the extra indentation on the web browser causing the page to
-look different than what would be expected.  If you wish to add more tags to
-the list of tags that are not to be touched, push them onto the C<@AS_IS> array:
-
-    push @CGI::Pretty::AS_IS,qw(CODE XMP);
-
-=head2 Customizing the Indenting
-
-If you wish to have your own personal style of indenting, you can change the
-C<$INDENT> variable:
-
-    $CGI::Pretty::INDENT = "\t\t";
-
-would cause the indents to be two tabs.
-
-Similarly, if you wish to have more space between lines, you may change the
-C<$LINEBREAK> variable:
-
-    $CGI::Pretty::LINEBREAK = "\n\n";
-
-would create two carriage returns between lines.
-
-If you decide you want to use the regular CGI indenting, you can easily do 
-the following:
-
-    $CGI::Pretty::INDENT = $CGI::Pretty::LINEBREAK = "";
-
-=head1 BUGS
-
-This section intentionally left blank.
-
-=head1 AUTHOR
-
-Brian Paulsen , with minor modifications by
-Lincoln Stein  for incorporation into the CGI.pm
-distribution.
-
-Copyright 1999, Brian Paulsen.  All rights reserved.
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself.
-
-Bug reports and comments to Brian@ThePaulsens.com.  You can also write
-to lstein@cshl.org, but this code looks pretty hairy to me and I'm not
-sure I understand it!
-
-=head1 SEE ALSO
-
-L
-
-=cut
diff --git a/lib/CGI/Push.pm b/lib/CGI/Push.pm
deleted file mode 100644
index 8356c60..0000000
--- a/lib/CGI/Push.pm
+++ /dev/null
@@ -1,328 +0,0 @@
-package CGI::Push;
-
-# See the bottom of this file for the POD documentation.  Search for the
-# string '=head'.
-
-# You can run this file through either pod2man or pod2html to produce pretty
-# documentation in manual or html file format (these utilities are part of the
-# Perl 5 distribution).
-
-# Copyright 1995-2000, Lincoln D. Stein.  All rights reserved.
-# It may be used and modified freely, but I do request that this copyright
-# notice remain attached to the file.  You may modify this module as you
-# wish, but if you redistribute a modified version, please attach a note
-# listing the modifications you have made.
-
-# The most recent version and complete docs are available at:
-#   http://stein.cshl.org/WWW/software/CGI/
-
-$CGI::Push::VERSION='1.04';
-use CGI;
-use CGI::Util 'rearrange';
-@ISA = ('CGI');
-
-$CGI::DefaultClass = 'CGI::Push';
-$CGI::Push::AutoloadClass = 'CGI';
-
-# add do_push() and push_delay() to exported tags
-push(@{$CGI::EXPORT_TAGS{':standard'}},'do_push','push_delay');
-
-sub do_push {
-    my ($self,@p) = CGI::self_or_default(@_);
-
-    # unbuffer output
-    $| = 1;
-    srand;
-    my ($random) = sprintf("%08.0f",rand()*1E8);
-    my ($boundary) = "----=_NeXtPaRt$random";
-
-    my (@header);
-    my ($type,$callback,$delay,$last_page,$cookie,$target,$expires,$nph,$handle,@other) = rearrange([TYPE,NEXT_PAGE,DELAY,LAST_PAGE,[COOKIE,COOKIES],TARGET,EXPIRES,NPH,HANDLE],@p);
-    $type = 'text/html' unless $type;
-    $callback = \&simple_counter unless $callback && ref($callback) eq 'CODE';
-    $delay = 1 unless defined($delay);
-    $self->push_delay($delay);
-    $nph = 1 unless defined($nph);
-    $handle = \*STDOUT unless defined($handle);
-
-sdf;kjsdlfsdfkl
-
-    my(@o);
-    foreach (@other) { push(@o,split("=")); }
-    push(@o,'-Target'=>$target) if defined($target);
-    push(@o,'-Cookie'=>$cookie) if defined($cookie);
-    push(@o,'-Type'=>"multipart/x-mixed-replace;boundary=\"$boundary\"");
-    push(@o,'-Server'=>"CGI.pm Push Module") if $nph;
-    push(@o,'-Status'=>'200 OK');
-    push(@o,'-nph'=>1) if $nph;
-    $handle->print($self->header(@o));
-
-    $boundary = "$CGI::CRLF--$boundary";
-
-    $handle->print("WARNING: YOUR BROWSER DOESN'T SUPPORT THIS SERVER-PUSH TECHNOLOGY.${boundary}$CGI::CRLF");
-
-    my (@contents) = &$callback($self,++$COUNTER);
-
-    # now we enter a little loop
-    while (1) {
-        $handle->print("Content-type: ${type}$CGI::CRLF$CGI::CRLF") unless $type =~ /^dynamic|heterogeneous$/i;
-        $handle->print(@contents);
-        @contents = &$callback($self,++$COUNTER);
-        if ((@contents) && defined($contents[0])) {
-            $handle->print("${boundary}$CGI::CRLF");
-            do_sleep($self->push_delay()) if $self->push_delay();
-        } else {
-            if ($last_page && ref($last_page) eq 'CODE') {
-                $handle->print("${boundary}$CGI::CRLF");
-                do_sleep($self->push_delay()) if $self->push_delay();
-                $handle->print("Content-type: ${type}$CGI::CRLF$CGI::CRLF") unless $type =~ /^dynamic|heterogeneous$/i;
-                $handle->print(&$last_page($self,$COUNTER));
-            }
-            $handle->print("${boundary}--$CGI::CRLF");
-            last;
-        }
-    }
-    $handle->print("WARNING: YOUR BROWSER DOESN'T SUPPORT THIS SERVER-PUSH TECHNOLOGY.${boundary}$CGI::CRLF");
-}
-
-sub simple_counter {
-    my ($self,$count) = @_;
-    return $self->start_html("CGI::Push Default Counter"),
-           $self->h1("CGI::Push Default Counter"),
-           "This page has been updated ",$self->strong($count)," times.",
-           $self->hr(),
-           $self->a({'-href'=>'http://www.genome.wi.mit.edu/ftp/pub/software/WWW/cgi_docs.html'},'CGI.pm home page'),
-           $self->end_html;
-}
-
-sub do_sleep {
-    my $delay = shift;
-    if ( ($delay >= 1) && ($delay!~/\./) ){
-        sleep($delay);
-    } else {
-        select(undef,undef,undef,$delay);
-    }
-}
-
-sub push_delay {
-    my ($self,$delay) = CGI::self_or_default(@_);
-    return defined($delay) ? $self->{'.delay'} =
-        $delay : $self->{'.delay'};
-}
-
-1;
-
-=head1 NAME
-
-CGI::Push - Simple Interface to Server Push
-
-=head1 SYNOPSIS
-
-    use CGI::Push qw(:standard);
-
-    do_push(-next_page=>\&next_page,
-            -last_page=>\&last_page,
-            -delay=>0.5);
-
-    sub next_page {
-        my($q,$counter) = @_;
-        return undef if $counter >= 10;
-        return start_html('Test'),
-               h1('Visible'),"\n",
-               "This page has been called ", strong($counter)," times",
-               end_html();
-    }
-
-    sub last_page {
-        my($q,$counter) = @_;
-        return start_html('Done'),
-               h1('Finished'),
-               strong($counter - 1),' iterations.',
-               end_html;
-    }
-
-=head1 DESCRIPTION
-
-CGI::Push is a subclass of the CGI object created by CGI.pm.  It is
-specialized for server push operations, which allow you to create
-animated pages whose content changes at regular intervals.
-
-You provide CGI::Push with a pointer to a subroutine that will draw
-one page.  Every time your subroutine is called, it generates a new
-page.  The contents of the page will be transmitted to the browser
-in such a way that it will replace what was there beforehand.  The
-technique will work with HTML pages as well as with graphics files,
-allowing you to create animated GIFs.
-
-Only Netscape Navigator supports server push.  Internet Explorer
-browsers do not.
-
-=head1 USING CGI::Push
-
-CGI::Push adds one new method to the standard CGI suite, do_push().
-When you call this method, you pass it a reference to a subroutine
-that is responsible for drawing each new page, an interval delay, and
-an optional subroutine for drawing the last page.  Other optional
-parameters include most of those recognized by the CGI header()
-method.
-
-You may call do_push() in the object oriented manner or not, as you
-prefer:
-
-    use CGI::Push;
-    $q = new CGI::Push;
-    $q->do_push(-next_page=>\&draw_a_page);
-
-        -or-
-
-    use CGI::Push qw(:standard);
-    do_push(-next_page=>\&draw_a_page);
-
-Parameters are as follows:
-
-=over 4
-
-=item -next_page
-
-    do_push(-next_page=>\&my_draw_routine);
-
-This required parameter points to a reference to a subroutine responsible for
-drawing each new page.  The subroutine should expect two parameters
-consisting of the CGI object and a counter indicating the number
-of times the subroutine has been called.  It should return the
-contents of the page as an B of one or more items to print.
-It can return a false value (or an empty array) in order to abort the
-redrawing loop and print out the final page (if any)
-
-    sub my_draw_routine {
-        my($q,$counter) = @_;
-        return undef if $counter > 100;
-        return start_html('testing'),
-               h1('testing'),
-               "This page called $counter times";
-    }
-
-You are of course free to refer to create and use global variables
-within your draw routine in order to achieve special effects.
-
-=item -last_page
-
-This optional parameter points to a reference to the subroutine
-responsible for drawing the last page of the series.  It is called
-after the -next_page routine returns a false value.  The subroutine
-itself should have exactly the same calling conventions as the
--next_page routine.
-
-=item -type
-
-This optional parameter indicates the content type of each page.  It
-defaults to "text/html".  Normally the module assumes that each page
-is of a homogenous MIME type.  However if you provide either of the
-magic values "heterogeneous" or "dynamic" (the latter provided for the
-convenience of those who hate long parameter names), you can specify
-the MIME type -- and other header fields -- on a per-page basis.  See
-"heterogeneous pages" for more details.
-
-=item -delay
-
-This indicates the delay, in seconds, between frames.  Smaller delays
-refresh the page faster.  Fractional values are allowed.
-
-B
-
-=item -cookie, -target, -expires, -nph
-
-These have the same meaning as the like-named parameters in
-CGI::header().
-
-If not specified, -nph will default to 1 (as needed for many servers, see below).
-
-=back
-
-=head2 Heterogeneous Pages
-
-Ordinarily all pages displayed by CGI::Push share a common MIME type.
-However by providing a value of "heterogeneous" or "dynamic" in the
-do_push() -type parameter, you can specify the MIME type of each page
-on a case-by-case basis.
-
-If you use this option, you will be responsible for producing the
-HTTP header for each page.  Simply modify your draw routine to
-look like this:
-
-    sub my_draw_routine {
-        my($q,$counter) = @_;
-        return header('text/html'),   # note we're producing the header here
-               start_html('testing'),
-               h1('testing'),
-               "This page called $counter times";
-    }
-
-You can add any header fields that you like, but some (cookies and
-status fields included) may not be interpreted by the browser.  One
-interesting effect is to display a series of pages, then, after the
-last page, to redirect the browser to a new URL.  Because redirect()
-does b work, the easiest way is with a -refresh header field,
-as shown below:
-
-    sub my_draw_routine {
-        my($q,$counter) = @_;
-        return undef if $counter > 10;
-        return header('text/html'),   # note we're producing the header here
-               start_html('testing'),
-               h1('testing'),
-               "This page called $counter times";
-    }
-
-    sub my_last_page {
-        return header(-refresh=>'5; URL=http://somewhere.else/finished.html',
-                      -type=>'text/html'),
-               start_html('Moved'),
-               h1('This is the last page'),
-               'Goodbye!'
-               hr,
-               end_html;
-    }
-
-=head2 Changing the Page Delay on the Fly
-
-If you would like to control the delay between pages on a page-by-page
-basis, call push_delay() from within your draw routine.  push_delay()
-takes a single numeric argument representing the number of seconds you
-wish to delay after the current page is displayed and before
-displaying the next one.  The delay may be fractional.  Without
-parameters, push_delay() just returns the current delay.
-
-=head1 INSTALLING CGI::Push SCRIPTS
-
-Server push scripts must be installed as no-parsed-header (NPH)
-scripts in order to work correctly on many servers.  On Unix systems,
-this is most often accomplished by prefixing the script's name with "nph-".
-Recognition of NPH scripts happens automatically with WebSTAR and
-Microsoft IIS.  Users of other servers should see their documentation
-for help.
-
-Apache web server from version 1.3b2 on does not need server
-push scripts installed as NPH scripts: the -nph parameter to do_push()
-may be set to a false value to disable the extra headers needed by an
-NPH script.
-
-=head1 AUTHOR INFORMATION
-
-Copyright 1995-1998, Lincoln D. Stein.  All rights reserved.
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself.
-
-Address bug reports and comments to: lstein@cshl.org
-
-=head1 BUGS
-
-This section intentionally left blank.
-
-=head1 SEE ALSO
-
-L, L
-
-=cut
-
diff --git a/lib/CGI/Switch.pm b/lib/CGI/Switch.pm
deleted file mode 100644
index b8cc9ef..0000000
--- a/lib/CGI/Switch.pm
+++ /dev/null
@@ -1,27 +0,0 @@
-use CGI;
-
-$VERSION = '1.00';
-
-1;
-
-__END__
-
-=head1 NAME
-
-CGI::Switch - Backward compatibility module for defunct CGI::Switch
-
-=head1 SYNOPSIS
-
-Do not use this module.  It is deprecated.
-
-=head1 ABSTRACT
-
-=head1 DESCRIPTION
-
-=head1 AUTHOR INFORMATION
-
-=head1 BUGS
-
-=head1 SEE ALSO
-
-=cut
diff --git a/lib/CGI/Util.pm b/lib/CGI/Util.pm
deleted file mode 100644
index 6af42de..0000000
--- a/lib/CGI/Util.pm
+++ /dev/null
@@ -1,317 +0,0 @@
-package CGI::Util;
-
-use strict;
-use vars qw($VERSION @EXPORT_OK @ISA $EBCDIC @A2E @E2A);
-require Exporter;
-@ISA = qw(Exporter);
-@EXPORT_OK = qw(rearrange make_attributes unescape escape 
-		expires ebcdic2ascii ascii2ebcdic);
-
-$VERSION = '1.5';
-
-$EBCDIC = "\t" ne "\011";
-# (ord('^') == 95) for codepage 1047 as on os390, vmesa
-@A2E = (
-   0,  1,  2,  3, 55, 45, 46, 47, 22,  5, 21, 11, 12, 13, 14, 15,
-  16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31,
-  64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97,
- 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111,
- 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214,
- 215,216,217,226,227,228,229,230,231,232,233,173,224,189, 95,109,
- 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150,
- 151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161,  7,
-  32, 33, 34, 35, 36, 37,  6, 23, 40, 41, 42, 43, 44,  9, 10, 27,
-  48, 49, 26, 51, 52, 53, 54,  8, 56, 57, 58, 59,  4, 20, 62,255,
-  65,170, 74,177,159,178,106,181,187,180,154,138,176,202,175,188,
- 144,143,234,250,190,160,182,179,157,218,155,139,183,184,185,171,
- 100,101, 98,102, 99,103,158,104,116,113,114,115,120,117,118,119,
- 172,105,237,238,235,239,236,191,128,253,254,251,252,186,174, 89,
-  68, 69, 66, 70, 67, 71,156, 72, 84, 81, 82, 83, 88, 85, 86, 87,
- 140, 73,205,206,203,207,204,225,112,221,222,219,220,141,142,223
-	 );
-@E2A = (
-   0,  1,  2,  3,156,  9,134,127,151,141,142, 11, 12, 13, 14, 15,
-  16, 17, 18, 19,157, 10,  8,135, 24, 25,146,143, 28, 29, 30, 31,
- 128,129,130,131,132,133, 23, 27,136,137,138,139,140,  5,  6,  7,
- 144,145, 22,147,148,149,150,  4,152,153,154,155, 20, 21,158, 26,
-  32,160,226,228,224,225,227,229,231,241,162, 46, 60, 40, 43,124,
-  38,233,234,235,232,237,238,239,236,223, 33, 36, 42, 41, 59, 94,
-  45, 47,194,196,192,193,195,197,199,209,166, 44, 37, 95, 62, 63,
- 248,201,202,203,200,205,206,207,204, 96, 58, 35, 64, 39, 61, 34,
- 216, 97, 98, 99,100,101,102,103,104,105,171,187,240,253,254,177,
- 176,106,107,108,109,110,111,112,113,114,170,186,230,184,198,164,
- 181,126,115,116,117,118,119,120,121,122,161,191,208, 91,222,174,
- 172,163,165,183,169,167,182,188,189,190,221,168,175, 93,180,215,
- 123, 65, 66, 67, 68, 69, 70, 71, 72, 73,173,244,246,242,243,245,
- 125, 74, 75, 76, 77, 78, 79, 80, 81, 82,185,251,252,249,250,255,
-  92,247, 83, 84, 85, 86, 87, 88, 89, 90,178,212,214,210,211,213,
-  48, 49, 50, 51, 52, 53, 54, 55, 56, 57,179,219,220,217,218,159
-	 );
-
-if ($EBCDIC && ord('^') == 106) { # as in the BS2000 posix-bc coded character set
-     $A2E[91] = 187;   $A2E[92] = 188;  $A2E[94] = 106;  $A2E[96] = 74;
-     $A2E[123] = 251;  $A2E[125] = 253; $A2E[126] = 255; $A2E[159] = 95;
-     $A2E[162] = 176;  $A2E[166] = 208; $A2E[168] = 121; $A2E[172] = 186;
-     $A2E[175] = 161;  $A2E[217] = 224; $A2E[219] = 221; $A2E[221] = 173;
-     $A2E[249] = 192;
-
-     $E2A[74] = 96;   $E2A[95] = 159;  $E2A[106] = 94;  $E2A[121] = 168;
-     $E2A[161] = 175; $E2A[173] = 221; $E2A[176] = 162; $E2A[186] = 172;
-     $E2A[187] = 91;  $E2A[188] = 92;  $E2A[192] = 249; $E2A[208] = 166;
-     $E2A[221] = 219; $E2A[224] = 217; $E2A[251] = 123; $E2A[253] = 125;
-     $E2A[255] = 126;
-   }
-elsif ($EBCDIC && ord('^') == 176) { # as in codepage 037 on os400
-  $A2E[10] = 37;  $A2E[91] = 186;  $A2E[93] = 187; $A2E[94] = 176;
-  $A2E[133] = 21; $A2E[168] = 189; $A2E[172] = 95; $A2E[221] = 173;
-
-  $E2A[21] = 133; $E2A[37] = 10;  $E2A[95] = 172; $E2A[173] = 221;
-  $E2A[176] = 94; $E2A[186] = 91; $E2A[187] = 93; $E2A[189] = 168;
-}
-
-# Smart rearrangement of parameters to allow named parameter
-# calling.  We do the rearangement if:
-# the first parameter begins with a -
-sub rearrange {
-    my($order,@param) = @_;
-    return () unless @param;
-
-    if (ref($param[0]) eq 'HASH') {
-	@param = %{$param[0]};
-    } else {
-	return @param 
-	    unless (defined($param[0]) && substr($param[0],0,1) eq '-');
-    }
-
-    # map parameters into positional indices
-    my ($i,%pos);
-    $i = 0;
-    foreach (@$order) {
-	foreach (ref($_) eq 'ARRAY' ? @$_ : $_) { $pos{lc($_)} = $i; }
-	$i++;
-    }
-
-    my (@result,%leftover);
-    $#result = $#$order;  # preextend
-    while (@param) {
-	my $key = lc(shift(@param));
-	$key =~ s/^\-//;
-	if (exists $pos{$key}) {
-	    $result[$pos{$key}] = shift(@param);
-	} else {
-	    $leftover{$key} = shift(@param);
-	}
-    }
-
-    push (@result,make_attributes(\%leftover,1)) if %leftover;
-    @result;
-}
-
-sub make_attributes {
-    my $attr = shift;
-    return () unless $attr && ref($attr) && ref($attr) eq 'HASH';
-    my $escape = shift || 0;
-    my(@att);
-    foreach (keys %{$attr}) {
-	my($key) = $_;
-	$key=~s/^\-//;     # get rid of initial - if present
-
-	# old way: breaks EBCDIC!
-	# $key=~tr/A-Z_/a-z-/; # parameters are lower case, use dashes
-
-	($key="\L$key") =~ tr/_/-/; # parameters are lower case, use dashes
-
-	my $value = $escape ? simple_escape($attr->{$_}) : $attr->{$_};
-	push(@att,defined($attr->{$_}) ? qq/$key="$value"/ : qq/$key/);
-    }
-    return @att;
-}
-
-sub simple_escape {
-  return unless defined(my $toencode = shift);
-  $toencode =~ s{&}{&}gso;
-  $toencode =~ s{<}{<}gso;
-  $toencode =~ s{>}{>}gso;
-  $toencode =~ s{\"}{"}gso;
-# Doesn't work.  Can't work.  forget it.
-#  $toencode =~ s{\x8b}{‹}gso;
-#  $toencode =~ s{\x9b}{›}gso;
-  $toencode;
-}
-
-sub utf8_chr {
-        my $c = shift(@_);
-
-        if ($c < 0x80) {
-                return sprintf("%c", $c);
-        } elsif ($c < 0x800) {
-                return sprintf("%c%c", 0xc0 | ($c >> 6), 0x80 | ($c & 0x3f));
-        } elsif ($c < 0x10000) {
-                return sprintf("%c%c%c",
-                                           0xe0 |  ($c >> 12),
-                                           0x80 | (($c >>  6) & 0x3f),
-                                           0x80 | ( $c          & 0x3f));
-        } elsif ($c < 0x200000) {
-                return sprintf("%c%c%c%c",
-                                           0xf0 |  ($c >> 18),
-                                           0x80 | (($c >> 12) & 0x3f),
-                                           0x80 | (($c >>  6) & 0x3f),
-                                           0x80 | ( $c          & 0x3f));
-        } elsif ($c < 0x4000000) {
-                return sprintf("%c%c%c%c%c",
-                                           0xf8 |  ($c >> 24),
-                                           0x80 | (($c >> 18) & 0x3f),
-                                           0x80 | (($c >> 12) & 0x3f),
-                                           0x80 | (($c >>  6) & 0x3f),
-                                           0x80 | ( $c          & 0x3f));
-
-        } elsif ($c < 0x80000000) {
-                return sprintf("%c%c%c%c%c%c",
-                                           0xfc |  ($c >> 30),
-                                           0x80 | (($c >> 24) & 0x3f),
-                                           0x80 | (($c >> 18) & 0x3f),
-                                           0x80 | (($c >> 12) & 0x3f),
-                                           0x80 | (($c >> 6)  & 0x3f),
-                                           0x80 | ( $c          & 0x3f));
-        } else {
-                return utf8_chr(0xfffd);
-        }
-}
-
-# unescape URL-encoded data
-sub unescape {
-  shift() if @_ > 1 and (ref($_[0]) || (defined $_[1] && $_[0] eq $CGI::DefaultClass));
-  my $todecode = shift;
-  return undef unless defined($todecode);
-  $todecode =~ tr/+/ /;       # pluses become spaces
-    $EBCDIC = "\t" ne "\011";
-    if ($EBCDIC) {
-      $todecode =~ s/%([0-9a-fA-F]{2})/chr $A2E[hex($1)]/ge;
-    } else {
-      $todecode =~ s/%(?:([0-9a-fA-F]{2})|u([0-9a-fA-F]{4}))/
-	defined($1)? chr hex($1) : utf8_chr(hex($2))/ge;
-    }
-  return $todecode;
-}
-
-# URL-encode data
-sub escape {
-  shift() if @_ > 1 and ( ref($_[0]) || (defined $_[1] && $_[0] eq $CGI::DefaultClass));
-  my $toencode = shift;
-  return undef unless defined($toencode);
-  # force bytes while preserving backward compatibility -- dankogai
-  $toencode = pack("C*", unpack("C*", $toencode));
-    if ($EBCDIC) {
-      $toencode=~s/([^a-zA-Z0-9_.-])/uc sprintf("%%%02x",$E2A[ord($1)])/eg;
-    } else {
-      $toencode=~s/([^a-zA-Z0-9_.-])/uc sprintf("%%%02x",ord($1))/eg;
-    }
-  return $toencode;
-}
-
-# This internal routine creates date strings suitable for use in
-# cookies and HTTP headers.  (They differ, unfortunately.)
-# Thanks to Mark Fisher for this.
-sub expires {
-    my($time,$format) = @_;
-    $format ||= 'http';
-
-    my(@MON)=qw/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/;
-    my(@WDAY) = qw/Sun Mon Tue Wed Thu Fri Sat/;
-
-    # pass through preformatted dates for the sake of expire_calc()
-    $time = expire_calc($time);
-    return $time unless $time =~ /^\d+$/;
-
-    # make HTTP/cookie date string from GMT'ed time
-    # (cookies use '-' as date separator, HTTP uses ' ')
-    my($sc) = ' ';
-    $sc = '-' if $format eq "cookie";
-    my($sec,$min,$hour,$mday,$mon,$year,$wday) = gmtime($time);
-    $year += 1900;
-    return sprintf("%s, %02d$sc%s$sc%04d %02d:%02d:%02d GMT",
-                   $WDAY[$wday],$mday,$MON[$mon],$year,$hour,$min,$sec);
-}
-
-# This internal routine creates an expires time exactly some number of
-# hours from the current time.  It incorporates modifications from 
-# Mark Fisher.
-sub expire_calc {
-    my($time) = @_;
-    my(%mult) = ('s'=>1,
-                 'm'=>60,
-                 'h'=>60*60,
-                 'd'=>60*60*24,
-                 'M'=>60*60*24*30,
-                 'y'=>60*60*24*365);
-    # format for time can be in any of the forms...
-    # "now" -- expire immediately
-    # "+180s" -- in 180 seconds
-    # "+2m" -- in 2 minutes
-    # "+12h" -- in 12 hours
-    # "+1d"  -- in 1 day
-    # "+3M"  -- in 3 months
-    # "+2y"  -- in 2 years
-    # "-3m"  -- 3 minutes ago(!)
-    # If you don't supply one of these forms, we assume you are
-    # specifying the date yourself
-    my($offset);
-    if (!$time || (lc($time) eq 'now')) {
-        $offset = 0;
-    } elsif ($time=~/^\d+/) {
-        return $time;
-    } elsif ($time=~/^([+-]?(?:\d+|\d*\.\d*))([mhdMy]?)/) {
-        $offset = ($mult{$2} || 1)*$1;
-    } else {
-        return $time;
-    }
-    return (time+$offset);
-}
-
-sub ebcdic2ascii {
-  my $data = shift;
-  $data =~ s/(.)/chr $E2A[ord($1)]/ge;
-  $data;
-}
-
-sub ascii2ebcdic {
-  my $data = shift;
-  $data =~ s/(.)/chr $A2E[ord($1)]/ge;
-  $data;
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-CGI::Util - Internal utilities used by CGI module
-
-=head1 SYNOPSIS
-
-none
-
-=head1 DESCRIPTION
-
-no public subroutines
-
-=head1 AUTHOR INFORMATION
-
-Copyright 1995-1998, Lincoln D. Stein.  All rights reserved.  
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself.
-
-Address bug reports and comments to: lstein@cshl.org.  When sending
-bug reports, please provide the version of CGI.pm, the version of
-Perl, the name and version of your Web server, and the name and
-version of the operating system you are using.  If the problem is even
-remotely browser dependent, please provide information about the
-affected browers as well.
-
-=head1 SEE ALSO
-
-L
-
-=cut
diff --git a/lib/Config/Tiny.pm b/lib/Config/Tiny.pm
deleted file mode 100644
index c543756..0000000
--- a/lib/Config/Tiny.pm
+++ /dev/null
@@ -1,248 +0,0 @@
-package Config::Tiny;
-
-# If you thought Config::Simple was small...
-
-use 5.004;
-use strict;
-
-use vars qw{$VERSION $errstr};
-BEGIN {
-	$VERSION = '2.00';
-	$errstr  = '';
-}
-
-# Create an empty object
-sub new { bless {}, shift }
-
-# Create an object from a file
-sub read {
-	my $class = ref $_[0] ? ref shift : shift;
-
-	# Check the file
-	my $file = shift or return $class->_error( 'You did not specify a file name' );
-	return $class->_error( "File '$file' does not exist" )              unless -e $file;
-	return $class->_error( "'$file' is a directory, not a file" )       unless -f _;
-	return $class->_error( "Insufficient permissions to read '$file'" ) unless -r _;
-
-	# Slurp in the file
-	local $/ = undef;
-	open CFG, $file or return $class->_error( "Failed to open file '$file': $!" );
-	my $contents = ;
-	close CFG;
-
-	$class->read_string( $contents );
-}
-
-# Create an object from a string
-sub read_string {
-	my $class = ref $_[0] ? ref shift : shift;
-	my $self  = bless {}, $class;
-	return undef unless defined $_[0];
-
-	# Parse the file
-	my $ns      = '_';
-	my $counter = 0;
-	foreach ( split /(?:\015{1,2}\012|\015|\012)/, shift ) {
-		$counter++;
-
-		# Skip comments and empty lines
-		next if /^\s*(?:\#|\;|$)/;
-
-		# Handle section headers
-		if ( /^\s*\[(.+?)\]\s*$/ ) {
-			# Create the sub-hash if it doesn't exist.
-			# Without this sections without keys will not
-			# appear at all in the completed struct.
-            $ns = $1;
-			$self->{$ns} = {};
-			next;
-		}
-
-		# Handle properties
-		if ( /^\s*([^=]+?)\s*=\s*(.*?)\s*$/ ) {
-			$self->{$ns}->{$1} = $2;
-			next;
-		}
-
-		return $self->_error( "Syntax error at line $counter: '$_'" );
-	}
-
-	$self;
-}
-
-# Save an object to a file
-sub write {
-	my $self = shift;
-	my $file = shift or return $self->_error( 'No file name provided' );
-
-	# Write it to the file
-	open( CFG, '>', $file )
-		or return $self->_error( "Failed to open file '$file' for writing: $!" );
-	print CFG $self->write_string;
-	close CFG;
-}
-
-# Save an object to a string
-sub write_string {
-	my $self = shift;
-
-	my $contents = '';
-	foreach my $section ( sort { (($b eq '_') <=> ($a eq '_')) || ($a cmp $b) } keys %$self ) {
-		my $block = $self->{$section};
-		$contents .= "\n" if length $contents;
-		$contents .= "[$section]\n" unless $section eq '_';
-		foreach my $property ( sort keys %$block ) {
-			$contents .= "$property=$block->{$property}\n";
-		}
-	}
-
-	$contents;
-}
-
-# Error handling
-sub errstr { $errstr }
-sub _error { $errstr = $_[1]; undef }
-
-1;
-
-__END__
-
-=pod
-
-=head1 NAME
-
-Config::Tiny - Read/Write .ini style files with as little code as possible
-
-=head1 SYNOPSIS
-
-    # In your configuration file
-    rootproperty=blah
-
-    [section]
-    one=twp
-    three= four
-    Foo =Bar
-    empty=
-
-    # In your program
-    use Config::Tiny;
-
-    # Create a config
-    my $Config = Config::Tiny->new();
-
-    # Open the config
-    $Config = Config::Tiny->read( 'file.conf' );
-
-    # Reading properties
-    my $rootproperty = $Config->{_}->{rootproperty};
-    my $one = $Config->{section}->{one};
-    my $Foo = $Config->{section}->{Foo};
-
-    # Changing data
-    $Config->{newsection} = { this => 'that' }; # Add a section
-    $Config->{section}->{Foo} = 'Not Bar!';     # Change a value
-    delete $Config->{_};                        # Delete a value or section
-
-    # Save a config
-    $Config->write( 'file.conf' );
-
-=head1 DESCRIPTION
-
-Config::Tiny is a perl class to read and write .ini style configuration files
-with as little code as possible, reducing load time and memory overhead.
-Memory usage is normally scoffed at in Perl, but in my opinion should be
-at least kept in mind.
-
-This module is primarily for reading human written files, and anything we
-write shouldn't need to have documentation/comments. If you need something
-with more power, move up to Config::Simple, Config::General or one of the
-many other Config:: modules. To rephrase, Config::Tiny does not preserve
-your comments, whitespace, or the order of your config file.
-
-=head1 CONFIGURATION FILE SYNTAX
-
-Files are the same as windows .ini files, for example.
-
-	[section]
-	var1=value1
-	var2=value2
-
-If a property is outside of a section, it will be assigned to the root
-section, available at C<$Config-E{_}>.
-
-Lines starting with '#' or ';' are comments, and blank lines are ignored.
-
-When writing back to the config file, any comments are discarded.
-
-=head1 METHODS
-
-=head2 new
-
-The constructor C creates and returns an empty Config::Tiny object.
-
-=head2 read $filename
-
-The C constructor reads a config file, and returns a new Config::Tiny
-object containing the properties in the file.
-
-Returns the object on success, or C on error.
-
-=head2 read_string $string;
-
-The C method takes as argument the contents of a config file as a string
-and returns the Config::Tiny object for it.
-
-=head2 write
-
-The C generates the file for the properties, and writes it
-to disk.
-
-Returns true on success or C on error.
-
-=head2 write_string
-
-Generates the file for the object and returns it as a string.
-
-=head2 errstr
-
-When an error occurs, you can retrieve the error message either from the
-C<$Config::Tiny::errstr> variable, or using the C method.
-
-=head1 SUPPORT
-
-Bugs should be reported via the CPAN bug tracker at
-
-  http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Config%3A%3ATiny
-
-For other issues, contact the author
-
-=head1 TO DO
-
-I'm debating adding a get and set method to get or set a section.key based
-value...
-
-Implementation is left as an exercise for the reader.
-
-=head1 AUTHOR
-
-        Adam Kennedy ( maintainer )
-        cpan@ali.as
-        http://ali.as/
-
-Thanks to Sherzod Ruzmetov  for Config::Simple,
-which inspired this module by being not quite "simple" enough for me :)
-
-=head1 SEE ALSO
-
-L, L
-
-=head1 COPYRIGHT
-
-Copyright 2002-2004 Adam Kennedy. All rights reserved.
-This program is free software; you can redistribute
-it and/or modify it under the same terms as Perl itself.
-
-The full text of the license can be found in the
-LICENSE file included with this module.
-
-=cut
diff --git a/lib/Date/Manip.pm b/lib/Date/Manip.pm
deleted file mode 100644
index 7a3f810..0000000
--- a/lib/Date/Manip.pm
+++ /dev/null
@@ -1,7362 +0,0 @@
-package Date::Manip;
-# Copyright (c) 1995-2003 Sullivan Beck.  All rights reserved.
-# This program is free software; you can redistribute it and/or modify it
-# under the same terms as Perl itself.
-
-###########################################################################
-###########################################################################
-
-use vars qw($OS %Lang %Holiday %Events %Curr %Cnf %Zone $VERSION @ISA @EXPORT);
-
-# Determine the type of OS...
-$OS="Unix";
-$OS="Windows"  if ((defined $^O and
-                    $^O =~ /MSWin32/i ||
-                    $^O =~ /Windows_95/i ||
-                    $^O =~ /Windows_NT/i) ||
-                   (defined $ENV{OS} and
-                    $ENV{OS} =~ /MSWin32/i ||
-                    $ENV{OS} =~ /Windows_95/i ||
-                    $ENV{OS} =~ /Windows_NT/i));
-$OS="Netware"  if (defined $^O and
-                   $^O =~ /NetWare/i);
-$OS="Mac"      if ((defined $^O and
-                    $^O =~ /MacOS/i) ||
-                   (defined $ENV{OS} and
-                    $ENV{OS} =~ /MacOS/i));
-$OS="MPE"      if (defined $^O and
-                   $^O =~ /MPE/i);
-$OS="OS2"      if (defined $^O and
-                   $^O =~ /os2/i);
-$OS="VMS"      if (defined $^O and
-                   $^O =~ /VMS/i);
-
-# Determine if we're doing taint checking
-$Date::Manip::NoTaint = eval { local $^W; unlink "$^X$^T"; 1 };
-
-###########################################################################
-# CUSTOMIZATION
-###########################################################################
-#
-# See the section of the POD documentation section CUSTOMIZING DATE::MANIP
-# below for a complete description of each of these variables.
-
-
-# Location of a the global config file.  Tilde (~) expansions are allowed.
-# This should be set in Date_Init arguments.
-$Cnf{"GlobalCnf"}="";
-$Cnf{"IgnoreGlobalCnf"}="";
-
-# Name of a personal config file and the path to search for it.  Tilde (~)
-# expansions are allowed.  This should be set in Date_Init arguments or in
-# the global config file.
-
-@Date::Manip::DatePath=();
-if ($OS eq "Windows") {
-  $Cnf{"PathSep"}         = ";";
-  $Cnf{"PersonalCnf"}     = "Manip.cnf";
-  $Cnf{"PersonalCnfPath"} = ".";
-
-} elsif ($OS eq "Netware") {
-  $Cnf{"PathSep"}         = ";";
-  $Cnf{"PersonalCnf"}     = "Manip.cnf";
-  $Cnf{"PersonalCnfPath"} = ".";
-
-} elsif ($OS eq "MPE") {
-  $Cnf{"PathSep"}         = ":";
-  $Cnf{"PersonalCnf"}     = "Manip.cnf";
-  $Cnf{"PersonalCnfPath"} = ".";
-
-} elsif ($OS eq "OS2") {
-  $Cnf{"PathSep"}         = ":";
-  $Cnf{"PersonalCnf"}     = "Manip.cnf";
-  $Cnf{"PersonalCnfPath"} = ".";
-
-} elsif ($OS eq "Mac") {
-  $Cnf{"PathSep"}         = ":";
-  $Cnf{"PersonalCnf"}     = "Manip.cnf";
-  $Cnf{"PersonalCnfPath"} = ".";
-
-} elsif ($OS eq "VMS") {
-  # VMS doesn't like files starting with "."
-  $Cnf{"PathSep"}         = "\n";
-  $Cnf{"PersonalCnf"}     = "Manip.cnf";
-  $Cnf{"PersonalCnfPath"} = ".\n~";
-
-} else {
-  # Unix
-  $Cnf{"PathSep"}         = ":";
-  $Cnf{"PersonalCnf"}     = ".DateManip.cnf";
-  $Cnf{"PersonalCnfPath"} = ".:~";
-  @Date::Manip::DatePath=qw(/bin /usr/bin /usr/local/bin);
-}
-
-### Date::Manip variables set in the global or personal config file
-
-# Which language to use when parsing dates.
-$Cnf{"Language"}="English";
-
-# 12/10 = Dec 10 (US) or Oct 12 (anything else)
-$Cnf{"DateFormat"}="US";
-
-# Local timezone
-$Cnf{"TZ"}="";
-
-# Timezone to work in (""=local, "IGNORE", or a timezone)
-$Cnf{"ConvTZ"}="";
-
-# Date::Manip internal format (0=YYYYMMDDHH:MN:SS, 1=YYYYHHMMDDHHMNSS)
-$Cnf{"Internal"}=0;
-
-# First day of the week (1=monday, 7=sunday).  ISO 8601 says monday.
-$Cnf{"FirstDay"}=1;
-
-# First and last day of the work week  (1=monday, 7=sunday)
-$Cnf{"WorkWeekBeg"}=1;
-$Cnf{"WorkWeekEnd"}=5;
-
-# If non-nil, a work day is treated as 24 hours long (WorkDayBeg/WorkDayEnd
-# ignored)
-$Cnf{"WorkDay24Hr"}=0;
-
-# Start and end time of the work day (any time format allowed, seconds
-# ignored)
-$Cnf{"WorkDayBeg"}="08:00";
-$Cnf{"WorkDayEnd"}="17:00";
-
-# If "today" is a holiday, we look either to "tomorrow" or "yesterday" for
-# the nearest business day.  By default, we'll always look "tomorrow"
-# first.
-$Cnf{"TomorrowFirst"}=1;
-
-# Erase the old holidays
-$Cnf{"EraseHolidays"}="";
-
-# Set this to non-zero to be produce completely backwards compatible deltas
-$Cnf{"DeltaSigns"}=0;
-
-# If this is 0, use the ISO 8601 standard that Jan 4 is in week 1.  If 1,
-# make week 1 contain Jan 1.
-$Cnf{"Jan1Week1"}=0;
-
-# 2 digit years fall into the 100 year period given by [ CURR-N,
-# CURR+(99-N) ] where N is 0-99.  Default behavior is 89, but other useful
-# numbers might be 0 (forced to be this year or later) and 99 (forced to be
-# this year or earlier).  It can also be set to "c" (current century) or
-# "cNN" (i.e.  c18 forces the year to bet 1800-1899).  Also accepts the
-# form cNNNN to give the 100 year period NNNN to NNNN+99.
-$Cnf{"YYtoYYYY"}=89;
-
-# Set this to 1 if you want a long-running script to always update the
-# timezone.  This will slow Date::Manip down.  Read the POD documentation.
-$Cnf{"UpdateCurrTZ"}=0;
-
-# Use an international character set.
-$Cnf{"IntCharSet"}=0;
-
-# Use this to force the current date to be set to this:
-$Cnf{"ForceDate"}="";
-
-###########################################################################
-
-require 5.000;
-require Exporter;
-@ISA = qw(Exporter);
-@EXPORT = qw(
-   DateManipVersion
-   Date_Init
-   ParseDateString
-   ParseDate
-   ParseRecur
-   Date_Cmp
-   DateCalc
-   ParseDateDelta
-   UnixDate
-   Delta_Format
-   Date_GetPrev
-   Date_GetNext
-   Date_SetTime
-   Date_SetDateField
-   Date_IsHoliday
-   Events_List
-
-   Date_DaysInMonth
-   Date_DayOfWeek
-   Date_SecsSince1970
-   Date_SecsSince1970GMT
-   Date_DaysSince1BC
-   Date_DayOfYear
-   Date_DaysInYear
-   Date_WeekOfYear
-   Date_LeapYear
-   Date_DaySuffix
-   Date_ConvTZ
-   Date_TimeZone
-   Date_IsWorkDay
-   Date_NextWorkDay
-   Date_PrevWorkDay
-   Date_NearestWorkDay
-   Date_NthDayOfYear
-);
-use strict;
-use integer;
-use Carp;
-
-use IO::File;
-
-$VERSION="5.42";
-
-########################################################################
-########################################################################
-
-$Curr{"InitLang"}      = 1;     # Whether a language is being init'ed
-$Curr{"InitDone"}      = 0;     # Whether Init_Date has been called
-$Curr{"InitFilesRead"} = 0;
-$Curr{"ResetWorkDay"}  = 1;
-$Curr{"Debug"}         = "";
-$Curr{"DebugVal"}      = "";
-
-$Holiday{"year"}       = 0;
-$Holiday{"dates"}      = {};
-$Holiday{"desc"}       = {};
-
-$Events{"raw"}         = [];
-$Events{"parsed"}      = 0;
-$Events{"dates"}       = [];
-$Events{"recur"}       = [];
-
-########################################################################
-########################################################################
-# THESE ARE THE MAIN ROUTINES
-########################################################################
-########################################################################
-
-# Get rid of a problem with old versions of perl
-no strict "vars";
-# This sorts from longest to shortest element
-sub sortByLength {
-  return (length $b <=> length $a);
-}
-use strict "vars";
-
-sub DateManipVersion {
-  print "DEBUG: DateManipVersion\n"  if ($Curr{"Debug"} =~ /trace/);
-  return $VERSION;
-}
-
-sub Date_Init {
-  print "DEBUG: Date_Init\n"  if ($Curr{"Debug"} =~ /trace/);
-  $Curr{"Debug"}="";
-
-  my(@args)=@_;
-  $Curr{"InitDone"}=1;
-  local($_)=();
-  my($internal,$firstday)=();
-  my($var,$val,$file,@tmp)=();
-
-  # InitFilesRead = 0    : no conf files read yet
-  #                 1    : global read, no personal read
-  #                 2    : personal read
-
-  $Cnf{"EraseHolidays"}=0;
-  foreach (@args) {
-    s/\s*$//;
-    s/^\s*//;
-    /^(\S+) \s* = \s* (.+)$/x;
-    ($var,$val)=($1,$2);
-    if ($var =~ /^GlobalCnf$/i) {
-      $Cnf{"GlobalCnf"}=$val;
-      if ($val) {
-        $Curr{"InitFilesRead"}=0;
-        &EraseHolidays();
-      }
-    } elsif ($var =~ /^PathSep$/i) {
-      $Cnf{"PathSep"}=$val;
-    } elsif ($var =~ /^PersonalCnf$/i) {
-      $Cnf{"PersonalCnf"}=$val;
-      $Curr{"InitFilesRead"}=1  if ($Curr{"InitFilesRead"}==2);
-    } elsif ($var =~ /^PersonalCnfPath$/i) {
-      $Cnf{"PersonalCnfPath"}=$val;
-      $Curr{"InitFilesRead"}=1  if ($Curr{"InitFilesRead"}==2);
-    } elsif ($var =~ /^IgnoreGlobalCnf$/i) {
-      $Curr{"InitFilesRead"}=1  if ($Curr{"InitFilesRead"}==0);
-      $Cnf{"IgnoreGlobalCnf"}=1;
-    } elsif ($var =~ /^EraseHolidays$/i) {
-      &EraseHolidays();
-    } else {
-      push(@tmp,$_);
-    }
-  }
-  @args=@tmp;
-
-  # Read global config file
-  if ($Curr{"InitFilesRead"}<1  &&  ! $Cnf{"IgnoreGlobalCnf"}) {
-    $Curr{"InitFilesRead"}=1;
-
-    if ($Cnf{"GlobalCnf"}) {
-      $file=&ExpandTilde($Cnf{"GlobalCnf"});
-      &Date_InitFile($file)  if ($file);
-    }
-  }
-
-  # Read personal config file
-  if ($Curr{"InitFilesRead"}<2) {
-    $Curr{"InitFilesRead"}=2;
-
-    if ($Cnf{"PersonalCnf"}  and  $Cnf{"PersonalCnfPath"}) {
-      $file=&SearchPath($Cnf{"PersonalCnf"},$Cnf{"PersonalCnfPath"},"r");
-      &Date_InitFile($file)  if ($file);
-    }
-  }
-
-  foreach (@args) {
-    s/\s*$//;
-    s/^\s*//;
-    /^(\S+) \s* = \s* (.*)$/x;
-    ($var,$val)=($1,$2);
-    $val=""  if (! defined $val);
-    &Date_SetConfigVariable($var,$val);
-  }
-
-  confess "ERROR: Unknown FirstDay in Date::Manip.\n"
-    if (! &IsInt($Cnf{"FirstDay"},1,7));
-  confess "ERROR: Unknown WorkWeekBeg in Date::Manip.\n"
-    if (! &IsInt($Cnf{"WorkWeekBeg"},1,7));
-  confess "ERROR: Unknown WorkWeekEnd in Date::Manip.\n"
-    if (! &IsInt($Cnf{"WorkWeekEnd"},1,7));
-  confess "ERROR: Invalid WorkWeek in Date::Manip.\n"
-    if ($Cnf{"WorkWeekEnd"} <= $Cnf{"WorkWeekBeg"});
-
-  my(%lang,
-     $tmp,%tmp,$tmp2,@tmp2,
-     $i,$j,@tmp3,
-     $zonesrfc,@zones)=();
-
-  my($L)=$Cnf{"Language"};
-
-  if ($Curr{"InitLang"}) {
-    $Curr{"InitLang"}=0;
-
-    if ($L eq "English") {
-      &Date_Init_English(\%lang);
-
-    } elsif ($L eq "French") {
-      &Date_Init_French(\%lang);
-
-    } elsif ($L eq "Swedish") {
-      &Date_Init_Swedish(\%lang);
-
-    } elsif ($L eq "German") {
-      &Date_Init_German(\%lang);
-
-    } elsif ($L eq "Polish") {
-      &Date_Init_Polish(\%lang);
-
-    } elsif ($L eq "Dutch"  ||
-             $L eq "Nederlands") {
-      &Date_Init_Dutch(\%lang);
-
-    } elsif ($L eq "Spanish") {
-      &Date_Init_Spanish(\%lang);
-
-    } elsif ($L eq "Portuguese") {
-      &Date_Init_Portuguese(\%lang);
-
-    } elsif ($L eq "Romanian") {
-      &Date_Init_Romanian(\%lang);
-
-    } elsif ($L eq "Italian") {
-      &Date_Init_Italian(\%lang);
-
-    } elsif ($L eq "Russian") {
-      &Date_Init_Russian(\%lang);
-
-    } elsif ($L eq "Turkish") {
-      &Date_Init_Turkish(\%lang);
-
-    } elsif ($L eq "Danish") {
-      &Date_Init_Danish(\%lang);
-
-    } else {
-      confess "ERROR: Unknown language in Date::Manip.\n";
-    }
-
-    #  variables for months
-    #   Month   = "(jan|january|feb|february ... )"
-    #   MonL    = [ "Jan","Feb",... ]
-    #   MonthL  = [ "January","February", ... ]
-    #   MonthH  = { "january"=>1, "jan"=>1, ... }
-
-    $Lang{$L}{"MonthH"}={};
-    $Lang{$L}{"MonthL"}=[];
-    $Lang{$L}{"MonL"}=[];
-    &Date_InitLists([$lang{"month_name"},
-                     $lang{"month_abb"}],
-                    \$Lang{$L}{"Month"},"lc,sort,back",
-                    [$Lang{$L}{"MonthL"},
-                     $Lang{$L}{"MonL"}],
-                    [$Lang{$L}{"MonthH"},1]);
-
-    #  variables for day of week
-    #   Week   = "(mon|monday|tue|tuesday ... )"
-    #   WL     = [ "M","T",... ]
-    #   WkL    = [ "Mon","Tue",... ]
-    #   WeekL  = [ "Monday","Tudesday",... ]
-    #   WeekH  = { "monday"=>1,"mon"=>1,"m"=>1,... }
-
-    $Lang{$L}{"WeekH"}={};
-    $Lang{$L}{"WeekL"}=[];
-    $Lang{$L}{"WkL"}=[];
-    $Lang{$L}{"WL"}=[];
-    &Date_InitLists([$lang{"day_name"},
-                     $lang{"day_abb"}],
-                    \$Lang{$L}{"Week"},"lc,sort,back",
-                    [$Lang{$L}{"WeekL"},
-                     $Lang{$L}{"WkL"}],
-                    [$Lang{$L}{"WeekH"},1]);
-    &Date_InitLists([$lang{"day_char"}],
-                    "","lc",
-                    [$Lang{$L}{"WL"}],
-                    [\%tmp,1]);
-    %{ $Lang{$L}{"WeekH"} } =
-      (%{ $Lang{$L}{"WeekH"} },%tmp);
-
-    #  variables for last
-    #   Last      = "(last)"
-    #   LastL     = [ "last" ]
-    #   Each      = "(each)"
-    #   EachL     = [ "each" ]
-    #  variables for day of month
-    #   DoM       = "(1st|first ... 31st)"
-    #   DoML      = [ "1st","2nd",... "31st" ]
-    #   DoMH      = { "1st"=>1,"first"=>1, ... "31st"=>31 }
-    #  variables for week of month
-    #   WoM       = "(1st|first| ... 5th|last)"
-    #   WoMH      = { "1st"=>1, ... "5th"=>5,"last"=>-1 }
-
-    $Lang{$L}{"LastL"}=$lang{"last"};
-    &Date_InitStrings($lang{"last"},
-                      \$Lang{$L}{"Last"},"lc,sort");
-
-    $Lang{$L}{"EachL"}=$lang{"each"};
-    &Date_InitStrings($lang{"each"},
-                      \$Lang{$L}{"Each"},"lc,sort");
-
-    $Lang{$L}{"DoMH"}={};
-    $Lang{$L}{"DoML"}=[];
-    &Date_InitLists([$lang{"num_suff"},
-                     $lang{"num_word"}],
-                    \$Lang{$L}{"DoM"},"lc,sort,back,escape",
-                    [$Lang{$L}{"DoML"},
-                     \@tmp],
-                    [$Lang{$L}{"DoMH"},1]);
-
-    @tmp=();
-    foreach $tmp (keys %{ $Lang{$L}{"DoMH"} }) {
-      $tmp2=$Lang{$L}{"DoMH"}{$tmp};
-      if ($tmp2<6) {
-        $Lang{$L}{"WoMH"}{$tmp} = $tmp2;
-        push(@tmp,$tmp);
-      }
-    }
-    foreach $tmp (@{ $Lang{$L}{"LastL"} }) {
-      $Lang{$L}{"WoMH"}{$tmp} = -1;
-      push(@tmp,$tmp);
-    }
-    &Date_InitStrings(\@tmp,\$Lang{$L}{"WoM"},
-                      "lc,sort,back,escape");
-
-    #  variables for AM or PM
-    #   AM      = "(am)"
-    #   PM      = "(pm)"
-    #   AmPm    = "(am|pm)"
-    #   AMstr   = "AM"
-    #   PMstr   = "PM"
-
-    &Date_InitStrings($lang{"am"},\$Lang{$L}{"AM"},"lc,sort,escape");
-    &Date_InitStrings($lang{"pm"},\$Lang{$L}{"PM"},"lc,sort,escape");
-    &Date_InitStrings([ @{$lang{"am"}},@{$lang{"pm"}} ],\$Lang{$L}{"AmPm"},
-                      "lc,back,sort,escape");
-    $Lang{$L}{"AMstr"}=$lang{"am"}[0];
-    $Lang{$L}{"PMstr"}=$lang{"pm"}[0];
-
-    #  variables for expressions used in parsing deltas
-    #    Yabb   = "(?:y|yr|year|years)"
-    #    Mabb   = similar for months
-    #    Wabb   = similar for weeks
-    #    Dabb   = similar for days
-    #    Habb   = similar for hours
-    #    MNabb  = similar for minutes
-    #    Sabb   = similar for seconds
-    #    Repl   = { "abb"=>"replacement" }
-    # Whenever an abbreviation could potentially refer to two different
-    # strings (M standing for Minutes or Months), the abbreviation must
-    # be listed in Repl instead of in the appropriate Xabb values.  This
-    # only applies to abbreviations which are substrings of other values
-    # (so there is no confusion between Mn and Month).
-
-    &Date_InitStrings($lang{"years"}  ,\$Lang{$L}{"Yabb"}, "lc,sort");
-    &Date_InitStrings($lang{"months"} ,\$Lang{$L}{"Mabb"}, "lc,sort");
-    &Date_InitStrings($lang{"weeks"}  ,\$Lang{$L}{"Wabb"}, "lc,sort");
-    &Date_InitStrings($lang{"days"}   ,\$Lang{$L}{"Dabb"}, "lc,sort");
-    &Date_InitStrings($lang{"hours"}  ,\$Lang{$L}{"Habb"}, "lc,sort");
-    &Date_InitStrings($lang{"minutes"},\$Lang{$L}{"MNabb"},"lc,sort");
-    &Date_InitStrings($lang{"seconds"},\$Lang{$L}{"Sabb"}, "lc,sort");
-    $Lang{$L}{"Repl"}={};
-    &Date_InitHash($lang{"replace"},undef,"lc",$Lang{$L}{"Repl"});
-
-    #  variables for special dates that are offsets from now
-    #    Now      = "(now|today)"
-    #    Offset   = "(yesterday|tomorrow)"
-    #    OffsetH  = { "yesterday"=>"-0:0:0:1:0:0:0",... ]
-    #    Times    = "(noon|midnight)"
-    #    TimesH   = { "noon"=>"12:00:00","midnight"=>"00:00:00" }
-    #    SepHM    = hour/minute separator
-    #    SepMS    = minute/second separator
-    #    SepSS    = second/fraction separator
-
-    $Lang{$L}{"TimesH"}={};
-    &Date_InitHash($lang{"times"},
-                   \$Lang{$L}{"Times"},"lc,sort,back",
-                   $Lang{$L}{"TimesH"});
-    &Date_InitStrings($lang{"now"},\$Lang{$L}{"Now"},"lc,sort");
-    $Lang{$L}{"OffsetH"}={};
-    &Date_InitHash($lang{"offset"},
-                   \$Lang{$L}{"Offset"},"lc,sort,back",
-                   $Lang{$L}{"OffsetH"});
-    $Lang{$L}{"SepHM"}=$lang{"sephm"};
-    $Lang{$L}{"SepMS"}=$lang{"sepms"};
-    $Lang{$L}{"SepSS"}=$lang{"sepss"};
-
-    #  variables for time zones
-    #    zones      = regular expression with all zone names (EST)
-    #    n2o        = a hash of all parsable zone names with their offsets
-    #    tzones     = reguar expression with all tzdata timezones (US/Eastern)
-    #    tz2z       = hash of all tzdata timezones to full timezone (EST#EDT)
-
-    $zonesrfc=
-      "idlw   -1200 ".  # International Date Line West
-      "nt     -1100 ".  # Nome
-      "hst    -1000 ".  # Hawaii Standard
-      "cat    -1000 ".  # Central Alaska
-      "ahst   -1000 ".  # Alaska-Hawaii Standard
-      "akst   -0900 ".  # Alaska Standard
-      "yst    -0900 ".  # Yukon Standard
-      "hdt    -0900 ".  # Hawaii Daylight
-      "akdt   -0800 ".  # Alaska Daylight
-      "ydt    -0800 ".  # Yukon Daylight
-      "pst    -0800 ".  # Pacific Standard
-      "pdt    -0700 ".  # Pacific Daylight
-      "mst    -0700 ".  # Mountain Standard
-      "mdt    -0600 ".  # Mountain Daylight
-      "cst    -0600 ".  # Central Standard
-      "cdt    -0500 ".  # Central Daylight
-      "est    -0500 ".  # Eastern Standard
-      "act    -0500 ".  # Brazil, Acre
-      "sat    -0400 ".  # Chile
-      "bot    -0400 ".  # Bolivia
-      "amt    -0400 ".  # Brazil, Amazon
-      "acst   -0400 ".  # Brazil, Acre Daylight
-      "edt    -0400 ".  # Eastern Daylight
-      "ast    -0400 ".  # Atlantic Standard
-      #"nst   -0330 ".  # Newfoundland Standard      nst=North Sumatra    +0630
-      "nft    -0330 ".  # Newfoundland
-      #"gst   -0300 ".  # Greenland Standard         gst=Guam Standard    +1000
-      #"bst   -0300 ".  # Brazil Standard            bst=British Summer   +0100
-      "brt    -0300 ".  # Brazil Standard (official time)
-      "brst   -0300 ".  # Brazil Standard
-      "adt    -0300 ".  # Atlantic Daylight
-      "art    -0300 ".  # Argentina
-      "amst   -0300 ".  # Brazil, Amazon Daylight
-      "ndt    -0230 ".  # Newfoundland Daylight
-      "brst   -0200 ".  # Brazil Daylight (official time)
-      "fnt    -0200 ".  # Brazil, Fernando de Noronha
-      "at     -0200 ".  # Azores
-      "wat    -0100 ".  # West Africa
-      "fnst   -0100 ".  # Brazil, Fernando de Noronha Daylight
-      "gmt    +0000 ".  # Greenwich Mean
-      "ut     +0000 ".  # Universal
-      "utc    +0000 ".  # Universal (Coordinated)
-      "wet    +0000 ".  # Western European
-      "cet    +0100 ".  # Central European
-      "fwt    +0100 ".  # French Winter
-      "met    +0100 ".  # Middle European
-      "mez    +0100 ".  # Middle European
-      "mewt   +0100 ".  # Middle European Winter
-      "swt    +0100 ".  # Swedish Winter
-      "bst    +0100 ".  # British Summer             bst=Brazil standard  -0300
-      "gb     +0100 ".  # GMT with daylight savings
-      "west   +0000 ".  # Western European Daylight
-      "eet    +0200 ".  # Eastern Europe, USSR Zone 1
-      "cest   +0200 ".  # Central European Summer
-      "fst    +0200 ".  # French Summer
-      "ist    +0200 ".  # Israel standard
-      "mest   +0200 ".  # Middle European Summer
-      "mesz   +0200 ".  # Middle European Summer
-      "metdst +0200 ".  # An alias for mest used by HP-UX
-      "sast   +0200 ".  # South African Standard
-      "sst    +0200 ".  # Swedish Summer             sst=South Sumatra    +0700
-      "bt     +0300 ".  # Baghdad, USSR Zone 2
-      "eest   +0300 ".  # Eastern Europe Summer
-      "eetedt +0300 ".  # Eastern Europe, USSR Zone 1
-      "idt    +0300 ".  # Israel Daylight
-      "msk    +0300 ".  # Moscow
-      "eat    +0300 ".  # East Africa
-      "it     +0330 ".  # Iran
-      "zp4    +0400 ".  # USSR Zone 3
-      "msd    +0400 ".  # Moscow Daylight
-      "zp5    +0500 ".  # USSR Zone 4
-      "ist    +0530 ".  # Indian Standard
-      "zp6    +0600 ".  # USSR Zone 5
-      "novst  +0600 ".  # Novosibirsk time zone, Russia
-      "nst    +0630 ".  # North Sumatra              nst=Newfoundland Std -0330
-      #"sst   +0700 ".  # South Sumatra, USSR Zone 6 sst=Swedish Summer   +0200
-      "javt   +0700 ".  # Java
-      "hkt    +0800 ".  # Hong Kong
-      "sgt    +0800 ".  # Singapore
-      "cct    +0800 ".  # China Coast, USSR Zone 7
-      "awst   +0800 ".  # Australian Western Standard
-      "wst    +0800 ".  # West Australian Standard
-      "pht    +0800 ".  # Asia Manila
-      "kst    +0900 ".  # Republic of Korea
-      "jst    +0900 ".  # Japan Standard, USSR Zone 8
-      "rok    +0900 ".  # Republic of Korea
-      "acst   +0930 ".  # Australian Central Standard
-      "cast   +0930 ".  # Central Australian Standard
-      "aest   +1000 ".  # Australian Eastern Standard
-      "east   +1000 ".  # Eastern Australian Standard
-      "gst    +1000 ".  # Guam Standard, USSR Zone 9 gst=Greenland Std    -0300
-      "acdt   +1030 ".  # Australian Central Daylight
-      "cadt   +1030 ".  # Central Australian Daylight
-      "aedt   +1100 ".  # Australian Eastern Daylight
-      "eadt   +1100 ".  # Eastern Australian Daylight
-      "idle   +1200 ".  # International Date Line East
-      "nzst   +1200 ".  # New Zealand Standard
-      "nzt    +1200 ".  # New Zealand
-      "nzdt   +1300 ".  # New Zealand Daylight
-      "z +0000 ".
-      "a +0100 b +0200 c +0300 d +0400 e +0500 f +0600 g +0700 h +0800 ".
-      "i +0900 k +1000 l +1100 m +1200 ".
-      "n -0100 o -0200 p -0300 q -0400 r -0500 s -0600 t -0700 u -0800 ".
-      "v -0900 w -1000 x -1100 y -1200";
-
-    $Zone{"n2o"} = {};
-    ($Zone{"zones"},%{ $Zone{"n2o"} })=
-      &Date_Regexp($zonesrfc,"sort,lc,under,back",
-                   "keys");
-
-    $tmp=
-      "US/Pacific  PST8PDT ".
-      "US/Mountain MST7MDT ".
-      "US/Central  CST6CDT ".
-      "US/Eastern  EST5EDT ".
-      "Canada/Pacific  PST8PDT ".
-      "Canada/Mountain MST7MDT ".
-      "Canada/Central  CST6CDT ".
-      "Canada/Eastern  EST5EDT";
-
-    $Zone{"tz2z"} = {};
-    ($Zone{"tzones"},%{ $Zone{"tz2z"} })=
-      &Date_Regexp($tmp,"lc,under,back","keys");
-    $Cnf{"TZ"}=&Date_TimeZone;
-
-    #  misc. variables
-    #    At     = "(?:at)"
-    #    Of     = "(?:in|of)"
-    #    On     = "(?:on)"
-    #    Future = "(?:in)"
-    #    Later  = "(?:later)"
-    #    Past   = "(?:ago)"
-    #    Next   = "(?:next)"
-    #    Prev   = "(?:last|previous)"
-
-    &Date_InitStrings($lang{"at"},    \$Lang{$L}{"At"},     "lc,sort");
-    &Date_InitStrings($lang{"on"},    \$Lang{$L}{"On"},     "lc,sort");
-    &Date_InitStrings($lang{"future"},\$Lang{$L}{"Future"}, "lc,sort");
-    &Date_InitStrings($lang{"later"}, \$Lang{$L}{"Later"},  "lc,sort");
-    &Date_InitStrings($lang{"past"},  \$Lang{$L}{"Past"},   "lc,sort");
-    &Date_InitStrings($lang{"next"},  \$Lang{$L}{"Next"},   "lc,sort");
-    &Date_InitStrings($lang{"prev"},  \$Lang{$L}{"Prev"},   "lc,sort");
-    &Date_InitStrings($lang{"of"},    \$Lang{$L}{"Of"},     "lc,sort");
-
-    #  calc mode variables
-    #    Approx   = "(?:approximately)"
-    #    Exact    = "(?:exactly)"
-    #    Business = "(?:business)"
-
-    &Date_InitStrings($lang{"exact"},   \$Lang{$L}{"Exact"},   "lc,sort");
-    &Date_InitStrings($lang{"approx"},  \$Lang{$L}{"Approx"},  "lc,sort");
-    &Date_InitStrings($lang{"business"},\$Lang{$L}{"Business"},"lc,sort");
-
-    ############### END OF LANGUAGE INITIALIZATION
-  }
-
-  if ($Curr{"ResetWorkDay"}) {
-    my($h1,$m1,$h2,$m2)=();
-    if ($Cnf{"WorkDay24Hr"}) {
-      ($Curr{"WDBh"},$Curr{"WDBm"})=(0,0);
-      ($Curr{"WDEh"},$Curr{"WDEm"})=(24,0);
-      $Curr{"WDlen"}=24*60;
-      $Cnf{"WorkDayBeg"}="00:00";
-      $Cnf{"WorkDayEnd"}="23:59";
-
-    } else {
-      confess "ERROR: Invalid WorkDayBeg in Date::Manip.\n"
-        if (! (($h1,$m1)=&CheckTime($Cnf{"WorkDayBeg"})));
-      $Cnf{"WorkDayBeg"}="$h1:$m1";
-      confess "ERROR: Invalid WorkDayEnd in Date::Manip.\n"
-        if (! (($h2,$m2)=&CheckTime($Cnf{"WorkDayEnd"})));
-      $Cnf{"WorkDayEnd"}="$h2:$m2";
-
-      ($Curr{"WDBh"},$Curr{"WDBm"})=($h1,$m1);
-      ($Curr{"WDEh"},$Curr{"WDEm"})=($h2,$m2);
-
-      # Work day length = h1:m1  or  0:len (len minutes)
-      $h1=$h2-$h1;
-      $m1=$m2-$m1;
-      if ($m1<0) {
-        $h1--;
-        $m1+=60;
-      }
-      $Curr{"WDlen"}=$h1*60+$m1;
-    }
-    $Curr{"ResetWorkDay"}=0;
-  }
-
-  # current time
-  my($s,$mn,$h,$d,$m,$y,$wday,$yday,$isdst,$ampm,$wk)=();
-  if ($Cnf{"ForceDate"}=~
-      /^(\d{4})-(\d{2})-(\d{2})-(\d{2}):(\d{2}):(\d{2})$/) {
-       ($y,$m,$d,$h,$mn,$s)=($1,$2,$3,$4,$5,$6);
-  } else {
-    ($s,$mn,$h,$d,$m,$y,$wday,$yday,$isdst)=localtime(time);
-    $y+=1900;
-    $m++;
-  }
-  &Date_DateCheck(\$y,\$m,\$d,\$h,\$mn,\$s,\$ampm,\$wk);
-  $Curr{"Y"}=$y;
-  $Curr{"M"}=$m;
-  $Curr{"D"}=$d;
-  $Curr{"H"}=$h;
-  $Curr{"Mn"}=$mn;
-  $Curr{"S"}=$s;
-  $Curr{"AmPm"}=$ampm;
-  $Curr{"Now"}=&Date_Join($y,$m,$d,$h,$mn,$s);
-
-  $Curr{"Debug"}=$Curr{"DebugVal"};
-
-  # If we're in array context, let's return a list of config variables
-  # that could be passed to Date_Init to get the same state as we're
-  # currently in.
-  if (wantarray) {
-    # Some special variables that have to be in a specific order
-    my(@special)=qw(IgnoreGlobalCnf GlobalCnf PersonalCnf PersonalCnfPath);
-    my(%tmp)=map { $_,1 } @special;
-    my(@tmp,$key,$val);
-    foreach $key (@special) {
-      $val=$Cnf{$key};
-      push(@tmp,"$key=$val");
-    }
-    foreach $key (keys %Cnf) {
-      next  if (exists $tmp{$key});
-      $val=$Cnf{$key};
-      push(@tmp,"$key=$val");
-    }
-    return @tmp;
-  }
-  return ();
-}
-
-sub ParseDateString {
-  print "DEBUG: ParseDateString\n"  if ($Curr{"Debug"} =~ /trace/);
-  local($_)=@_;
-  return ""  if (! $_);
-
-  my($y,$m,$d,$h,$mn,$s,$i,$wofm,$dofw,$wk,$tmp,$z,$num,$err,$iso,$ampm)=();
-  my($date,$z2,$delta,$from,$falsefrom,$to,$which,$midnight)=();
-
-  # We only need to reinitialize if we have to determine what NOW is.
-  &Date_Init()  if (! $Curr{"InitDone"}  or  $Cnf{"UpdateCurrTZ"});
-
-  my($L)=$Cnf{"Language"};
-  my($type)=$Cnf{"DateFormat"};
-
-  # Mode is set in DateCalc.  ParseDate only overrides it if the string
-  # contains a mode.
-  if      ($Lang{$L}{"Exact"}  &&
-           s/$Lang{$L}{"Exact"}//) {
-    $Curr{"Mode"}=0;
-  } elsif ($Lang{$L}{"Approx"}  &&
-           s/$Lang{$L}{"Approx"}//) {
-    $Curr{"Mode"}=1;
-  } elsif ($Lang{$L}{"Business"}  &&
-           s/$Lang{$L}{"Business"}//) {
-    $Curr{"Mode"}=2;
-  } elsif (! exists $Curr{"Mode"}) {
-    $Curr{"Mode"}=0;
-  }
-
-  # Unfortunately, some deltas can be parsed as dates.  An example is
-  #    1 second  ==  1 2nd  ==  1 2
-  # But, some dates can be parsed as deltas.  The most important being:
-  #    1998010101:00:00
-  # We'll check to see if a "date" can be parsed as a delta.  If so, we'll
-  # assume that it is a delta (since they are much simpler, it is much
-  # less likely that we'll mistake a delta for a date than vice versa)
-  # unless it is an ISO-8601 date.
-  #
-  # This is important because we are using DateCalc to test whether a
-  # string is a date or a delta.  Dates are tested first, so we need to
-  # be able to pass a delta into this routine and have it correctly NOT
-  # interpreted as a date.
-  #
-  # We will insist that the string contain something other than digits and
-  # colons so that the following will get correctly interpreted as a date
-  # rather than a delta:
-  #     12:30
-  #     19980101
-
-  $delta="";
-  $delta=&ParseDateDelta($_)  if (/[^:0-9]/);
-
-  # Put parse in a simple loop for an easy exit.
- PARSE: {
-    my(@tmp)=&Date_Split($_);
-    if (@tmp) {
-      ($y,$m,$d,$h,$mn,$s)=@tmp;
-      last PARSE;
-    }
-
-    # Fundamental regular expressions
-
-    my($month)=$Lang{$L}{"Month"};          # (jan|january|...)
-    my(%month)=%{ $Lang{$L}{"MonthH"} };    # { jan=>1, ... }
-    my($week)=$Lang{$L}{"Week"};            # (mon|monday|...)
-    my(%week)=%{ $Lang{$L}{"WeekH"} };      # { mon=>1, monday=>1, ... }
-    my($wom)=$Lang{$L}{"WoM"};              # (1st|...|fifth|last)
-    my(%wom)=%{ $Lang{$L}{"WoMH"} };        # { 1st=>1,... fifth=>5,last=>-1 }
-    my($dom)=$Lang{$L}{"DoM"};              # (1st|first|...31st)
-    my(%dom)=%{ $Lang{$L}{"DoMH"} };        # { 1st=>1, first=>1, ... }
-    my($ampmexp)=$Lang{$L}{"AmPm"};         # (am|pm)
-    my($timeexp)=$Lang{$L}{"Times"};        # (noon|midnight)
-    my($now)=$Lang{$L}{"Now"};              # (now|today)
-    my($offset)=$Lang{$L}{"Offset"};        # (yesterday|tomorrow)
-    my($zone)=$Zone{"zones"} . '(?:\s+|$)'; # (edt|est|...)\s+
-    my($day)='\s*'.$Lang{$L}{"Dabb"};       # \s*(?:d|day|days)
-    my($mabb)='\s*'.$Lang{$L}{"Mabb"};      # \s*(?:mon|month|months)
-    my($wkabb)='\s*'.$Lang{$L}{"Wabb"};     # \s*(?:w|wk|week|weeks)
-    my($next)='\s*'.$Lang{$L}{"Next"};      # \s*(?:next)
-    my($prev)='\s*'.$Lang{$L}{"Prev"};      # \s*(?:last|previous)
-    my($past)='\s*'.$Lang{$L}{"Past"};      # \s*(?:ago)
-    my($future)='\s*'.$Lang{$L}{"Future"};  # \s*(?:in)
-    my($later)='\s*'.$Lang{$L}{"Later"};    # \s*(?:later)
-    my($at)=$Lang{$L}{"At"};                # (?:at)
-    my($of)='\s*'.$Lang{$L}{"Of"};          # \s*(?:in|of)
-    my($on)='(?:\s*'.$Lang{$L}{"On"}.'\s*|\s+)';
-                                            # \s*(?:on)\s*    or  \s+
-    my($last)='\s*'.$Lang{$L}{"Last"};      # \s*(?:last)
-    my($hm)=$Lang{$L}{"SepHM"};             # :
-    my($ms)=$Lang{$L}{"SepMS"};             # :
-    my($ss)=$Lang{$L}{"SepSS"};             # .
-
-    # Other regular expressions
-
-    my($D4)='(\d{4})';            # 4 digits      (yr)
-    my($YY)='(\d{4}|\d{2})';      # 2 or 4 digits (yr)
-    my($DD)='(\d{2})';            # 2 digits      (mon/day/hr/min/sec)
-    my($D) ='(\d{1,2})';          # 1 or 2 digit  (mon/day/hr)
-    my($FS)="(?:$ss\\d+)?";       # fractional secs
-    my($sep)='[\/.-]';            # non-ISO8601 m/d/yy separators
-    # absolute time zone     +0700 (GMT)
-    my($hzone)='(?:[0-1][0-9]|2[0-3])';                    # 00 - 23
-    my($mzone)='(?:[0-5][0-9])';                           # 00 - 59
-    my($zone2)='(?:\s*([+-](?:'."$hzone$mzone|$hzone:$mzone|$hzone))".
-                                                           # +0700 +07:00 -07
-      '(?:\s*\([^)]+\))?)';                                # (GMT)
-
-    # A regular expression for the time EXCEPT for the hour part
-    my($mnsec)="$hm$DD(?:$ms$DD$FS)?(?:\\s*$ampmexp)?";
-
-    # A special regular expression for /YYYY:HH:MN:SS used by Apache
-    my($apachetime)='(/\d{4}):' . "$DD$hm$DD$ms$DD";
-
-    my($time)="";
-    $ampm="";
-    $date="";
-
-    # Substitute all special time expressions.
-    if (/(^|[^a-z])$timeexp($|[^a-z])/i) {
-      $tmp=$2;
-      $tmp=$Lang{$L}{"TimesH"}{lc($tmp)};
-      s/(^|[^a-z])$timeexp($|[^a-z])/$1 $tmp $3/i;
-    }
-
-    # Remove some punctuation
-    s/[,]/ /g;
-
-    # Make sure that ...7EST works (i.e. a timezone immediately following
-    # a digit.
-    s/(\d)$zone(\s+|$|[0-9])/$1 $2$3/i;
-    $zone = '\s+'.$zone;
-
-    # Remove the time
-    $iso=1;
-    $midnight=0;
-    $from="24${hm}00(?:${ms}00)?";
-    $falsefrom="${hm}24${ms}00";   # Don't trap XX:24:00
-    $to="00${hm}00${ms}00";
-    $midnight=1  if (!/$falsefrom/  &&  s/$from/$to/);
-
-    $h=$mn=$s=0;
-    if (/$D$mnsec/i || /$ampmexp/i) {
-      $iso=0;
-      $tmp=0;
-      $tmp=1  if (/$mnsec$zone2?\s*$/i);  # or /$mnsec$zone/ ??
-      $tmp=0  if (/$ampmexp/i);
-      if (s/$apachetime$zone()/$1 /i                            ||
-          s/$apachetime$zone2?/$1 /i                            ||
-          s/(^|[^a-z])$at\s*$D$mnsec$zone()/$1 /i               ||
-          s/(^|[^a-z])$at\s*$D$mnsec$zone2?/$1 /i               ||
-          s/(^|[^0-9])(\d)$mnsec$zone()/$1 /i                   ||
-          s/(^|[^0-9])(\d)$mnsec$zone2?/$1 /i                   ||
-          (s/(t)$D$mnsec$zone()/$1 /i and (($iso=-$tmp) || 1))  ||
-          (s/(t)$D$mnsec$zone2?/$1 /i and (($iso=-$tmp) || 1))  ||
-          (s/()$DD$mnsec$zone()/ /i and (($iso=$tmp) || 1))     ||
-          (s/()$DD$mnsec$zone2?/ /i and (($iso=$tmp) || 1))     ||
-          s/(^|$at\s*|\s+)$D()()\s*$ampmexp$zone()/ /i          ||
-          s/(^|$at\s*|\s+)$D()()\s*$ampmexp$zone2?/ /i          ||
-          0
-         ) {
-        ($h,$mn,$s,$ampm,$z,$z2)=($2,$3,$4,$5,$6,$7);
-        if (defined ($z)) {
-          if ($z =~ /^[+-]\d{2}:\d{2}$/) {
-            $z=~ s/://;
-          } elsif ($z =~ /^[+-]\d{2}$/) {
-            $z .= "00";
-          }
-        }
-        $time=1;
-        &Date_TimeCheck(\$h,\$mn,\$s,\$ampm);
-        $y=$m=$d="";
-        # We're going to be calling TimeCheck again below (when we check the
-        # final date), so get rid of $ampm so that we don't have an error
-        # due to "15:30:00 PM".  It'll get reset below.
-        $ampm="";
-        if (/^\s*$/) {
-          &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-          last PARSE;
-        }
-      }
-    }
-    $time=0  if ($time ne "1");
-    s/\s+$//;
-    s/^\s+//;
-
-    # dateTtime ISO 8601 formats
-    my($orig)=$_;
-    s/t$//i  if ($iso<0);
-
-    # Parse ISO 8601 dates now (which may still have a zone stuck to it).
-    if ( ($iso && /^([0-9-]+(?:W[0-9-]+)?)$zone?$/i)   ||
-         ($iso && /^([0-9-]+(?:W[0-9-]+)?)$zone2?$/i)  ||
-         ($iso && /^([0-9-]+(?:T[0-9-]+)?)$zone?$/i)   ||
-         ($iso && /^([0-9-]+(?:T[0-9-]+)?)$zone2?$/i)  ||
-         0) {
-
-      # ISO 8601 dates
-      ($_,$z,$z2) = ($1,$2);
-      s,-, ,g;            # Change all ISO8601 seps to spaces
-      s/^\s+//;
-      s/\s+$//;
-
-      if (/^$D4\s*$DD\s*$DD\s*t?$DD(?:$DD(?:$DD(\d*))?)?$/i ||
-          /^$DD\s+$DD\s*$DD\s*t?$DD(?:$DD(?:$DD(\d*))?)?$/i ||
-          0
-         ) {
-        # ISO 8601 Dates with times
-        #    YYYYMMDDHHMNSSFFFF...
-        #    YYYYMMDDHHMNSS
-        #    YYYYMMDDHHMN
-        #    YYYYMMDDHH
-        #    YY MMDDHHMNSSFFFF...
-        #    YY MMDDHHMNSS
-        #    YY MMDDHHMN
-        #    YY MMDDHH
-        ($y,$m,$d,$h,$mn,$s,$tmp)=($1,$2,$3,$4,$5,$6,$7);
-        if ($h==24 && (! defined $mn || $mn==0) && (! defined $s || $s==0)) {
-          $h=0;
-          $midnight=1;
-        }
-        $z = ""    if (! defined $h);
-        return ""  if ($time  &&  defined $h);
-        last PARSE;
-
-      } elsif (/^$D4(?:\s*$DD(?:\s*$DD)?)?$/  ||
-               /^$DD(?:\s+$DD(?:\s*$DD)?)?$/) {
-        # ISO 8601 Dates
-        #    YYYYMMDD
-        #    YYYYMM
-        #    YYYY
-        #    YY MMDD
-        #    YY MM
-        #    YY
-        ($y,$m,$d)=($1,$2,$3);
-        last PARSE;
-
-      } elsif (/^$YY\s+$D\s+$D/) {
-        # YY-M-D
-        ($y,$m,$d)=($1,$2,$3);
-        last PARSE;
-
-      } elsif (/^$YY\s*W$DD\s*(\d)?$/i) {
-        # YY-W##-D
-        ($y,$wofm,$dofw)=($1,$2,$3);
-        ($y,$m,$d)=&Date_NthWeekOfYear($y,$wofm,$dofw);
-        last PARSE;
-
-      } elsif (/^$D4\s*(\d{3})$/ ||
-               /^$DD\s*(\d{3})$/) {
-        # YYDOY
-        ($y,$which)=($1,$2);
-        ($y,$m,$d)=&Date_NthDayOfYear($y,$which);
-        last PARSE;
-
-      } elsif ($iso<0) {
-        # We confused something like 1999/August12:00:00
-        # with a dateTtime format
-        $_=$orig;
-
-      } else {
-        return "";
-      }
-    }
-
-    # All deltas that are not ISO-8601 dates are NOT dates.
-    return ""  if ($Curr{"InCalc"}  &&  $delta);
-    if ($delta) {
-      &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-      return &DateCalc_DateDelta($Curr{"Now"},$delta);
-    }
-
-    # Check for some special types of dates (next, prev)
-    foreach $from (keys %{ $Lang{$L}{"Repl"} }) {
-      $to=$Lang{$L}{"Repl"}{$from};
-      s/(^|[^a-z])$from($|[^a-z])/$1$to$2/i;
-    }
-    if (/$wom/i  ||  /$future/i  ||  /$later/i  ||  /$past/i  ||
-        /$next/i  ||  /$prev/i  ||  /^$week$/i  ||  /$wkabb/i) {
-      $tmp=0;
-
-      if (/^$wom\s*$week$of\s*$month\s*$YY?$/i) {
-        # last friday in October 95
-        ($wofm,$dofw,$m,$y)=($1,$2,$3,$4);
-        # fix $m, $y
-        return ""  if (&Date_DateCheck(\$y,\$m,\$d,\$h,\$mn,\$s,\$ampm,\$wk));
-        $dofw=$week{lc($dofw)};
-        $wofm=$wom{lc($wofm)};
-        # Get the first day of the month
-        $date=&Date_Join($y,$m,1,$h,$mn,$s);
-        if ($wofm==-1) {
-          $date=&DateCalc_DateDelta($date,"+0:1:0:0:0:0:0",\$err,0);
-          $date=&Date_GetPrev($date,$dofw,0);
-        } else {
-          for ($i=0; $i<$wofm; $i++) {
-            if ($i==0) {
-              $date=&Date_GetNext($date,$dofw,1);
-            } else {
-              $date=&Date_GetNext($date,$dofw,0);
-            }
-          }
-        }
-        last PARSE;
-
-      } elsif (/^$last$day$of\s*$month(?:$of?\s*$YY)?/i) {
-        # last day in month
-        ($m,$y)=($1,$2);
-        &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-        $y=&Date_FixYear($y)  if (! defined $y  or  length($y)<4);
-        $m=$month{lc($m)};
-        $d=&Date_DaysInMonth($m,$y);
-        last PARSE;
-
-      } elsif (/^$week$/i) {
-        # friday
-        ($dofw)=($1);
-        &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-        $date=&Date_GetPrev($Curr{"Now"},$Cnf{"FirstDay"},1);
-        $date=&Date_GetNext($date,$dofw,1,$h,$mn,$s);
-        last PARSE;
-
-      } elsif (/^$next\s*$week$/i) {
-        # next friday
-        ($dofw)=($1);
-        &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-        $date=&Date_GetNext($Curr{"Now"},$dofw,0,$h,$mn,$s);
-        last PARSE;
-
-      } elsif (/^$prev\s*$week$/i) {
-        # last friday
-        ($dofw)=($1);
-        &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-        $date=&Date_GetPrev($Curr{"Now"},$dofw,0,$h,$mn,$s);
-        last PARSE;
-
-      } elsif (/^$next$wkabb$/i) {
-        # next week
-        &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-        $date=&DateCalc_DateDelta($Curr{"Now"},"+0:0:1:0:0:0:0",\$err,0);
-        $date=&Date_SetTime($date,$h,$mn,$s)  if (defined $h);
-        last PARSE;
-      } elsif (/^$prev$wkabb$/i) {
-        # last week
-        &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-        $date=&DateCalc_DateDelta($Curr{"Now"},"-0:0:1:0:0:0:0",\$err,0);
-        $date=&Date_SetTime($date,$h,$mn,$s)  if (defined $h);
-        last PARSE;
-
-      } elsif (/^$next$mabb$/i) {
-        # next month
-        &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-        $date=&DateCalc_DateDelta($Curr{"Now"},"+0:1:0:0:0:0:0",\$err,0);
-        $date=&Date_SetTime($date,$h,$mn,$s)  if (defined $h);
-        last PARSE;
-      } elsif (/^$prev$mabb$/i) {
-        # last month
-        &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-        $date=&DateCalc_DateDelta($Curr{"Now"},"-0:1:0:0:0:0:0",\$err,0);
-        $date=&Date_SetTime($date,$h,$mn,$s)  if (defined $h);
-        last PARSE;
-
-      } elsif (/^$future\s*(\d+)$day$/i  ||
-               /^(\d+)$day$later$/i) {
-        # in 2 days
-        # 2 days later
-        ($num)=($1);
-        &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-        $date=&DateCalc_DateDelta($Curr{"Now"},"+0:0:0:$num:0:0:0",
-                                  \$err,0);
-        $date=&Date_SetTime($date,$h,$mn,$s)  if (defined $h);
-        last PARSE;
-      } elsif (/^(\d+)$day$past$/i) {
-        # 2 days ago
-        ($num)=($1);
-        &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-        $date=&DateCalc_DateDelta($Curr{"Now"},"-0:0:0:$num:0:0:0",
-                                 \$err,0);
-        $date=&Date_SetTime($date,$h,$mn,$s)  if (defined $h);
-        last PARSE;
-
-      } elsif (/^$future\s*(\d+)$wkabb$/i  ||
-               /^(\d+)$wkabb$later$/i) {
-        # in 2 weeks
-        # 2 weeks later
-        ($num)=($1);
-        &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-        $date=&DateCalc_DateDelta($Curr{"Now"},"+0:0:$num:0:0:0:0",
-                                  \$err,0);
-        $date=&Date_SetTime($date,$h,$mn,$s)  if (defined $h);
-        last PARSE;
-      } elsif (/^(\d+)$wkabb$past$/i) {
-        # 2 weeks ago
-        ($num)=($1);
-        &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-        $date=&DateCalc_DateDelta($Curr{"Now"},"-0:0:$num:0:0:0:0",
-                                 \$err,0);
-        $date=&Date_SetTime($date,$h,$mn,$s)  if (defined $h);
-        last PARSE;
-
-      } elsif (/^$future\s*(\d+)$mabb$/i  ||
-               /^(\d+)$mabb$later$/i) {
-        # in 2 months
-        # 2 months later
-        ($num)=($1);
-        &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-        $date=&DateCalc_DateDelta($Curr{"Now"},"+0:$num:0:0:0:0:0",
-                                  \$err,0);
-        $date=&Date_SetTime($date,$h,$mn,$s)  if (defined $h);
-        last PARSE;
-      } elsif (/^(\d+)$mabb$past$/i) {
-        # 2 months ago
-        ($num)=($1);
-        &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-        $date=&DateCalc_DateDelta($Curr{"Now"},"-0:$num:0:0:0:0:0",
-                                  \$err,0);
-        $date=&Date_SetTime($date,$h,$mn,$s)  if (defined $h);
-        last PARSE;
-
-      } elsif (/^$week$future\s*(\d+)$wkabb$/i  ||
-               /^$week\s*(\d+)$wkabb$later$/i) {
-        # friday in 2 weeks
-        # friday 2 weeks later
-        ($dofw,$num)=($1,$2);
-        $tmp="+";
-      } elsif (/^$week\s*(\d+)$wkabb$past$/i) {
-        # friday 2 weeks ago
-        ($dofw,$num)=($1,$2);
-        $tmp="-";
-      } elsif (/^$future\s*(\d+)$wkabb$on$week$/i  ||
-               /^(\d+)$wkabb$later$on$week$/i) {
-        # in 2 weeks on friday
-        # 2 weeks later on friday
-        ($num,$dofw)=($1,$2);
-        $tmp="+"
-      } elsif (/^(\d+)$wkabb$past$on$week$/i) {
-        # 2 weeks ago on friday
-        ($num,$dofw)=($1,$2);
-        $tmp="-";
-      } elsif (/^$week\s*$wkabb$/i) {
-        # monday week    (British date: in 1 week on monday)
-        $dofw=$1;
-        $num=1;
-        $tmp="+";
-      } elsif (/^$now\s*$wkabb$/i) {
-        # today week     (British date: 1 week from today)
-        &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-        $date=&DateCalc_DateDelta($Curr{"Now"},"+0:0:1:0:0:0:0",\$err,0);
-        $date=&Date_SetTime($date,$h,$mn,$s)  if (defined $h);
-        last PARSE;
-      } elsif (/^$offset\s*$wkabb$/i) {
-        # tomorrow week  (British date: 1 week from tomorrow)
-        ($offset)=($1);
-        &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-        $offset=$Lang{$L}{"OffsetH"}{lc($offset)};
-        $date=&DateCalc_DateDelta($Curr{"Now"},$offset,\$err,0);
-        $date=&DateCalc_DateDelta($date,"+0:0:1:0:0:0:0",\$err,0);
-        if ($time) {
-          return ""
-            if (&Date_DateCheck(\$y,\$m,\$d,\$h,\$mn,\$s,\$ampm,\$wk));
-          $date=&Date_SetTime($date,$h,$mn,$s);
-        }
-        last PARSE;
-      }
-
-      if ($tmp) {
-        &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-        $date=&DateCalc_DateDelta($Curr{"Now"},
-                                  $tmp . "0:0:$num:0:0:0:0",\$err,0);
-        $date=&Date_GetPrev($date,$Cnf{"FirstDay"},1);
-        $date=&Date_GetNext($date,$dofw,1,$h,$mn,$s);
-        last PARSE;
-      }
-    }
-
-    # Change (2nd, second) to 2
-    $tmp=0;
-    if (/(^|[^a-z0-9])$dom($|[^a-z0-9])/i) {
-      if (/^\s*$dom\s*$/) {
-        ($d)=($1);
-        $d=$dom{lc($d)};
-        $m=$Curr{"M"};
-        last PARSE;
-      }
-      my $from = $2;
-      my $to   = $dom{ lc($from) };
-      s/(^|[^a-z])$from($|[^a-z])/$1 $to $2/i;
-      s/^\s+//;
-      s/\s+$//;
-    }
-
-    # Another set of special dates (Nth week)
-    if (/^$D\s*$week(?:$of?\s*$YY)?$/i) {
-      # 22nd sunday in 1996
-      ($which,$dofw,$y)=($1,$2,$3);
-      $y=$Curr{"Y"}  if (! $y);
-      $y--; # previous year
-      $tmp=&Date_GetNext("$y-12-31",$dofw,0);
-      if ($which>1) {
-        $tmp=&DateCalc_DateDelta($tmp,"+0:0:".($which-1).":0:0:0:0",\$err,0);
-      }
-      ($y,$m,$d)=(&Date_Split($tmp, 1))[0..2];
-      last PARSE;
-    } elsif (/^$week$wkabb\s*$D(?:$of?\s*$YY)?$/i  ||
-             /^$week\s*$D$wkabb(?:$of?\s*$YY)?$/i) {
-      # sunday week 22 in 1996
-      # sunday 22nd week in 1996
-      ($dofw,$which,$y)=($1,$2,$3);
-      ($y,$m,$d)=&Date_NthWeekOfYear($y,$which,$dofw);
-      last PARSE;
-    }
-
-    # Get rid of day of week
-    if (/(^|[^a-z])$week($|[^a-z])/i) {
-      $wk=$2;
-      (s/(^|[^a-z])$week,/$1 /i) ||
-        s/(^|[^a-z])$week($|[^a-z])/$1 $3/i;
-      s/^\s+//;
-      s/\s+$//;
-    }
-
-    {
-      # So that we can handle negative epoch times, let's convert
-      # things like "epoch -" to "epochNEGATIVE " before we strip out
-      # the $sep chars, which include '-'.
-      s,epoch\s*-,epochNEGATIVE ,g;
-
-      # Non-ISO8601 dates
-      s,\s*$sep\s*, ,g;     # change all non-ISO8601 seps to spaces
-      s,^\s*,,;             # remove leading/trailing space
-      s,\s*$,,;
-
-      if (/^$D\s+$D(?:\s+$YY)?$/) {
-        # MM DD YY (DD MM YY non-US)
-        ($m,$d,$y)=($1,$2,$3);
-        ($m,$d)=($d,$m)  if ($type ne "US");
-        last PARSE;
-
-      } elsif (/^$D4\s*$D\s*$D$/) {
-        # YYYY MM DD
-        ($y,$m,$d)=($1,$2,$3);
-        last PARSE;
-
-      } elsif (s/(^|[^a-z])$month($|[^a-z])/$1 $3/i) {
-        ($m)=($2);
-
-        if (/^\s*$D(?:\s+$YY)?\s*$/) {
-          # mmm DD YY
-          # DD mmm YY
-          # DD YY mmm
-          ($d,$y)=($1,$2);
-          last PARSE;
-
-        } elsif (/^\s*$D$D4\s*$/) {
-          # mmm DD YYYY
-          # DD mmm YYYY
-          # DD YYYY mmm
-          ($d,$y)=($1,$2);
-          last PARSE;
-
-        } elsif (/^\s*$D4\s*$D\s*$/) {
-          # mmm YYYY DD
-          # YYYY mmm DD
-          # YYYY DD mmm
-          ($y,$d)=($1,$2);
-          last PARSE;
-
-        } elsif (/^\s*$D4\s*$/) {
-          # mmm YYYY
-          # YYYY mmm
-          ($y,$d)=($1,1);
-          last PARSE;
-
-        } else {
-          return "";
-        }
-
-      } elsif (/^epochNEGATIVE (\d+)$/) {
-        $s=$1;
-        $date=&DateCalc("1970-01-01 00:00 GMT","-0:0:$s");
-      } elsif (/^epoch\s*(\d+)$/i) {
-        $s=$1;
-        $date=&DateCalc("1970-01-01 00:00 GMT","+0:0:$s");
-
-      } elsif (/^$now$/i) {
-        # now, today
-        &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-        $date=$Curr{"Now"};
-        if ($time) {
-          return ""
-            if (&Date_DateCheck(\$y,\$m,\$d,\$h,\$mn,\$s,\$ampm,\$wk));
-          $date=&Date_SetTime($date,$h,$mn,$s);
-        }
-        last PARSE;
-
-      } elsif (/^$offset$/i) {
-        # yesterday, tomorrow
-        ($offset)=($1);
-        &Date_Init()  if (! $Cnf{"UpdateCurrTZ"});
-        $offset=$Lang{$L}{"OffsetH"}{lc($offset)};
-        $date=&DateCalc_DateDelta($Curr{"Now"},$offset,\$err,0);
-        if ($time) {
-          return ""
-            if (&Date_DateCheck(\$y,\$m,\$d,\$h,\$mn,\$s,\$ampm,\$wk));
-          $date=&Date_SetTime($date,$h,$mn,$s);
-        }
-        last PARSE;
-
-      } else {
-        return "";
-      }
-    }
-  }
-
-  if (! $date) {
-    return ""  if (&Date_DateCheck(\$y,\$m,\$d,\$h,\$mn,\$s,\$ampm,\$wk));
-    $date=&Date_Join($y,$m,$d,$h,$mn,$s);
-  }
-  $date=&Date_ConvTZ($date,$z);
-  if ($midnight) {
-    $date=&DateCalc_DateDelta($date,"+0:0:0:1:0:0:0");
-  }
-  return $date;
-}
-
-sub ParseDate {
-  print "DEBUG: ParseDate\n"  if ($Curr{"Debug"} =~ /trace/);
-  &Date_Init()  if (! $Curr{"InitDone"});
-  my($args,@args,@a,$ref,$date)=();
-  @a=@_;
-
-  # @a : is the list of args to ParseDate.  Currently, only one argument
-  #      is allowed and it must be a scalar (or a reference to a scalar)
-  #      or a reference to an array.
-
-  if ($#a!=0) {
-    print "ERROR:  Invalid number of arguments to ParseDate.\n";
-    return "";
-  }
-  $args=$a[0];
-  $ref=ref $args;
-  if (! $ref) {
-    return $args  if (&Date_Split($args));
-    @args=($args);
-  } elsif ($ref eq "ARRAY") {
-    @args=@$args;
-  } elsif ($ref eq "SCALAR") {
-    return $$args  if (&Date_Split($$args));
-    @args=($$args);
-  } else {
-    print "ERROR:  Invalid arguments to ParseDate.\n";
-    return "";
-  }
-  @a=@args;
-
-  # @args : a list containing all the arguments (dereferenced if appropriate)
-  # @a    : a list containing all the arguments currently being examined
-  # $ref  : nil, "SCALAR", or "ARRAY" depending on whether a scalar, a
-  #         reference to a scalar, or a reference to an array was passed in
-  # $args : the scalar or refererence passed in
-
- PARSE: while($#a>=0) {
-    $date=join(" ",@a);
-    $date=&ParseDateString($date);
-    last  if ($date);
-    pop(@a);
-  } # PARSE
-
-  splice(@args,0,$#a + 1);
-  @$args= @args  if (defined $ref  and  $ref eq "ARRAY");
-  $date;
-}
-
-sub Date_Cmp {
-  my($D1,$D2)=@_;
-  my($date1)=&ParseDateString($D1);
-  my($date2)=&ParseDateString($D2);
-  return $date1 cmp $date2;
-}
-
-# **NOTE**
-# The calc routines all call parse routines, so it is never necessary to
-# call Date_Init in the calc routines.
-sub DateCalc {
-  print "DEBUG: DateCalc\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($D1,$D2,@arg)=@_;
-  my($ref,$err,$errref,$mode)=();
-
-  $errref=shift(@arg);
-  $ref=0;
-  if (defined $errref) {
-    if (ref $errref) {
-      $mode=shift(@arg);
-      $ref=1;
-    } else {
-      $mode=$errref;
-      $errref="";
-    }
-  }
-
-  my(@date,@delta,$ret,$tmp,$old)=();
-
-  if (defined $mode  and  $mode>=0  and  $mode<=3) {
-    $Curr{"Mode"}=$mode;
-  } else {
-    $Curr{"Mode"}=0;
-  }
-
-  $old=$Curr{"InCalc"};
-  $Curr{"InCalc"}=1;
-
-  if ($tmp=&ParseDateString($D1)) {
-    # If we've already parsed the date, we don't want to do it a second
-    # time (so we don't convert timezones twice).
-    if (&Date_Split($D1)) {
-      push(@date,$D1);
-    } else {
-      push(@date,$tmp);
-    }
-  } elsif ($tmp=&ParseDateDelta($D1)) {
-    push(@delta,$tmp);
-  } else {
-    $$errref=1  if ($ref);
-    return;
-  }
-
-  if ($tmp=&ParseDateString($D2)) {
-    if (&Date_Split($D2)) {
-      push(@date,$D2);
-    } else {
-      push(@date,$tmp);
-    }
-  } elsif ($tmp=&ParseDateDelta($D2)) {
-    push(@delta,$tmp);
-  } else {
-    $$errref=2  if ($ref);
-    return;
-  }
-  $mode=$Curr{"Mode"};
-  $Curr{"InCalc"}=$old;
-
-  if ($#date==1) {
-    $ret=&DateCalc_DateDate(@date,$mode);
-  } elsif ($#date==0) {
-    $ret=&DateCalc_DateDelta(@date,@delta,\$err,$mode);
-    $$errref=$err  if ($ref);
-  } else {
-    $ret=&DateCalc_DeltaDelta(@delta,$mode);
-  }
-  $ret;
-}
-
-sub ParseDateDelta {
-  print "DEBUG: ParseDateDelta\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($args,@args,@a,$ref)=();
-  local($_)=();
-  @a=@_;
-
-  # @a : is the list of args to ParseDateDelta.  Currently, only one argument
-  #      is allowed and it must be a scalar (or a reference to a scalar)
-  #      or a reference to an array.
-
-  if ($#a!=0) {
-    print "ERROR:  Invalid number of arguments to ParseDateDelta.\n";
-    return "";
-  }
-  $args=$a[0];
-  $ref=ref $args;
-  if (! $ref) {
-    @args=($args);
-  } elsif ($ref eq "ARRAY") {
-    @args=@$args;
-  } elsif ($ref eq "SCALAR") {
-    @args=($$args);
-  } else {
-    print "ERROR:  Invalid arguments to ParseDateDelta.\n";
-    return "";
-  }
-  @a=@args;
-
-  # @args : a list containing all the arguments (dereferenced if appropriate)
-  # @a    : a list containing all the arguments currently being examined
-  # $ref  : nil, "SCALAR", or "ARRAY" depending on whether a scalar, a
-  #         reference to a scalar, or a reference to an array was passed in
-  # $args : the scalar or refererence passed in
-
-  my(@colon,@delta,$delta,$dir,$colon,$sign,$val)=();
-  my($len,$tmp,$tmp2,$tmpl)=();
-  my($from,$to)=();
-  my($workweek)=$Cnf{"WorkWeekEnd"}-$Cnf{"WorkWeekBeg"}+1;
-
-  &Date_Init()  if (! $Curr{"InitDone"});
-  # A sign can be a sequence of zero or more + and - signs, this
-  # allows for deltas like '+ -2 days'.
-  my($signexp)='((?:[+-]\s*)*)';
-  my($numexp)='(\d+)';
-  my($exp1)="(?: \\s* $signexp \\s* $numexp \\s*)";
-  my($yexp,$mexp,$wexp,$dexp,$hexp,$mnexp,$sexp,$i)=();
-  $yexp=$mexp=$wexp=$dexp=$hexp=$mnexp=$sexp="()()";
-  $yexp ="(?: $exp1 ". $Lang{$Cnf{"Language"}}{"Yabb"} .")?";
-  $mexp ="(?: $exp1 ". $Lang{$Cnf{"Language"}}{"Mabb"} .")?";
-  $wexp ="(?: $exp1 ". $Lang{$Cnf{"Language"}}{"Wabb"} .")?";
-  $dexp ="(?: $exp1 ". $Lang{$Cnf{"Language"}}{"Dabb"} .")?";
-  $hexp ="(?: $exp1 ". $Lang{$Cnf{"Language"}}{"Habb"} .")?";
-  $mnexp="(?: $exp1 ". $Lang{$Cnf{"Language"}}{"MNabb"}.")?";
-  $sexp ="(?: $exp1 ". $Lang{$Cnf{"Language"}}{"Sabb"} ."?)?";
-  my($future)=$Lang{$Cnf{"Language"}}{"Future"};
-  my($later)=$Lang{$Cnf{"Language"}}{"Later"};
-  my($past)=$Lang{$Cnf{"Language"}}{"Past"};
-
-  $delta="";
- PARSE: while (@a) {
-    $_ = join(" ", grep {defined;} @a);
-    s/\s+$//;
-    last  if ($_ eq "");
-
-    # Mode is set in DateCalc.  ParseDateDelta only overrides it if the
-    # string contains a mode.
-    if      ($Lang{$Cnf{"Language"}}{"Exact"} &&
-             s/$Lang{$Cnf{"Language"}}{"Exact"}//) {
-      $Curr{"Mode"}=0;
-    } elsif ($Lang{$Cnf{"Language"}}{"Approx"} &&
-             s/$Lang{$Cnf{"Language"}}{"Approx"}//) {
-      $Curr{"Mode"}=1;
-    } elsif ($Lang{$Cnf{"Language"}}{"Business"} &&
-             s/$Lang{$Cnf{"Language"}}{"Business"}//) {
-      $Curr{"Mode"}=2;
-    } elsif (! exists $Curr{"Mode"}) {
-      $Curr{"Mode"}=0;
-    }
-    $workweek=7  if ($Curr{"Mode"} != 2);
-
-    foreach $from (keys %{ $Lang{$Cnf{"Language"}}{"Repl"} }) {
-      $to=$Lang{$Cnf{"Language"}}{"Repl"}{$from};
-      s/(^|[^a-z])$from($|[^a-z])/$1$to$2/i;
-    }
-
-    # in or ago
-    #
-    # We need to make sure that $later, $future, and $past don't contain each
-    # other... Romanian pointed this out where $past is "in urma" and $future
-    # is "in".  When they do, we have to take this into account.
-    #   $len  length of best match (greatest wins)
-    #   $tmp  string after best match
-    #   $dir  direction (prior, after) of best match
-    #
-    #   $tmp2 string before/after current match
-    #   $tmpl length of current match
-
-    $len=0;
-    $tmp=$_;
-    $dir=1;
-
-    $tmp2=$_;
-    if ($tmp2 =~ s/(^|[^a-z])($future)($|[^a-z])/$1 $3/i) {
-      $tmpl=length($2);
-      if ($tmpl>$len) {
-        $tmp=$tmp2;
-        $dir=1;
-        $len=$tmpl;
-      }
-    }
-
-    $tmp2=$_;
-    if ($tmp2 =~ s/(^|[^a-z])($later)($|[^a-z])/$1 $3/i) {
-      $tmpl=length($2);
-      if ($tmpl>$len) {
-        $tmp=$tmp2;
-        $dir=1;
-        $len=$tmpl;
-      }
-    }
-
-    $tmp2=$_;
-    if ($tmp2 =~ s/(^|[^a-z])($past)($|[^a-z])/$1 $3/i) {
-      $tmpl=length($2);
-      if ($tmpl>$len) {
-        $tmp=$tmp2;
-        $dir=-1;
-        $len=$tmpl;
-      }
-    }
-
-    $_ = $tmp;
-    s/\s*$//;
-
-    # the colon part of the delta
-    $colon="";
-    if (s/($signexp?$numexp?(:($signexp?$numexp)?){1,6})$//) {
-      $colon=$1;
-      s/\s+$//;
-    }
-    @colon=split(/:/,$colon);
-
-    # the non-colon part of the delta
-    $sign="+";
-    @delta=();
-    $i=6;
-    foreach $exp1 ($yexp,$mexp,$wexp,$dexp,$hexp,$mnexp,$sexp) {
-      last  if ($#colon>=$i--);
-      $val=0;
-      if (s/^$exp1//ix) {
-        $val=$2   if ($2);
-        $sign=$1  if ($1);
-      }
-
-      # Collapse a sign like '+ -' into a single character like '-',
-      # by counting the occurrences of '-'.
-      #
-      $sign =~ s/\s+//g;
-      $sign =~ tr/+//d;
-      my $count = ($sign =~ tr/-//d);
-      die "bad characters in sign: $sign" if length $sign;
-      $sign = $count % 2 ? '-' : '+';
-
-      push(@delta,"$sign$val");
-    }
-    if (! /^\s*$/) {
-      pop(@a);
-      next PARSE;
-    }
-
-    # make sure that the colon part has a sign
-    for ($i=0; $i<=$#colon; $i++) {
-      $val=0;
-      if ($colon[$i] =~ /^$signexp$numexp?/) {
-        $val=$2   if ($2);
-        $sign=$1  if ($1);
-      }
-      $colon[$i] = "$sign$val";
-    }
-
-    # combine the two
-    push(@delta,@colon);
-    if ($dir<0) {
-      for ($i=0; $i<=$#delta; $i++) {
-        $delta[$i] =~ tr/-+/+-/;
-      }
-    }
-
-    # form the delta and shift off the valid part
-    $delta=join(":",@delta);
-    splice(@args,0,$#a+1);
-    @$args=@args  if (defined $ref  and  $ref eq "ARRAY");
-    last PARSE;
-  }
-
-  $delta=&Delta_Normalize($delta,$Curr{"Mode"});
-  return $delta;
-}
-
-sub UnixDate {
-  print "DEBUG: UnixDate\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($date,@format)=@_;
-  local($_)=();
-  my($format,%f,$out,@out,$c,$date1,$date2,$tmp)=();
-  my($scalar)=();
-  $date=&ParseDateString($date);
-  return  if (! $date);
-
-  my($y,$m,$d,$h,$mn,$s)=($f{"Y"},$f{"m"},$f{"d"},$f{"H"},$f{"M"},$f{"S"})=
-    &Date_Split($date, 1);
-  $f{"y"}=substr $f{"Y"},2;
-  &Date_Init()  if (! $Curr{"InitDone"});
-
-  if (! wantarray) {
-    $format=join(" ",@format);
-    @format=($format);
-    $scalar=1;
-  }
-
-  # month, week
-  $_=$m;
-  s/^0//;
-  $f{"b"}=$f{"h"}=$Lang{$Cnf{"Language"}}{"MonL"}[$_-1];
-  $f{"B"}=$Lang{$Cnf{"Language"}}{"MonthL"}[$_-1];
-  $_=$m;
-  s/^0/ /;
-  $f{"f"}=$_;
-  $f{"U"}=&Date_WeekOfYear($m,$d,$y,7);
-  $f{"W"}=&Date_WeekOfYear($m,$d,$y,1);
-
-  # check week 52,53 and 0
-  $f{"G"}=$f{"L"}=$y;
-  if ($f{"W"}>=52 || $f{"U"}>=52) {
-    my($dd,$mm,$yy)=($d,$m,$y);
-    $dd+=7;
-    if ($dd>31) {
-      $dd-=31;
-      $mm=1;
-      $yy++;
-      if (&Date_WeekOfYear($mm,$dd,$yy,1)==2) {
-        $f{"G"}=$yy;
-        $f{"W"}=1;
-      }
-      if (&Date_WeekOfYear($mm,$dd,$yy,7)==2) {
-        $f{"L"}=$yy;
-        $f{"U"}=1;
-      }
-    }
-  }
-  if ($f{"W"}==0) {
-    my($dd,$mm,$yy)=($d,$m,$y);
-    $dd-=7;
-    $dd+=31  if ($dd<1);
-    $yy--;
-    $mm=12;
-    $f{"G"}=$yy;
-    $f{"W"}=&Date_WeekOfYear($mm,$dd,$yy,1)+1;
-  }
-  if ($f{"U"}==0) {
-    my($dd,$mm,$yy)=($d,$m,$y);
-    $dd-=7;
-    $dd+=31  if ($dd<1);
-    $yy--;
-    $mm=12;
-    $f{"L"}=$yy;
-    $f{"U"}=&Date_WeekOfYear($mm,$dd,$yy,7)+1;
-  }
-
-  $f{"U"}="0".$f{"U"}  if (length $f{"U"} < 2);
-  $f{"W"}="0".$f{"W"}  if (length $f{"W"} < 2);
-
-  # day
-  $f{"j"}=&Date_DayOfYear($m,$d,$y);
-  $f{"j"} = "0" . $f{"j"}   while (length($f{"j"})<3);
-  $_=$d;
-  s/^0/ /;
-  $f{"e"}=$_;
-  $f{"w"}=&Date_DayOfWeek($m,$d,$y);
-  $f{"v"}=$Lang{$Cnf{"Language"}}{"WL"}[$f{"w"}-1];
-  $f{"v"}=" ".$f{"v"}  if (length $f{"v"} < 2);
-  $f{"a"}=$Lang{$Cnf{"Language"}}{"WkL"}[$f{"w"}-1];
-  $f{"A"}=$Lang{$Cnf{"Language"}}{"WeekL"}[$f{"w"}-1];
-  $f{"E"}=&Date_DaySuffix($f{"e"});
-
-  # hour
-  $_=$h;
-  s/^0/ /;
-  $f{"k"}=$_;
-  $f{"i"}=$f{"k"}+1;
-  $f{"i"}=$f{"k"};
-  $f{"i"}=12          if ($f{"k"}==0);
-  $f{"i"}=$f{"k"}-12  if ($f{"k"}>12);
-  $f{"i"}=$f{"i"}-12  if ($f{"i"}>12);
-  $f{"i"}=" ".$f{"i"} if (length($f{"i"})<2);
-  $f{"I"}=$f{"i"};
-  $f{"I"}=~ s/^ /0/;
-  $f{"p"}=$Lang{$Cnf{"Language"}}{"AMstr"};
-  $f{"p"}=$Lang{$Cnf{"Language"}}{"PMstr"}  if ($f{"k"}>11);
-
-  # minute, second, timezone
-  $f{"o"}=&Date_SecsSince1970($m,$d,$y,$h,$mn,$s);
-  $f{"s"}=&Date_SecsSince1970GMT($m,$d,$y,$h,$mn,$s);
-  $f{"Z"}=($Cnf{"ConvTZ"} eq "IGNORE" or $Cnf{"ConvTZ"} eq "") ?
-           $Cnf{"TZ"} : $Cnf{"ConvTZ"};
-  $f{"z"}=($f{"Z"}=~/^[+-]\d{4}/) ? $f{"Z"} : ($Zone{"n2o"}{lc $f{"Z"}} || "");
-
-  # date, time
-  $f{"c"}=qq|$f{"a"} $f{"b"} $f{"e"} $h:$mn:$s $y|;
-  $f{"C"}=$f{"u"}=
-    qq|$f{"a"} $f{"b"} $f{"e"} $h:$mn:$s $f{"z"} $y|;
-  $f{"g"}=qq|$f{"a"}, $d $f{"b"} $y $h:$mn:$s $f{"z"}|;
-  $f{"D"}=$f{"x"}=qq|$m/$d/$f{"y"}|;
-  $f{"r"}=qq|$f{"I"}:$mn:$s $f{"p"}|;
-  $f{"R"}=qq|$h:$mn|;
-  $f{"T"}=$f{"X"}=qq|$h:$mn:$s|;
-  $f{"V"}=qq|$m$d$h$mn$f{"y"}|;
-  $f{"Q"}="$y$m$d";
-  $f{"q"}=qq|$y$m$d$h$mn$s|;
-  $f{"P"}=qq|$y$m$d$h:$mn:$s|;
-  $f{"F"}=qq|$f{"A"}, $f{"B"} $f{"e"}, $f{"Y"}|;
-  if ($f{"W"}==0) {
-    $y--;
-    $tmp=&Date_WeekOfYear(12,31,$y,1);
-    $tmp="0$tmp"  if (length($tmp) < 2);
-    $f{"J"}=qq|$y-W$tmp-$f{"w"}|;
-  } else {
-    $f{"J"}=qq|$f{"G"}-W$f{"W"}-$f{"w"}|;
-  }
-  $f{"K"}=qq|$y-$f{"j"}|;
-  # %l is a special case.  Since it requires the use of the calculator
-  # which requires this routine, an infinite recursion results.  To get
-  # around this, %l is NOT determined every time this is called so the
-  # recursion breaks.
-
-  # other formats
-  $f{"n"}="\n";
-  $f{"t"}="\t";
-  $f{"%"}="%";
-  $f{"+"}="+";
-
-  foreach $format (@format) {
-    $format=reverse($format);
-    $out="";
-    while ($format ne "") {
-      $c=chop($format);
-      if ($c eq "%") {
-        $c=chop($format);
-        if ($c eq "l") {
-          &Date_Init();
-          $date1=&DateCalc_DateDelta($Curr{"Now"},"-0:6:0:0:0:0:0");
-          $date2=&DateCalc_DateDelta($Curr{"Now"},"+0:6:0:0:0:0:0");
-          if (&Date_Cmp($date,$date1)>=0  &&  &Date_Cmp($date,$date2)<=0) {
-            $f{"l"}=qq|$f{"b"} $f{"e"} $h:$mn|;
-          } else {
-            $f{"l"}=qq|$f{"b"} $f{"e"}  $f{"Y"}|;
-          }
-          $out .= $f{"$c"};
-        } elsif (exists $f{"$c"}) {
-          $out .= $f{"$c"};
-        } else {
-          $out .= $c;
-        }
-      } else {
-        $out .= $c;
-      }
-    }
-    push(@out,$out);
-  }
-  if ($scalar) {
-    return $out[0];
-  } else {
-    return (@out);
-  }
-}
-
-# Can't be in "use integer" because we're doing decimal arithmatic
-no integer;
-sub Delta_Format {
-  print "DEBUG: Delta_Format\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($delta,$dec,@format)=@_;
-  $delta=&ParseDateDelta($delta);
-  return ""  if (! $delta);
-  my(@out,%f,$out,$c1,$c2,$scalar,$format)=();
-  local($_)=$delta;
-  my($y,$M,$w,$d,$h,$m,$s)=&Delta_Split($delta);
-  # Get rid of positive signs.
-  ($y,$M,$w,$d,$h,$m,$s)=map { 1*$_; }($y,$M,$w,$d,$h,$m,$s);
-
-  if (defined $dec  &&  $dec>0) {
-    $dec="%." . ($dec*1) . "f";
-  } else {
-    $dec="%f";
-  }
-
-  if (! wantarray) {
-    $format=join(" ",@format);
-    @format=($format);
-    $scalar=1;
-  }
-
-  # Length of each unit in seconds
-  my($sl,$ml,$hl,$dl,$wl,$yl)=();
-  $sl = 1;
-  $ml = $sl*60;
-  $hl = $ml*60;
-  $dl = $hl*24;
-  $wl = $dl*7;
-  $yl = $dl*365.25;
-
-  # The decimal amount of each unit contained in all smaller units
-  my($yd,$Md,$sd,$md,$hd,$dd,$wd)=();
-  if ($M) {
-    $yd = $M/12;
-    $Md = 0;
-  } else {
-    $yd = ($w*$wl + $d*$dl + $h*$hl + $m*$ml + $s*$sl)/$yl;
-    $Md = 0;
-  }
-
-  $wd = ($d*$dl + $h*$hl + $m*$ml + $s*$sl)/$wl;
-  $dd =          ($h*$hl + $m*$ml + $s*$sl)/$dl;
-  $hd =                   ($m*$ml + $s*$sl)/$hl;
-  $md =                            ($s*$sl)/$ml;
-  $sd = 0;
-
-  # The amount of each unit contained in higher units.
-  my($yh,$Mh,$sh,$mh,$hh,$dh,$wh)=();
-  $yh = 0;
-
-  if ($M) {
-    $Mh = ($yh+$y)*12;
-    $wh = 0;
-    $dh = ($wh+$w)*7;
-  } else {
-    $Mh = 0;
-    $wh = ($yh+$y)*365.25/7;
-    $dh = ($yh+$y)*365.25 + $w*7;
-  }
-
-  $hh = ($dh+$d)*24;
-  $mh = ($hh+$h)*60;
-  $sh = ($mh+$m)*60;
-
-  # Set up the formats
-
-  $f{"yv"} = $y;
-  $f{"Mv"} = $M;
-  $f{"wv"} = $w;
-  $f{"dv"} = $d;
-  $f{"hv"} = $h;
-  $f{"mv"} = $m;
-  $f{"sv"} = $s;
-
-  $f{"yh"} = $y+$yh;
-  $f{"Mh"} = $M+$Mh;
-  $f{"wh"} = $w+$wh;
-  $f{"dh"} = $d+$dh;
-  $f{"hh"} = $h+$hh;
-  $f{"mh"} = $m+$mh;
-  $f{"sh"} = $s+$sh;
-
-  $f{"yd"} = sprintf($dec,$y+$yd);
-  $f{"Md"} = sprintf($dec,$M+$Md);
-  $f{"wd"} = sprintf($dec,$w+$wd);
-  $f{"dd"} = sprintf($dec,$d+$dd);
-  $f{"hd"} = sprintf($dec,$h+$hd);
-  $f{"md"} = sprintf($dec,$m+$md);
-  $f{"sd"} = sprintf($dec,$s+$sd);
-
-  $f{"yt"} = sprintf($dec,$yh+$y+$yd);
-  $f{"Mt"} = sprintf($dec,$Mh+$M+$Md);
-  $f{"wt"} = sprintf($dec,$wh+$w+$wd);
-  $f{"dt"} = sprintf($dec,$dh+$d+$dd);
-  $f{"ht"} = sprintf($dec,$hh+$h+$hd);
-  $f{"mt"} = sprintf($dec,$mh+$m+$md);
-  $f{"st"} = sprintf($dec,$sh+$s+$sd);
-
-  $f{"%"}  = "%";
-
-  foreach $format (@format) {
-    $format=reverse($format);
-    $out="";
-  PARSE: while ($format) {
-      $c1=chop($format);
-      if ($c1 eq "%") {
-        $c1=chop($format);
-        if (exists($f{$c1})) {
-          $out .= $f{$c1};
-          next PARSE;
-        }
-        $c2=chop($format);
-        if (exists($f{"$c1$c2"})) {
-          $out .= $f{"$c1$c2"};
-          next PARSE;
-        }
-        $out .= $c1;
-        $format .= $c2;
-      } else {
-        $out .= $c1;
-      }
-    }
-    push(@out,$out);
-  }
-  if ($scalar) {
-    return $out[0];
-  } else {
-    return (@out);
-  }
-}
-use integer;
-
-sub ParseRecur {
-  print "DEBUG: ParseRecur\n"  if ($Curr{"Debug"} =~ /trace/);
-  &Date_Init()  if (! $Curr{"InitDone"});
-
-  my($recur,$dateb,$date0,$date1,$flag)=@_;
-  local($_)=$recur;
-
-  my($recur_0,$recur_1,@recur0,@recur1)=();
-  my(@tmp,$tmp,$each,$num,$y,$m,$d,$w,$h,$mn,$s,$delta,$y0,$y1,$yb)=();
-  my($yy,$n,$dd,@d,@tmp2,$date,@date,@w,@tmp3,@m,@y,$tmp2,$d2,@flags)=();
-
-  # $date0, $date1, $dateb, $flag : passed in (these are always the final say
-  #                                 in determining whether a date matches a
-  #                                 recurrence IF they are present.
-  # $date_b, $date_0, $date_1     : if a value can be determined from the
-  # $flag_t                         recurrence, they are stored here.
-  #
-  # If values can be determined from the recurrence AND are passed in, the
-  # following are used:
-  #    max($date0,$date_0)    i.e. the later of the two dates
-  #    min($date1,$date_1)    i.e. the earlier of the two dates
-  #
-  # The base date that is used is the first one defined from
-  #    $dateb $date_b
-  # The base date is only used if necessary (as determined by the recur).
-  # For example, "every other friday" requires a base date, but "2nd
-  # friday of every month" doesn't.
-
-  my($date_b,$date_0,$date_1,$flag_t);
-
-  #
-  # Check the arguments passed in.
-  #
-
-  $date0=""  if (! defined $date0);
-  $date1=""  if (! defined $date1);
-  $dateb=""  if (! defined $dateb);
-  $flag =""  if (! defined $flag);
-
-  if ($dateb) {
-    $dateb=&ParseDateString($dateb);
-    return ""  if (! $dateb);
-  }
-  if ($date0) {
-    $date0=&ParseDateString($date0);
-    return ""  if (! $date0);
-  }
-  if ($date1) {
-    $date1=&ParseDateString($date1);
-    return ""  if (! $date1);
-  }
-
-  #
-  # Parse the recur.  $date_b, $date_0, and $date_e are values obtained
-  # from the recur.
-  #
-
-  @tmp=&Recur_Split($_);
-
-  if (@tmp) {
-    ($recur_0,$recur_1,$flag_t,$date_b,$date_0,$date_1)=@tmp;
-    $recur_0 = ""  if (! defined $recur_0);
-    $recur_1 = ""  if (! defined $recur_1);
-    $flag_t  = ""  if (! defined $flag_t);
-    $date_b  = ""  if (! defined $date_b);
-    $date_0  = ""  if (! defined $date_0);
-    $date_1  = ""  if (! defined $date_1);
-
-    @recur0 = split(/:/,$recur_0);
-    @recur1 = split(/:/,$recur_1);
-    return ""  if ($#recur0 + $#recur1 + 2 != 7);
-
-    if ($date_b) {
-      $date_b=&ParseDateString($date_b);
-      return ""  if (! $date_b);
-    }
-    if ($date_0) {
-      $date_0=&ParseDateString($date_0);
-      return ""  if (! $date_0);
-    }
-    if ($date_1) {
-      $date_1=&ParseDateString($date_1);
-      return ""  if (! $date_1);
-    }
-
-  } else {
-
-    my($mmm)='\s*'.$Lang{$Cnf{"Language"}}{"Month"};  # \s*(jan|january|...)
-    my(%mmm)=%{ $Lang{$Cnf{"Language"}}{"MonthH"} };  # { jan=>1, ... }
-    my($wkexp)='\s*'.$Lang{$Cnf{"Language"}}{"Week"}; # \s*(mon|monday|...)
-    my(%week)=%{ $Lang{$Cnf{"Language"}}{"WeekH"} };  # { monday=>1, ... }
-    my($day)='\s*'.$Lang{$Cnf{"Language"}}{"Dabb"};   # \s*(?:d|day|days)
-    my($month)='\s*'.$Lang{$Cnf{"Language"}}{"Mabb"}; # \s*(?:mon|month|months)
-    my($week)='\s*'.$Lang{$Cnf{"Language"}}{"Wabb"};  # \s*(?:w|wk|week|weeks)
-    my($daysexp)=$Lang{$Cnf{"Language"}}{"DoM"};      # (1st|first|...31st)
-    my(%dayshash)=%{ $Lang{$Cnf{"Language"}}{"DoMH"} };
-                                                      # { 1st=>1,first=>1,...}
-    my($of)='\s*'.$Lang{$Cnf{"Language"}}{"Of"};      # \s*(?:in|of)
-    my($lastexp)=$Lang{$Cnf{"Language"}}{"Last"};     # (?:last)
-    my($each)=$Lang{$Cnf{"Language"}}{"Each"};        # (?:each|every)
-
-    my($D)='\s*(\d+)';
-    my($Y)='\s*(\d{4}|\d{2})';
-
-    # Change 1st to 1
-    if (/(^|[^a-z])$daysexp($|[^a-z])/i) {
-      $tmp=lc($2);
-      $tmp=$dayshash{"$tmp"};
-      s/(^|[^a-z])$daysexp($|[^a-z])/$1 $tmp $3/i;
-    }
-    s/\s*$//;
-
-    # Get rid of "each"
-    if (/(^|[^a-z])$each($|[^a-z])/i) {
-      s/(^|[^a-z])$each($|[^a-z])/$1 $2/i;
-      $each=1;
-    } else {
-      $each=0;
-    }
-
-    if ($each) {
-
-      if (/^$D?$day(?:$of$mmm?$Y)?$/i ||
-          /^$D?$day(?:$of$mmm())?$/i) {
-        # every [2nd] day in [june] 1997
-        # every [2nd] day [in june]
-        ($num,$m,$y)=($1,$2,$3);
-        $num=1 if (! defined $num);
-        $m=""  if (! defined $m);
-        $y=""  if (! defined $y);
-
-        $y=$Curr{"Y"}  if (! $y);
-        if ($m) {
-          $m=$mmm{lc($m)};
-          $date_0=&Date_Join($y,$m,1,0,0,0);
-          $date_1=&DateCalc_DateDelta($date_0,"+0:1:0:0:0:0:0",0);
-        } else {
-          $date_0=&Date_Join($y,  1,1,0,0,0);
-          $date_1=&Date_Join($y+1,1,1,0,0,0);
-        }
-        $date_b=&DateCalc($date_0,"-0:0:0:1:0:0:0",0);
-        @recur0=(0,0,0,$num,0,0,0);
-        @recur1=();
-
-      } elsif (/^$D$day?$of$month(?:$of?$Y)?$/) {
-        # 2nd [day] of every month [in 1997]
-        ($num,$y)=($1,$2);
-        $y=$Curr{"Y"}  if (! $y);
-
-        $date_0=&Date_Join($y,  1,1,0,0,0);
-        $date_1=&Date_Join($y+1,1,1,0,0,0);
-        $date_b=$date_0;
-
-        @recur0=(0,1,0);
-        @recur1=($num,0,0,0);
-
-      } elsif (/^$D$wkexp$of$month(?:$of?$Y)?$/ ||
-               /^($lastexp)$wkexp$of$month(?:$of?$Y)?$/) {
-        # 2nd tuesday of every month [in 1997]
-        # last tuesday of every month [in 1997]
-        ($num,$d,$y)=($1,$2,$3);
-        $y=$Curr{"Y"}  if (! $y);
-        $d=$week{lc($d)};
-        $num=-1  if ($num !~ /^$D$/);
-
-        $date_0=&Date_Join($y,1,1,0,0,0);
-        $date_1=&Date_Join($y+1,1,1,0,0,0);
-        $date_b=$date_0;
-
-        @recur0=(0,1);
-        @recur1=($num,$d,0,0,0);
-
-      } elsif (/^$D?$wkexp(?:$of$mmm?$Y)?$/i ||
-               /^$D?$wkexp(?:$of$mmm())?$/i) {
-        # every tuesday in june 1997
-        # every 2nd tuesday in june 1997
-        ($num,$d,$m,$y)=($1,$2,$3,$4);
-        $y=$Curr{"Y"}  if (! $y);
-        $num=1 if (! defined $num);
-        $m=""  if (! defined $m);
-        $d=$week{lc($d)};
-
-        if ($m) {
-          $m=$mmm{lc($m)};
-          $date_0=&Date_Join($y,$m,1,0,0,0);
-          $date_1=&DateCalc_DateDelta($date_0,"+0:1:0:0:0:0:0",0);
-        } else {
-          $date_0=&Date_Join($y,1,1,0,0,0);
-          $date_1=&Date_Join($y+1,1,1,0,0,0);
-        }
-        $date_b=&DateCalc($date_0,"-0:0:0:1:0:0:0",0);
-
-        @recur0=(0,0,$num);
-        @recur1=($d,0,0,0);
-
-      } else {
-        return "";
-      }
-
-      $date_0=""  if ($date0);
-      $date_1=""  if ($date1);
-    } else {
-      return "";
-    }
-  }
-
-  #
-  # Override with any values passed in
-  #
-
-  if ($date0 && $date_0) {
-    $date0=( &Date_Cmp($date0,$date_0) > 1  ? $date0 : $date_0);
-  } elsif ($date_0) {
-    $date0 = $date_0;
-  }
-
-  if ($date1 && $date_1) {
-    $date1=( &Date_Cmp($date1,$date_1) > 1  ? $date_1 : $date1);
-  } elsif ($date_1) {
-    $date1 = $date_1;
-  }
-
-  $dateb=$date_b  if (! $dateb);
-
-  if ($flag =~ s/^\+//) {
-    if ($flag_t) {
-      $flag="$flag_t,$flag";
-    }
-  }
-  $flag =$flag_t  if (! $flag  &&  $flag_t);
-
-  if (! wantarray) {
-    $tmp  = join(":",@recur0);
-    $tmp .= "*" . join(":",@recur1)  if (@recur1);
-    $tmp .= "*$flag*$dateb*$date0*$date1";
-    return $tmp;
-  }
-  if (@recur0) {
-    return ()  if (! $date0  ||  ! $date1); # dateb is NOT required in all case
-  }
-
-  #
-  # Some flags affect parsing.
-  #
-
-  @flags   = split(/,/,$flag);
-  my($MDn) = 0;
-  my($MWn) = 7;
-  my($f);
-  foreach $f (@flags) {
-    if ($f =~ /^MW([1-7])$/i) {
-      $MWn=$1;
-      $MDn=0;
-
-    } elsif ($f =~ /^MD([1-7])$/i) {
-      $MDn=$1;
-      $MWn=0;
-
-    } elsif ($f =~ /^EASTER$/i) {
-      ($y,$m,$w,$d,$h,$mn,$s)=(@recur0,@recur1);
-      # We want something that will return Jan 1 for the given years.
-      if ($#recur0==-1) {
-        @recur1=($y,1,0,1,$h,$mn,$s);
-      } elsif ($#recur0<=3) {
-        @recur0=($y,0,0,0);
-        @recur1=($h,$mn,$s);
-      } elsif ($#recur0==4) {
-        @recur0=($y,0,0,0,0);
-        @recur1=($mn,$s);
-      } elsif ($#recur0==5) {
-        @recur0=($y,0,0,0,0,0);
-        @recur1=($s);
-      } else {
-        @recur0=($y,0,0,0,0,0,0);
-      }
-    }
-  }
-
-  #
-  # Determine the dates referenced by the recur.  Also, fix the base date
-  # as necessary for the recurrences which require it.
-  #
-
-  ($y,$m,$w,$d,$h,$mn,$s)=(@recur0,@recur1);
-  @y=@m=@w=@d=();
-  my(@time)=($h,$mn,$s);
-
- RECUR: while (1) {
-
-    if ($#recur0==-1) {
-      # * Y-M-W-D-H-MN-S
-      if ($y eq "0") {
-        push(@recur0,0);
-        shift(@recur1);
-
-      } else {
-        @y=&ReturnList($y);
-        foreach $y (@y) {
-          $y=&Date_FixYear($y)  if (length($y)==2);
-          return ()  if (length($y)!=4  ||  ! &IsInt($y));
-        }
-        @y=sort { $a<=>$b } @y;
-
-        $date0=&ParseDate("0000-01-01")          if (! $date0);
-        $date1=&ParseDate("9999-12-31 23:59:59") if (! $date1);
-
-        if ($m eq "0"  and  $w eq "0") {
-          # * Y-0-0-0-H-MN-S
-          # * Y-0-0-DOY-H-MN-S
-          if ($d eq "0") {
-            @d=(1);
-          } else {
-            @d=&ReturnList($d);
-            return ()  if (! @d);
-            foreach $d (@d) {
-              return ()  if (! &IsInt($d,1,366));
-            }
-            @d=sort { $a<=>$b } (@d);
-          }
-
-          @date=();
-          foreach $yy (@y) {
-            foreach $d (@d) {
-              ($y,$m,$dd)=&Date_NthDayOfYear($yy,$d);
-              push(@date, &Date_Join($y,$m,$dd,0,0,0));
-            }
-          }
-          last RECUR;
-
-        } elsif ($w eq "0") {
-          # * Y-M-0-0-H-MN-S
-          # * Y-M-0-DOM-H-MN-S
-
-          @m=&ReturnList($m);
-          return ()  if (! @m);
-          foreach $m (@m) {
-            return ()  if (! &IsInt($m,1,12));
-          }
-          @m=sort { $a<=>$b } (@m);
-
-          if ($d eq "0") {
-            @d=(1);
-          } else {
-            @d=&ReturnList($d);
-            return ()  if (! @d);
-            foreach $d (@d) {
-              return ()  if (! &IsInt($d,1,31));
-            }
-            @d=sort { $a<=>$b } (@d);
-          }
-
-          @date=();
-          foreach $y (@y) {
-            foreach $m (@m) {
-              foreach $d (@d) {
-                $date=&Date_Join($y,$m,$d,0,0,0);
-                push(@date,$date)  if ($d<29 || &Date_Split($date));
-              }
-            }
-          }
-          last RECUR;
-
-        } elsif ($m eq "0") {
-          # * Y-0-WOY-DOW-H-MN-S
-          # * Y-0-WOY-0-H-MN-S
-          @w=&ReturnList($w);
-          return ()  if (! @w);
-          foreach $w (@w) {
-            return ()  if (! &IsInt($w,1,53));
-          }
-
-          if ($d eq "0") {
-            @d=($Cnf{"FirstDay"});
-          } else {
-            @d=&ReturnList($d);
-            return ()  if (! @d);
-            foreach $d (@d) {
-              return ()  if (! &IsInt($d,1,7));
-            }
-            @d=sort { $a<=>$b } (@d);
-          }
-
-          @date=();
-          foreach $y (@y) {
-            foreach $w (@w) {
-              $w="0$w"  if (length($w)==1);
-              foreach $d (@d) {
-                $date=&ParseDateString("$y-W$w-$d");
-                push(@date,$date);
-              }
-            }
-          }
-          last RECUR;
-
-        } else {
-          # * Y-M-WOM-DOW-H-MN-S
-          # * Y-M-WOM-0-H-MN-S
-
-          @m=&ReturnList($m);
-          return ()  if (! @m);
-          foreach $m (@m) {
-            return ()  if (! &IsInt($m,1,12));
-          }
-          @m=sort { $a<=>$b } (@m);
-
-          @w=&ReturnList($w);
-
-          if ($d eq "0") {
-            @d=();
-          } else {
-            @d=&ReturnList($d);
-          }
-
-          @date=&Date_Recur_WoM(\@y,\@m,\@w,\@d,$MWn,$MDn);
-          last RECUR;
-        }
-      }
-    }
-
-    if ($#recur0==0) {
-      # Y * M-W-D-H-MN-S
-      $n=$y;
-      $n=1  if ($n==0);
-
-      @m=&ReturnList($m);
-      return ()  if (! @m);
-      foreach $m (@m) {
-        return ()  if (! &IsInt($m,1,12));
-      }
-      @m=sort { $a<=>$b } (@m);
-
-      if ($m eq "0") {
-        # Y * 0-W-D-H-MN-S   (equiv to Y-0 * W-D-H-MN-S)
-        push(@recur0,0);
-        shift(@recur1);
-
-      } elsif ($w eq "0") {
-        # Y * M-0-DOM-H-MN-S
-        return ()  if (! $dateb);
-        $d=1  if ($d eq "0");
-
-        @d=&ReturnList($d);
-        return ()  if (! @d);
-        foreach $d (@d) {
-          return ()  if (! &IsInt($d,1,31));
-        }
-        @d=sort { $a<=>$b } (@d);
-
-        # We need to find years that are a multiple of $n from $y(base)
-        ($y0)=( &Date_Split($date0, 1) )[0];
-        ($y1)=( &Date_Split($date1, 1) )[0];
-        ($yb)=( &Date_Split($dateb, 1) )[0];
-        @date=();
-        for ($yy=$y0; $yy<=$y1; $yy++) {
-          if (($yy-$yb)%$n == 0) {
-            foreach $m (@m) {
-              foreach $d (@d) {
-                $date=&Date_Join($yy,$m,$d,0,0,0);
-                push(@date,$date)  if ($d<29 || &Date_Split($date));
-              }
-            }
-          }
-        }
-        last RECUR;
-
-      } else {
-        # Y * M-WOM-DOW-H-MN-S
-        # Y * M-WOM-0-H-MN-S
-        return ()  if (! $dateb);
-        @m=&ReturnList($m);
-        @w=&ReturnList($w);
-        if ($d eq "0") {
-          @d=();
-        } else {
-          @d=&ReturnList($d);
-        }
-
-        ($y0)=( &Date_Split($date0, 1) )[0];
-        ($y1)=( &Date_Split($date1, 1) )[0];
-        ($yb)=( &Date_Split($dateb, 1) )[0];
-        @y=();
-        for ($yy=$y0; $yy<=$y1; $yy++) {
-          if (($yy-$yb)%$n == 0) {
-            push(@y,$yy);
-          }
-        }
-
-        @date=&Date_Recur_WoM(\@y,\@m,\@w,\@d,$MWn,$MDn);
-        last RECUR;
-      }
-    }
-
-    if ($#recur0==1) {
-      # Y-M * W-D-H-MN-S
-
-      if ($w eq "0") {
-        # Y-M * 0-D-H-MN-S   (equiv to Y-M-0 * D-H-MN-S)
-        push(@recur0,0);
-        shift(@recur1);
-
-      } elsif ($m==0) {
-        # Y-0 * WOY-0-H-MN-S
-        # Y-0 * WOY-DOW-H-MN-S
-        return ()  if (! $dateb);
-        $n=$y;
-        $n=1  if ($n==0);
-
-        @w=&ReturnList($w);
-        return ()  if (! @w);
-        foreach $w (@w) {
-          return ()  if (! &IsInt($w,1,53));
-        }
-
-        if ($d eq "0") {
-          @d=($Cnf{"FirstDay"});
-        } else {
-          @d=&ReturnList($d);
-          return ()  if (! @d);
-          foreach $d (@d) {
-            return ()  if (! &IsInt($d,1,7));
-          }
-          @d=sort { $a<=>$b } (@d);
-        }
-
-        # We need to find years that are a multiple of $n from $y(base)
-        ($y0)=( &Date_Split($date0, 1) )[0];
-        ($y1)=( &Date_Split($date1, 1) )[0];
-        ($yb)=( &Date_Split($dateb, 1) )[0];
-        @date=();
-        for ($yy=$y0; $yy<=$y1; $yy++) {
-          if (($yy-$yb)%$n == 0) {
-            foreach $w (@w) {
-              $w="0$w"  if (length($w)==1);
-              foreach $tmp (@d) {
-                $date=&ParseDateString("$yy-W$w-$tmp");
-                push(@date,$date);
-              }
-            }
-          }
-        }
-        last RECUR;
-
-      } else {
-        # Y-M * WOM-0-H-MN-S
-        # Y-M * WOM-DOW-H-MN-S
-        return ()  if (! $dateb);
-        @tmp=(@recur0);
-        push(@tmp,0)  while ($#tmp<6);
-        $delta=join(":",@tmp);
-        @tmp=&Date_Recur($date0,$date1,$dateb,$delta);
-
-        @w=&ReturnList($w);
-        @m=();
-        if ($d eq "0") {
-          @d=();
-        } else {
-          @d=&ReturnList($d);
-        }
-
-        @date=&Date_Recur_WoM(\@tmp,\@m,\@w,\@d,$MWn,$MDn);
-        last RECUR;
-      }
-    }
-
-    if ($#recur0==2) {
-      # Y-M-W * D-H-MN-S
-
-      if ($d eq "0") {
-        # Y-M-W * 0-H-MN-S
-        return ()  if (! $dateb);
-        $y=1  if ($y==0 && $m==0 && $w==0);
-        $delta="$y:$m:$w:0:0:0:0";
-        @date=&Date_Recur($date0,$date1,$dateb,$delta);
-        last RECUR;
-
-      } elsif ($m==0 && $w==0) {
-        # Y-0-0 * DOY-H-MN-S
-        $y=1  if ($y==0);
-        $n=$y;
-        return ()  if (! $dateb  &&  $y!=1);
-
-        @d=&ReturnList($d);
-        return ()  if (! @d);
-        foreach $d (@d) {
-          return ()  if (! &IsInt($d,1,366));
-        }
-        @d=sort { $a<=>$b } (@d);
-
-        # We need to find years that are a multiple of $n from $y(base)
-        ($y0)=( &Date_Split($date0, 1) )[0];
-        ($y1)=( &Date_Split($date1, 1) )[0];
-        ($yb)=( &Date_Split($dateb, 1) )[0];
-        @date=();
-        for ($yy=$y0; $yy<=$y1; $yy++) {
-          if (($yy-$yb)%$n == 0) {
-            foreach $d (@d) {
-              ($y,$m,$dd)=&Date_NthDayOfYear($yy,$d);
-              push(@date, &Date_Join($y,$m,$dd,0,0,0));
-            }
-          }
-        }
-        last RECUR;
-
-      } elsif ($w>0) {
-        # Y-M-W * DOW-H-MN-S
-        return ()  if (! $dateb);
-        @tmp=(@recur0);
-        push(@tmp,0)  while ($#tmp<6);
-        $delta=join(":",@tmp);
-
-        @d=&ReturnList($d);
-        return ()  if (! @d);
-        foreach $d (@d) {
-          return ()  if (! &IsInt($d,1,7));
-        }
-
-        # Find out what DofW the basedate is.
-        @tmp2=&Date_Split($dateb, 1);
-        $tmp=&Date_DayOfWeek($tmp2[1],$tmp2[2],$tmp2[0]);
-
-        @date=();
-        foreach $d (@d) {
-          $date_b=$dateb;
-          # Move basedate to DOW
-          if ($d != $tmp) {
-            if (($tmp>=$Cnf{"FirstDay"} && $d<$Cnf{"FirstDay"}) ||
-                ($tmp>=$Cnf{"FirstDay"} && $d>$tmp) ||
-                ($tmp<$d && $d<$Cnf{"FirstDay"})) {
-              $date_b=&Date_GetNext($date_b,$d);
-            } else {
-              $date_b=&Date_GetPrev($date_b,$d);
-            }
-          }
-          push(@date,&Date_Recur($date0,$date1,$date_b,$delta));
-        }
-        @date=sort(@date);
-        last RECUR;
-
-      } elsif ($m>0) {
-        # Y-M-0 * DOM-H-MN-S
-        return ()  if (! $dateb);
-        @tmp=(@recur0);
-        push(@tmp,0)  while ($#tmp<6);
-        $delta=join(":",@tmp);
-
-        @d=&ReturnList($d);
-        return ()  if (! @d);
-        foreach $d (@d) {
-          return ()  if (! &IsInt($d,-31,31)  ||  $d==0);
-        }
-        @d=sort { $a<=>$b } (@d);
-
-        @tmp2=&Date_Recur($date0,$date1,$dateb,$delta);
-        @date=();
-        foreach $date (@tmp2) {
-          ($y,$m)=( &Date_Split($date, 1) )[0..1];
-          $tmp2=&Date_DaysInMonth($m,$y);
-          foreach $d (@d) {
-            $d2=$d;
-            $d2=$tmp2+1+$d  if ($d<0);
-            push(@date,&Date_Join($y,$m,$d2,0,0,0))  if ($d2<=$tmp2);
-          }
-        }
-        @date=sort (@date);
-        last RECUR;
-
-      } else {
-        return ();
-      }
-    }
-
-    if ($#recur0>2) {
-      # Y-M-W-D * H-MN-S
-      # Y-M-W-D-H * MN-S
-      # Y-M-W-D-H-MN * S
-      # Y-M-W-D-H-S
-      return ()  if (! $dateb);
-      @tmp=(@recur0);
-      push(@tmp,0)  while ($#tmp<6);
-      $delta=join(":",@tmp);
-      return ()  if ($delta !~ /[1-9]/);    # return if "0:0:0:0:0:0:0"
-      @date=&Date_Recur($date0,$date1,$dateb,$delta);
-      if (@recur1) {
-        unshift(@recur1,-1)  while ($#recur1<2);
-        @time=@recur1;
-      } else {
-        shift(@date);
-        pop(@date);
-        @time=();
-      }
-    }
-
-    last RECUR;
-  }
-  @date=&Date_RecurSetTime($date0,$date1,\@date,@time)  if (@time);
-
-  #
-  # We've got a list of dates.  Operate on them with the flags.
-  #
-
-  my($sign,$forw,$today,$df,$db,$work,$i);
-  if (@flags) {
-  FLAG: foreach $f (@flags) {
-      $f = uc($f);
-
-      if ($f =~ /^(P|N)(D|T)([1-7])$/) {
-        @tmp=($1,$2,$3);
-        $forw =($tmp[0] eq "P" ? 0 : 1);
-        $today=($tmp[1] eq "D" ? 0 : 1);
-        $d=$tmp[2];
-        @tmp=();
-        foreach $date (@date) {
-          if ($forw) {
-            push(@tmp, &Date_GetNext($date,$d,$today));
-          } else {
-            push(@tmp, &Date_GetPrev($date,$d,$today));
-          }
-        }
-        @date=@tmp;
-        next FLAG;
-      }
-
-      # We want to go forward exact amounts of time instead of
-      # business mode calculations so that we don't change the time
-      # (which may have been set in the recur).
-      if ($f =~ /^(F|B)(D|W)(\d+)$/) {
-        @tmp=($1,$2,$3);
-        $sign="+";
-        $sign="-"  if ($tmp[0] eq "B");
-        $work=0;
-        $work=1    if ($tmp[1] eq "W");
-        $n=$tmp[2];
-        @tmp=();
-        foreach $date (@date) {
-          for ($i=1; $i<=$n; $i++) {
-            while (1) {
-              $date=&DateCalc($date,"${sign}0:0:0:1:0:0:0");
-              last if (! $work  ||  &Date_IsWorkDay($date,0));
-            }
-          }
-          push(@tmp,$date);
-        }
-        @date=@tmp;
-        next FLAG;
-      }
-
-      if ($f =~ /^CW(N|P|D)$/ || $f =~ /^(N|P|D)W(D)$/) {
-        $tmp=$1;
-        my $noalt = $2 ? 1 : 0;
-        if ($tmp eq "N"  ||  ($tmp eq "D" && $Cnf{"TomorrowFirst"})) {
-          $forw=1;
-        } else {
-          $forw=0;
-        }
-
-        @tmp=();
-      DATE: foreach $date (@date) {
-          $df=$db=$date;
-          if (&Date_IsWorkDay($date)) {
-            push(@tmp,$date);
-            next DATE;
-          }
-          while (1) {
-            if ($forw) {
-              $d=$df=&DateCalc($df,"+0:0:0:1:0:0:0");
-            } else {
-              $d=$db=&DateCalc($db,"-0:0:0:1:0:0:0");
-            }
-            if (&Date_IsWorkDay($d)) {
-              push(@tmp,$d);
-              next DATE;
-            }
-            $forw=1-$forw  if (! $noalt);
-          }
-        }
-        @date=@tmp;
-        next FLAG;
-      }
-
-      if ($f eq "EASTER") {
-        @tmp=();
-        foreach $date (@date) {
-          ($y,$m,$d,$h,$mn,$s)=&Date_Split($date, 1);
-          ($m,$d)=&Date_Easter($y);
-          $date=&Date_Join($y,$m,$d,$h,$mn,$s);
-          next  if (&Date_Cmp($date,$date0)<0  ||
-                    &Date_Cmp($date,$date1)>0);
-          push(@tmp,$date);
-        }
-        @date=@tmp;
-      }
-    }
-    @date = sort(@date);
-  }
-  @date;
-}
-
-sub Date_GetPrev {
-  print "DEBUG: Date_GetPrev\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($date,$dow,$today,$hr,$min,$sec)=@_;
-  &Date_Init()  if (! $Curr{"InitDone"});
-  my($y,$m,$d,$h,$mn,$s,$err,$curr_dow,%dow,$num,$delta,$th,$tm,$ts,
-     $adjust,$curr)=();
-  $hr="00"   if (defined $hr   &&  $hr eq "0");
-  $min="00"  if (defined $min  &&  $min eq "0");
-  $sec="00"  if (defined $sec  &&  $sec eq "0");
-
-  if (! &Date_Split($date)) {
-    $date=&ParseDateString($date);
-    return ""  if (! $date);
-  }
-  $curr=$date;
-  ($y,$m,$d)=( &Date_Split($date, 1) )[0..2];
-
-  if ($dow) {
-    $curr_dow=&Date_DayOfWeek($m,$d,$y);
-    %dow=%{ $Lang{$Cnf{"Language"}}{"WeekH"} };
-    if (&IsInt($dow)) {
-      return ""  if ($dow<1  ||  $dow>7);
-    } else {
-      return ""  if (! exists $dow{lc($dow)});
-      $dow=$dow{lc($dow)};
-    }
-    if ($dow == $curr_dow) {
-      $date=&DateCalc_DateDelta($date,"-0:0:1:0:0:0:0",\$err,0)  if (! $today);
-      $adjust=1  if ($today==2);
-    } else {
-      $dow -= 7  if ($dow>$curr_dow); # make sure previous day is less
-      $num = $curr_dow - $dow;
-      $date=&DateCalc_DateDelta($date,"-0:0:0:$num:0:0:0",\$err,0);
-    }
-    $date=&Date_SetTime($date,$hr,$min,$sec)  if (defined $hr);
-    $date=&DateCalc_DateDelta($date,"-0:0:1:0:0:0:0",\$err,0)
-      if ($adjust  &&  &Date_Cmp($date,$curr)>0);
-
-  } else {
-    ($h,$mn,$s)=( &Date_Split($date, 1) )[3..5];
-    ($th,$tm,$ts)=&Date_ParseTime($hr,$min,$sec);
-    if ($hr) {
-      ($hr,$min,$sec)=($th,$tm,$ts);
-      $delta="-0:0:0:1:0:0:0";
-    } elsif ($min) {
-      ($hr,$min,$sec)=($h,$tm,$ts);
-      $delta="-0:0:0:0:1:0:0";
-    } elsif ($sec) {
-      ($hr,$min,$sec)=($h,$mn,$ts);
-      $delta="-0:0:0:0:0:1:0";
-    } else {
-      confess "ERROR: invalid arguments in Date_GetPrev.\n";
-    }
-
-    $d=&Date_SetTime($date,$hr,$min,$sec);
-    if ($today) {
-      $d=&DateCalc_DateDelta($d,$delta,\$err,0)  if (&Date_Cmp($d,$date)>0);
-    } else {
-      $d=&DateCalc_DateDelta($d,$delta,\$err,0)  if (&Date_Cmp($d,$date)>=0);
-    }
-    $date=$d;
-  }
-  return $date;
-}
-
-sub Date_GetNext {
-  print "DEBUG: Date_GetNext\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($date,$dow,$today,$hr,$min,$sec)=@_;
-  &Date_Init()  if (! $Curr{"InitDone"});
-  my($y,$m,$d,$h,$mn,$s,$err,$curr_dow,%dow,$num,$delta,$th,$tm,$ts,
-     $adjust,$curr)=();
-  $hr="00"   if (defined $hr   &&  $hr eq "0");
-  $min="00"  if (defined $min  &&  $min eq "0");
-  $sec="00"  if (defined $sec  &&  $sec eq "0");
-
-  if (! &Date_Split($date)) {
-    $date=&ParseDateString($date);
-    return ""  if (! $date);
-  }
-  $curr=$date;
-  ($y,$m,$d)=( &Date_Split($date, 1) )[0..2];
-
-  if ($dow) {
-    $curr_dow=&Date_DayOfWeek($m,$d,$y);
-    %dow=%{ $Lang{$Cnf{"Language"}}{"WeekH"} };
-    if (&IsInt($dow)) {
-      return ""  if ($dow<1  ||  $dow>7);
-    } else {
-      return ""  if (! exists $dow{lc($dow)});
-      $dow=$dow{lc($dow)};
-    }
-    if ($dow == $curr_dow) {
-      $date=&DateCalc_DateDelta($date,"+0:0:1:0:0:0:0",\$err,0)  if (! $today);
-      $adjust=1  if ($today==2);
-    } else {
-      $curr_dow -= 7  if ($curr_dow>$dow); # make sure next date is greater
-      $num = $dow - $curr_dow;
-      $date=&DateCalc_DateDelta($date,"+0:0:0:$num:0:0:0",\$err,0);
-    }
-    $date=&Date_SetTime($date,$hr,$min,$sec)  if (defined $hr);
-    $date=&DateCalc_DateDelta($date,"+0:0:1:0:0:0:0",\$err,0)
-      if ($adjust  &&  &Date_Cmp($date,$curr)<0);
-
-  } else {
-    ($h,$mn,$s)=( &Date_Split($date, 1) )[3..5];
-    ($th,$tm,$ts)=&Date_ParseTime($hr,$min,$sec);
-    if ($hr) {
-      ($hr,$min,$sec)=($th,$tm,$ts);
-      $delta="+0:0:0:1:0:0:0";
-    } elsif ($min) {
-      ($hr,$min,$sec)=($h,$tm,$ts);
-      $delta="+0:0:0:0:1:0:0";
-    } elsif ($sec) {
-      ($hr,$min,$sec)=($h,$mn,$ts);
-      $delta="+0:0:0:0:0:1:0";
-    } else {
-      confess "ERROR: invalid arguments in Date_GetNext.\n";
-    }
-
-    $d=&Date_SetTime($date,$hr,$min,$sec);
-    if ($today) {
-      $d=&DateCalc_DateDelta($d,$delta,\$err,0)  if (&Date_Cmp($d,$date)<0);
-    } else {
-      $d=&DateCalc_DateDelta($d,$delta,\$err,0)  if (&Date_Cmp($d,$date)<1);
-    }
-    $date=$d;
-  }
-
-  return $date;
-}
-
-sub Date_IsHoliday {
-  print "DEBUG: Date_IsHoliday\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($date)=@_;
-  &Date_Init()  if (! $Curr{"InitDone"});
-  $date=&ParseDateString($date);
-  return undef  if (! $date);
-  $date=&Date_SetTime($date,0,0,0);
-  my($y)=(&Date_Split($date, 1))[0];
-  &Date_UpdateHolidays($y)  if (! exists $Holiday{"dates"}{$y});
-  return undef  if (! exists $Holiday{"dates"}{$y}{$date});
-  my($name)=$Holiday{"dates"}{$y}{$date};
-  return ""   if (! $name);
-  $name;
-}
-
-sub Events_List {
-  print "DEBUG: Events_List\n"  if ($Curr{"Debug"} =~ /trace/);
-  my(@args)=@_;
-  &Date_Init()  if (! $Curr{"InitDone"});
-  &Events_ParseRaw();
-
-  my($tmp,$date0,$date1,$flag);
-  $date0=&ParseDateString($args[0]);
-  warn "Invalid date $args[0]", return undef  if (! $date0);
-
-  if ($#args == 0) {
-    return &Events_Calc($date0);
-  }
-
-  if ($args[1]) {
-    $date1=&ParseDateString($args[1]);
-    warn "Invalid date $args[1]\n", return undef  if (! $date1);
-    if (&Date_Cmp($date0,$date1)>0) {
-      $tmp=$date1;
-      $date1=$date0;
-      $date0=$tmp;
-    }
-  } else {
-    $date0=&Date_SetTime($date0,"00:00:00");
-    $date1=&DateCalc_DateDelta($date0,"+0:0:0:1:0:0:0");
-  }
-
-  $tmp=&Events_Calc($date0,$date1);
-
-  $flag=$args[2];
-  return $tmp  if (! $flag);
-
-  my(@tmp,%ret,$delta)=();
-  @tmp=@$tmp;
-  push(@tmp,$date1);
-
-  if ($flag==1) {
-    while ($#tmp>0) {
-      ($date0,$tmp)=splice(@tmp,0,2);
-      $date1=$tmp[0];
-      $delta=&DateCalc_DateDate($date0,$date1);
-      foreach $flag (@$tmp) {
-        if (exists $ret{$flag}) {
-          $ret{$flag}=&DateCalc_DeltaDelta($ret{$flag},$delta);
-        } else {
-          $ret{$flag}=$delta;
-        }
-      }
-    }
-    return \%ret;
-
-  } elsif ($flag==2) {
-    while ($#tmp>0) {
-      ($date0,$tmp)=splice(@tmp,0,2);
-      $date1=$tmp[0];
-      $delta=&DateCalc_DateDate($date0,$date1);
-      $flag=join("+",sort @$tmp);
-      next  if (! $flag);
-      if (exists $ret{$flag}) {
-        $ret{$flag}=&DateCalc_DeltaDelta($ret{$flag},$delta);
-      } else {
-        $ret{$flag}=$delta;
-      }
-    }
-    return \%ret;
-  }
-
-  warn "Invalid flag $flag\n";
-  return undef;
-}
-
-###
-# NOTE: The following routines may be called in the routines below with very
-#       little time penalty.
-###
-sub Date_SetTime {
-  print "DEBUG: Date_SetTime\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($date,$h,$mn,$s)=@_;
-  &Date_Init()  if (! $Curr{"InitDone"});
-  my($y,$m,$d)=();
-
-  if (! &Date_Split($date)) {
-    $date=&ParseDateString($date);
-    return ""  if (! $date);
-  }
-
-  ($y,$m,$d)=( &Date_Split($date, 1) )[0..2];
-  ($h,$mn,$s)=&Date_ParseTime($h,$mn,$s);
-
-  my($ampm,$wk);
-  return ""  if (&Date_DateCheck(\$y,\$m,\$d,\$h,\$mn,\$s,\$ampm,\$wk));
-  &Date_Join($y,$m,$d,$h,$mn,$s);
-}
-
-sub Date_SetDateField {
-  print "DEBUG: Date_SetDateField\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($date,$field,$val,$nocheck)=@_;
-  my($y,$m,$d,$h,$mn,$s)=();
-  $nocheck=0  if (! defined $nocheck);
-
-  ($y,$m,$d,$h,$mn,$s)=&Date_Split($date);
-
-  if (! $y) {
-    $date=&ParseDateString($date);
-    return "" if (! $date);
-    ($y,$m,$d,$h,$mn,$s)=&Date_Split($date, 1);
-  }
-
-  if      (lc($field) eq "y") {
-    $y=$val;
-  } elsif (lc($field) eq "m") {
-    $m=$val;
-  } elsif (lc($field) eq "d") {
-    $d=$val;
-  } elsif (lc($field) eq "h") {
-    $h=$val;
-  } elsif (lc($field) eq "mn") {
-    $mn=$val;
-  } elsif (lc($field) eq "s") {
-    $s=$val;
-  } else {
-    confess "ERROR: Date_SetDateField: invalid field: $field\n";
-  }
-
-  $date=&Date_Join($y,$m,$d,$h,$mn,$s);
-  return $date  if ($nocheck  ||  &Date_Split($date));
-  return "";
-}
-
-########################################################################
-# OTHER SUBROUTINES
-########################################################################
-# NOTE: These routines should not call any of the routines above as
-#       there will be a severe time penalty (and the possibility of
-#       infinite recursion).  The last couple routines above are
-#       exceptions.
-# NOTE: Date_Init is a special case.  It should be called (conditionally)
-#       in every routine that uses any variable from the Date::Manip
-#       namespace.
-########################################################################
-
-sub Date_DaysInMonth {
-  print "DEBUG: Date_DaysInMonth\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($m,$y)=@_;
-  $y=&Date_FixYear($y)  if (length($y)!=4);
-  my(@d_in_m)=(0,31,28,31,30,31,30,31,31,30,31,30,31);
-  $d_in_m[2]=29  if (&Date_LeapYear($y));
-  return $d_in_m[$m];
-}
-
-sub Date_DayOfWeek {
-  print "DEBUG: Date_DayOfWeek\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($m,$d,$y)=@_;
-  $y=&Date_FixYear($y)  if (length($y)!=4);
-  my($dayofweek,$dec31)=();
-
-  $dec31=5;                     # Dec 31, 1BC was Friday
-  $dayofweek=(&Date_DaysSince1BC($m,$d,$y)+$dec31) % 7;
-  $dayofweek=7  if ($dayofweek==0);
-  return $dayofweek;
-}
-
-# Can't be in "use integer" because the numbers are too big.
-no integer;
-sub Date_SecsSince1970 {
-  print "DEBUG: Date_SecsSince1970\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($m,$d,$y,$h,$mn,$s)=@_;
-  $y=&Date_FixYear($y)  if (length($y)!=4);
-  my($sec_now,$sec_70)=();
-  $sec_now=(&Date_DaysSince1BC($m,$d,$y)-1)*24*3600 + $h*3600 + $mn*60 + $s;
-# $sec_70 =(&Date_DaysSince1BC(1,1,1970)-1)*24*3600;
-  $sec_70 =62167219200;
-  return ($sec_now-$sec_70);
-}
-
-sub Date_SecsSince1970GMT {
-  print "DEBUG: Date_SecsSince1970GMT\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($m,$d,$y,$h,$mn,$s)=@_;
-  &Date_Init()  if (! $Curr{"InitDone"});
-  $y=&Date_FixYear($y)  if (length($y)!=4);
-
-  my($sec)=&Date_SecsSince1970($m,$d,$y,$h,$mn,$s);
-  return $sec   if ($Cnf{"ConvTZ"} eq "IGNORE");
-
-  my($tz)=$Cnf{"ConvTZ"};
-  $tz=$Cnf{"TZ"}  if (! $tz);
-  $tz=$Zone{"n2o"}{lc($tz)}  if ($tz !~ /^[+-]\d{4}$/);
-
-  my($tzs)=1;
-  $tzs=-1 if ($tz<0);
-  $tz=~/.(..)(..)/;
-  my($tzh,$tzm)=($1,$2);
-  $sec - $tzs*($tzh*3600+$tzm*60);
-}
-use integer;
-
-sub Date_DaysSince1BC {
-  print "DEBUG: Date_DaysSince1BC\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($m,$d,$y)=@_;
-  $y=&Date_FixYear($y)  if (length($y)!=4);
-  my($Ny,$N4,$N100,$N400,$dayofyear,$days)=();
-  my($cc,$yy)=();
-
-  $y=~ /(\d{2})(\d{2})/;
-  ($cc,$yy)=($1,$2);
-
-  # Number of full years since Dec 31, 1BC (counting the year 0000).
-  $Ny=$y;
-
-  # Number of full 4th years (incl. 0000) since Dec 31, 1BC
-  $N4=($Ny-1)/4 + 1;
-  $N4=0         if ($y==0);
-
-  # Number of full 100th years (incl. 0000)
-  $N100=$cc + 1;
-  $N100--       if ($yy==0);
-  $N100=0       if ($y==0);
-
-  # Number of full 400th years (incl. 0000)
-  $N400=($N100-1)/4 + 1;
-  $N400=0       if ($y==0);
-
-  $dayofyear=&Date_DayOfYear($m,$d,$y);
-  $days= $Ny*365 + $N4 - $N100 + $N400 + $dayofyear;
-
-  return $days;
-}
-
-sub Date_DayOfYear {
-  print "DEBUG: Date_DayOfYear\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($m,$d,$y)=@_;
-  $y=&Date_FixYear($y)  if (length($y)!=4);
-  # DinM    = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
-  my(@days) = ( 0, 31, 59, 90,120,151,181,212,243,273,304,334,365);
-  my($ly)=0;
-  $ly=1  if ($m>2 && &Date_LeapYear($y));
-  return ($days[$m-1]+$d+$ly);
-}
-
-sub Date_DaysInYear {
-  print "DEBUG: Date_DaysInYear\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($y)=@_;
-  $y=&Date_FixYear($y)  if (length($y)!=4);
-  return 366  if (&Date_LeapYear($y));
-  return 365;
-}
-
-sub Date_WeekOfYear {
-  print "DEBUG: Date_WeekOfYear\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($m,$d,$y,$f)=@_;
-  &Date_Init()  if (! $Curr{"InitDone"});
-  $y=&Date_FixYear($y)  if (length($y)!=4);
-
-  my($day,$dow,$doy)=();
-  $doy=&Date_DayOfYear($m,$d,$y);
-
-  # The current DayOfYear and DayOfWeek
-  if ($Cnf{"Jan1Week1"}) {
-    $day=1;
-  } else {
-    $day=4;
-  }
-  $dow=&Date_DayOfWeek(1,$day,$y);
-
-  # Move back to the first day of week 1.
-  $f-=7  if ($f>$dow);
-  $day-= ($dow-$f);
-
-  return 0  if ($day>$doy);      # Day is in last week of previous year
-  return (($doy-$day)/7 + 1);
-}
-
-sub Date_LeapYear {
-  print "DEBUG: Date_LeapYear\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($y)=@_;
-  $y=&Date_FixYear($y)  if (length($y)!=4);
-  return 0 unless $y % 4 == 0;
-  return 1 unless $y % 100 == 0;
-  return 0 unless $y % 400 == 0;
-  return 1;
-}
-
-sub Date_DaySuffix {
-  print "DEBUG: Date_DaySuffix\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($d)=@_;
-  &Date_Init()  if (! $Curr{"InitDone"});
-  return $Lang{$Cnf{"Language"}}{"DoML"}[$d-1];
-}
-
-sub Date_ConvTZ {
-  print "DEBUG: Date_ConvTZ\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($date,$from,$to)=@_;
-  if (not Date_Split($date)) {
-      croak "date passed in ('$date') is not a Date::Manip object";
-  }
-
-  &Date_Init()  if (! $Curr{"InitDone"});
-  my($gmt)=();
-
-  if (! $from) {
-
-    if (! $to) {
-      # TZ -> ConvTZ
-      return $date  if ($Cnf{"ConvTZ"} eq "IGNORE" or ! $Cnf{"ConvTZ"});
-      $from=$Cnf{"TZ"};
-      $to=$Cnf{"ConvTZ"};
-
-    } else {
-      # ConvTZ,TZ -> $to
-      $from=$Cnf{"ConvTZ"};
-      $from=$Cnf{"TZ"}  if (! $from);
-    }
-
-  } else {
-
-    if (! $to) {
-      # $from -> ConvTZ,TZ
-      return $date  if ($Cnf{"ConvTZ"} eq "IGNORE");
-      $to=$Cnf{"ConvTZ"};
-      $to=$Cnf{"TZ"}  if (! $to);
-
-    } else {
-      # $from -> $to
-    }
-  }
-
-  $to=$Zone{"n2o"}{lc($to)}
-    if (exists $Zone{"n2o"}{lc($to)});
-  $from=$Zone{"n2o"}{lc($from)}
-    if (exists $Zone{"n2o"}{lc($from)});
-  $gmt=$Zone{"n2o"}{"gmt"};
-
-  return $date  if ($from !~ /^[+-]\d{4}$/ or $to !~ /^[+-]\d{4}$/);
-  return $date  if ($from eq $to);
-
-  my($s1,$h1,$m1,$s2,$h2,$m2,$d,$h,$m,$sign,$delta,$err,$yr,$mon,$sec)=();
-  # We're going to try to do the calculation without calling DateCalc.
-  ($yr,$mon,$d,$h,$m,$sec)=&Date_Split($date, 1);
-
-  # Convert $date from $from to GMT
-  $from=~/([+-])(\d{2})(\d{2})/;
-  ($s1,$h1,$m1)=($1,$2,$3);
-  $s1= ($s1 eq "-" ? "+" : "-");   # switch sign
-  $sign=$s1 . "1";     # + or - 1
-
-  # and from GMT to $to
-  $to=~/([+-])(\d{2})(\d{2})/;
-  ($s2,$h2,$m2)=($1,$2,$3);
-
-  if ($s1 eq $s2) {
-    # Both the same sign
-    $m+= $sign*($m1+$m2);
-    $h+= $sign*($h1+$h2);
-  } else {
-    $sign=($s2 eq "-" ? +1 : -1)  if ($h1<$h2  ||  ($h1==$h2 && $m1<$m2));
-    $m+= $sign*($m1-$m2);
-    $h+= $sign*($h1-$h2);
-  }
-
-  if ($m>59) {
-    $h+= $m/60;
-    $m-= ($m/60)*60;
-  } elsif ($m<0) {
-    $h+= ($m/60 - 1);
-    $m-= ($m/60 - 1)*60;
-  }
-
-  if ($h>23) {
-    $delta=$h/24;
-    $h -= $delta*24;
-    if (($d + $delta) > 28) {
-      $date=&Date_Join($yr,$mon,$d,$h,$m,$sec);
-      return &DateCalc_DateDelta($date,"+0:0:0:$delta:0:0:0",\$err,0);
-    }
-    $d+= $delta;
-  } elsif ($h<0) {
-    $delta=-$h/24 + 1;
-    $h += $delta*24;
-    if (($d - $delta) < 1) {
-      $date=&Date_Join($yr,$mon,$d,$h,$m,$sec);
-      return &DateCalc_DateDelta($date,"-0:0:0:$delta:0:0:0",\$err,0);
-    }
-    $d-= $delta;
-  }
-  return &Date_Join($yr,$mon,$d,$h,$m,$sec);
-}
-
-sub Date_TimeZone {
-  print "DEBUG: Date_TimeZone\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($null,$tz,@tz,$std,$dst,$time,$isdst,$tmp,$in)=();
-  &Date_Init()  if (! $Curr{"InitDone"});
-
-  # Get timezones from all of the relevant places
-
-  push(@tz,$Cnf{"TZ"})  if (defined $Cnf{"TZ"});  # TZ config var
-  push(@tz,$ENV{"TZ"})  if (defined $ENV{"TZ"});  # TZ environ var
-  push(@tz,$ENV{'SYS$TIMEZONE_RULE'})
-    if defined $ENV{'SYS$TIMEZONE_RULE'};         # VMS TZ environ var
-  push(@tz,$ENV{'SYS$TIMEZONE_NAME'})
-    if defined $ENV{'SYS$TIMEZONE_NAME'};         # VMS TZ name environ var
-  push(@tz,$ENV{'UCX$TZ'})
-    if defined $ENV{'UCX$TZ'};                    # VMS TZ environ var
-  push(@tz,$ENV{'TCPIP$TZ'})
-    if defined $ENV{'TCPIP$TZ'};                  # VMS TZ environ var
-
-  # The `date` command... if we're doing taint checking, we need to
-  # always call it with a full path... otherwise, use the user's path.
-  #
-  # Microsoft operating systems don't have a date command built in.  Try
-  # to trap all the various ways of knowing we are on one of these systems.
-  #
-  # We'll try `date +%Z` first, and if that fails, we'll take just the
-  # `date` program and assume the output is of the format:
-  # Thu Aug 31 14:57:46 EDT 2000
-
-  unless (($^X =~ /perl\.exe$/i) or
-          ($OS eq "Windows") or
-          ($OS eq "Netware") or
-          ($OS eq "VMS")) {
-    if ($Date::Manip::NoTaint) {
-      if ($OS eq "VMS") {
-        $tz=$ENV{'SYS$TIMEZONE_NAME'};
-        if (! $tz) {
-          $tz=$ENV{'MULTINET_TIMEZONE'};
-          if (! $tz) {
-            $tz=$ENV{'SYS$TIMEZONE_DIFFERENTIAL'}/3600.; # e.g. '-4' for EDT
-          }
-        }
-      } else {
-        $tz=`date +%Z 2> /dev/null`;
-        chomp($tz);
-        if (! $tz) {
-          $tz=`date 2> /dev/null`;
-          chomp($tz);
-          $tz=(split(/\s+/,$tz))[4];
-        }
-      }
-      push(@tz,$tz);
-    } else {
-      # We need to satisfy taint checking, but also look in all the
-      # directories in @DatePath.
-      #
-      local $ENV{PATH} = join(':', @Date::Manip::DatePath);
-      local $ENV{BASH_ENV} = '';
-      $tz=`date +%Z 2> /dev/null`;
-      chomp($tz);
-      if (! $tz) {
-	$tz=`date 2> /dev/null`;
-	chomp($tz);
-	$tz=(split(/\s+/,$tz))[4];
-      }
-      push(@tz,$tz);
-    }
-  }
-
-  push(@tz,$main::TZ)         if (defined $main::TZ);         # $main::TZ
-
-  if (-s "/etc/TIMEZONE") {                                   # /etc/TIMEZONE
-    $in=new IO::File;
-    $in->open("/etc/TIMEZONE","r");
-    while (! eof($in)) {
-      $tmp=<$in>;
-      if ($tmp =~ /^TZ\s*=\s*(.*?)\s*$/) {
-        push(@tz,$1);
-        last;
-      }
-    }
-    $in->close;
-  }
-
-  if (-s "/etc/timezone") {                                   # /etc/timezone
-    $in=new IO::File;
-    $in->open("/etc/timezone","r");
-    while (! eof($in)) {
-      $tmp=<$in>;
-      next  if ($tmp =~ /^\s*\043/);
-      chomp($tmp);
-      if ($tmp =~ /^\s*(.*?)\s*$/) {
-        push(@tz,$1);
-        last;
-      }
-    }
-    $in->close;
-  }
-
-  # Now parse each one to find the first valid one.
-  foreach $tz (@tz) {
-    $tz =~ s/\s*$//;
-    $tz =~ s/^\s*//;
-    next  if (! $tz);
-
-    return uc($tz)
-      if (defined $Zone{"n2o"}{lc($tz)});
-
-    if ($tz =~ /^[+-]\d{4}$/) {
-      return $tz;
-    } elsif ($tz =~ /^([+-]\d{2})(?::(\d{2}))?$/) {
-      my($h,$m)=($1,$2);
-      $m="00"  if (! $m);
-      return "$h$m";
-    }
-
-    # Handle US/Eastern format
-    if ($tz =~ /^$Zone{"tzones"}$/i) {
-      $tmp=lc $1;
-      $tz=$Zone{"tz2z"}{$tmp};
-    }
-
-    # Handle STD#DST# format (and STD-#DST-# formats)
-    if ($tz =~ /^([a-z]+)-?\d([a-z]+)-?\d?$/i) {
-      ($std,$dst)=($1,$2);
-      next  if (! defined $Zone{"n2o"}{lc($std)} or
-                ! defined $Zone{"n2o"}{lc($dst)});
-      $time = time();
-      ($null,$null,$null,$null,$null,$null,$null,$null,$isdst) =
-        localtime($time);
-      return uc($dst)  if ($isdst);
-      return uc($std);
-    }
-  }
-
-  confess "ERROR: Date::Manip unable to determine TimeZone.\n";
-}
-
-# Returns 1 if $date is a work day.  If $time is non-zero, the time is
-# also checked to see if it falls within work hours.  Returns "" if
-# an invalid date is passed in.
-sub Date_IsWorkDay {
-  print "DEBUG: Date_IsWorkDay\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($date,$time)=@_;
-  &Date_Init()  if (! $Curr{"InitDone"});
-  $date=&ParseDateString($date);
-  return ""  if (! $date);
-  my($d)=$date;
-  $d=&Date_SetTime($date,$Cnf{"WorkDayBeg"})  if (! $time);
-
-  my($y,$mon,$day,$tmp,$h,$m,$dow)=();
-  ($y,$mon,$day,$h,$m,$tmp)=&Date_Split($d, 1);
-  $dow=&Date_DayOfWeek($mon,$day,$y);
-
-  return 0  if ($dow<$Cnf{"WorkWeekBeg"} or
-                $dow>$Cnf{"WorkWeekEnd"} or
-                "$h:$m" lt $Cnf{"WorkDayBeg"} or
-                "$h:$m" gt $Cnf{"WorkDayEnd"});
-
-  if (! exists $Holiday{"dates"}{$y}) {
-    # There will be recursion problems if we ever end up here twice.
-    $Holiday{"dates"}{$y}={};
-    &Date_UpdateHolidays($y)
-  }
-  $d=&Date_SetTime($date,"00:00:00");
-  return 0  if (exists $Holiday{"dates"}{$y}{$d});
-  1;
-}
-
-# Finds the day $off work days from now.  If $time is passed in, we must
-# also take into account the time of day.
-#
-# If $time is not passed in, day 0 is today (if today is a workday) or the
-# next work day if it isn't.  In any case, the time of day is unaffected.
-#
-# If $time is passed in, day 0 is now (if now is part of a workday) or the
-# start of the very next work day.
-sub Date_NextWorkDay {
-  print "DEBUG: Date_NextWorkDay\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($date,$off,$time)=@_;
-  &Date_Init()  if (! $Curr{"InitDone"});
-  $date=&ParseDateString($date);
-  my($err)=();
-
-  if (! &Date_IsWorkDay($date,$time)) {
-    if ($time) {
-      while (1) {
-        $date=&Date_GetNext($date,undef,0,$Cnf{"WorkDayBeg"});
-        last  if (&Date_IsWorkDay($date,$time));
-      }
-    } else {
-      while (1) {
-        $date=&DateCalc_DateDelta($date,"+0:0:0:1:0:0:0",\$err,0);
-        last  if (&Date_IsWorkDay($date,$time));
-      }
-    }
-  }
-
-  while ($off>0) {
-    while (1) {
-      $date=&DateCalc_DateDelta($date,"+0:0:0:1:0:0:0",\$err,0);
-      last  if (&Date_IsWorkDay($date,$time));
-    }
-    $off--;
-  }
-
-  return $date;
-}
-
-# Finds the day $off work days before now.  If $time is passed in, we must
-# also take into account the time of day.
-#
-# If $time is not passed in, day 0 is today (if today is a workday) or the
-# previous work day if it isn't.  In any case, the time of day is unaffected.
-#
-# If $time is passed in, day 0 is now (if now is part of a workday) or the
-# end of the previous work period.  Note that since the end of a work day
-# will automatically be turned into the start of the next one, this time
-# may actually be treated as AFTER the current time.
-sub Date_PrevWorkDay {
-  print "DEBUG: Date_PrevWorkDay\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($date,$off,$time)=@_;
-  &Date_Init()  if (! $Curr{"InitDone"});
-  $date=&ParseDateString($date);
-  my($err)=();
-
-  if (! &Date_IsWorkDay($date,$time)) {
-    if ($time) {
-      while (1) {
-        $date=&Date_GetPrev($date,undef,0,$Cnf{"WorkDayEnd"});
-        last  if (&Date_IsWorkDay($date,$time));
-      }
-      while (1) {
-        $date=&Date_GetNext($date,undef,0,$Cnf{"WorkDayBeg"});
-        last  if (&Date_IsWorkDay($date,$time));
-      }
-    } else {
-      while (1) {
-        $date=&DateCalc_DateDelta($date,"-0:0:0:1:0:0:0",\$err,0);
-        last  if (&Date_IsWorkDay($date,$time));
-      }
-    }
-  }
-
-  while ($off>0) {
-    while (1) {
-      $date=&DateCalc_DateDelta($date,"-0:0:0:1:0:0:0",\$err,0);
-      last  if (&Date_IsWorkDay($date,$time));
-    }
-    $off--;
-  }
-
-  return $date;
-}
-
-# This finds the nearest workday to $date.  If $date is a workday, it
-# is returned.
-sub Date_NearestWorkDay {
-  print "DEBUG: Date_NearestWorkDay\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($date,$tomorrow)=@_;
-  &Date_Init()  if (! $Curr{"InitDone"});
-  $date=&ParseDateString($date);
-  my($a,$b,$dela,$delb,$err)=();
-  $tomorrow=$Cnf{"TomorrowFirst"}  if (! defined $tomorrow);
-
-  return $date  if (&Date_IsWorkDay($date));
-
-  # Find the nearest one.
-  if ($tomorrow) {
-    $dela="+0:0:0:1:0:0:0";
-    $delb="-0:0:0:1:0:0:0";
-  } else {
-    $dela="-0:0:0:1:0:0:0";
-    $delb="+0:0:0:1:0:0:0";
-  }
-  $a=$b=$date;
-
-  while (1) {
-    $a=&DateCalc_DateDelta($a,$dela,\$err);
-    return $a  if (&Date_IsWorkDay($a));
-    $b=&DateCalc_DateDelta($b,$delb,\$err);
-    return $b  if (&Date_IsWorkDay($b));
-  }
-}
-
-# &Date_NthDayOfYear($y,$n);
-#   Returns a list of (YYYY,MM,DD,HH,MM,SS) for the Nth day of the year.
-sub Date_NthDayOfYear {
-  no integer;
-  print "DEBUG: Date_NthDayOfYear\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($y,$n)=@_;
-  $y=$Curr{"Y"}  if (! $y);
-  $n=1       if (! defined $n  or  $n eq "");
-  $n+=0;     # to turn 023 into 23
-  $y=&Date_FixYear($y)  if (length($y)<4);
-  my $leap=&Date_LeapYear($y);
-  return ()  if ($n<1);
-  return ()  if ($n >= ($leap ? 367 : 366));
-
-  my(@d_in_m)=(31,28,31,30,31,30,31,31,30,31,30,31);
-  $d_in_m[1]=29  if ($leap);
-
-  # Calculate the hours, minutes, and seconds into the day.
-  my $remain=($n - int($n))*24;
-  my $h=int($remain);
-  $remain=($remain - $h)*60;
-  my $mn=int($remain);
-  $remain=($remain - $mn)*60;
-  my $s=$remain;
-
-  # Calculate the month and the day.
-  my($m,$d)=(0,0);
-  $n=int($n);
-  while ($n>0) {
-    $m++;
-    if ($n<=$d_in_m[0]) {
-      $d=int($n);
-      $n=0;
-    } else {
-      $n-= $d_in_m[0];
-      shift(@d_in_m);
-    }
-  }
-
-  ($y,$m,$d,$h,$mn,$s);
-}
-
-########################################################################
-# NOT FOR EXPORT
-########################################################################
-
-# This is used in Date_Init to fill in a hash based on international
-# data.  It takes a list of keys and values and returns both a hash
-# with these values and a regular expression of keys.
-#
-# IN:
-#   $data   = [ key1 val1 key2 val2 ... ]
-#   $opts   = lc     : lowercase the keys in the regexp
-#             sort   : sort (by length) the keys in the regexp
-#             back   : create a regexp with a back reference
-#             escape : escape all strings in the regexp
-#
-# OUT:
-#   $regexp = '(?:key1|key2|...)'
-#   $hash   = { key1=>val1 key2=>val2 ... }
-
-sub Date_InitHash {
-  print "DEBUG: Date_InitHash\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($data,$regexp,$opts,$hash)=@_;
-  my(@data)=@$data;
-  my($key,$val,@list)=();
-
-  # Parse the options
-  my($lc,$sort,$back,$escape)=(0,0,0,0);
-  $lc=1     if ($opts =~ /lc/i);
-  $sort=1   if ($opts =~ /sort/i);
-  $back=1   if ($opts =~ /back/i);
-  $escape=1 if ($opts =~ /escape/i);
-
-  # Create the hash
-  while (@data) {
-    ($key,$val,@data)=@data;
-    $key=lc($key)  if ($lc);
-    $$hash{$key}=$val;
-  }
-
-  # Create the regular expression
-  if ($regexp) {
-    @list=keys(%$hash);
-    @list=sort sortByLength(@list)  if ($sort);
-    if ($escape) {
-      foreach $val (@list) {
-        $val="\Q$val\E";
-      }
-    }
-    if ($back) {
-      $$regexp="(" . join("|",@list) . ")";
-    } else {
-      $$regexp="(?:" . join("|",@list) . ")";
-    }
-  }
-}
-
-# This is used in Date_Init to fill in regular expressions, lists, and
-# hashes based on international data.  It takes a list of lists which have
-# to be stored as regular expressions (to find any element in the list),
-# lists, and hashes (indicating the location in the lists).
-#
-# IN:
-#   $data   = [ [ [ valA1 valA2 ... ][ valA1' valA2' ... ] ... ]
-#               [ [ valB1 valB2 ... ][ valB1' valB2' ... ] ... ]
-#               ...
-#               [ [ valZ1 valZ2 ... ] [valZ1' valZ1' ... ] ... ] ]
-#   $lists  = [ \@listA \@listB ... \@listZ ]
-#   $opts   = lc     : lowercase the values in the regexp
-#             sort   : sort (by length) the values in the regexp
-#             back   : create a regexp with a back reference
-#             escape : escape all strings in the regexp
-#   $hash   = [ \%hash, TYPE ]
-#             TYPE 0 : $hash{ valBn=>n-1 }
-#             TYPE 1 : $hash{ valBn=>n }
-#
-# OUT:
-#   $regexp = '(?:valA1|valA2|...|valB1|...)'
-#   $lists  = [ [ valA1 valA2 ... ]         # only the 1st list (or
-#               [ valB1 valB2 ... ] ... ]   # 2nd for int. characters)
-#   $hash
-
-sub Date_InitLists {
-  print "DEBUG: Date_InitLists\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($data,$regexp,$opts,$lists,$hash)=@_;
-  my(@data)=@$data;
-  my(@lists)=@$lists;
-  my($i,@ele,$ele,@list,$j,$tmp)=();
-
-  # Parse the options
-  my($lc,$sort,$back,$escape)=(0,0,0,0);
-  $lc=1     if ($opts =~ /lc/i);
-  $sort=1   if ($opts =~ /sort/i);
-  $back=1   if ($opts =~ /back/i);
-  $escape=1 if ($opts =~ /escape/i);
-
-  # Set each of the lists
-  if (@lists) {
-    confess "ERROR: Date_InitLists: lists must be 1 per data\n"
-      if ($#lists != $#data);
-    for ($i=0; $i<=$#data; $i++) {
-      @ele=@{ $data[$i] };
-      if ($Cnf{"IntCharSet"} && $#ele>0) {
-        @{ $lists[$i] } = @{ $ele[1] };
-      } else {
-        @{ $lists[$i] } = @{ $ele[0] };
-      }
-    }
-  }
-
-  # Create the hash
-  my($hashtype,$hashsave,%hash)=();
-  if (@$hash) {
-    ($hash,$hashtype)=@$hash;
-    $hashsave=1;
-  } else {
-    $hashtype=0;
-    $hashsave=0;
-  }
-  for ($i=0; $i<=$#data; $i++) {
-    @ele=@{ $data[$i] };
-    foreach $ele (@ele) {
-      @list = @{ $ele };
-      for ($j=0; $j<=$#list; $j++) {
-        $tmp=$list[$j];
-        next  if (! $tmp);
-        $tmp=lc($tmp)  if ($lc);
-        $hash{$tmp}= $j+$hashtype;
-      }
-    }
-  }
-  %$hash = %hash  if ($hashsave);
-
-  # Create the regular expression
-  if ($regexp) {
-    @list=keys(%hash);
-    @list=sort sortByLength(@list)  if ($sort);
-    if ($escape) {
-      foreach $ele (@list) {
-        $ele="\Q$ele\E";
-      }
-    }
-    if ($back) {
-      $$regexp="(" . join("|",@list) . ")";
-    } else {
-      $$regexp="(?:" . join("|",@list) . ")";
-    }
-  }
-}
-
-# This is used in Date_Init to fill in regular expressions and lists based
-# on international data.  This takes a list of strings and returns a regular
-# expression (to find any one of them).
-#
-# IN:
-#   $data   = [ string1 string2 ... ]
-#   $opts   = lc     : lowercase the values in the regexp
-#             sort   : sort (by length) the values in the regexp
-#             back   : create a regexp with a back reference
-#             escape : escape all strings in the regexp
-#
-# OUT:
-#   $regexp = '(string1|string2|...)'
-
-sub Date_InitStrings {
-  print "DEBUG: Date_InitStrings\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($data,$regexp,$opts)=@_;
-  my(@list)=@{ $data };
-
-  # Parse the options
-  my($lc,$sort,$back,$escape)=(0,0,0,0);
-  $lc=1     if ($opts =~ /lc/i);
-  $sort=1   if ($opts =~ /sort/i);
-  $back=1   if ($opts =~ /back/i);
-  $escape=1 if ($opts =~ /escape/i);
-
-  # Create the regular expression
-  my($ele)=();
-  @list=sort sortByLength(@list)  if ($sort);
-  if ($escape) {
-    foreach $ele (@list) {
-      $ele="\Q$ele\E";
-    }
-  }
-  if ($back) {
-    $$regexp="(" . join("|",@list) . ")";
-  } else {
-    $$regexp="(?:" . join("|",@list) . ")";
-  }
-  $$regexp=lc($$regexp)  if ($lc);
-}
-
-# items is passed in (either as a space separated string, or a reference to
-# a list) and a regular expression which matches any one of the items is
-# prepared.  The regular expression will be of one of the forms:
-#   "(a|b)"       @list not empty, back option included
-#   "(?:a|b)"     @list not empty
-#   "()"          @list empty,     back option included
-#   ""            @list empty
-# $options is a string which contains any of the following strings:
-#   back     : the regular expression has a backreference
-#   opt      : the regular expression is optional and a "?" is appended in
-#              the first two forms
-#   optws    : the regular expression is optional and may be replaced by
-#              whitespace
-#   optWs    : the regular expression is optional, but if not present, must
-#              be replaced by whitespace
-#   sort     : the items in the list are sorted by length (longest first)
-#   lc       : the string is lowercased
-#   under    : any underscores are converted to spaces
-#   pre      : it may be preceded by whitespace
-#   Pre      : it must be preceded by whitespace
-#   PRE      : it must be preceded by whitespace or the start
-#   post     : it may be followed by whitespace
-#   Post     : it must be followed by whitespace
-#   POST     : it must be followed by whitespace or the end
-# Spaces due to pre/post options will not be included in the back reference.
-#
-# If $array is included, then the elements will also be returned as a list.
-# $array is a string which may contain any of the following:
-#   keys     : treat the list as a hash and only the keys go into the regexp
-#   key0     : treat the list as the values of a hash with keys 0 .. N-1
-#   key1     : treat the list as the values of a hash with keys 1 .. N
-#   val0     : treat the list as the keys of a hash with values 0 .. N-1
-#   val1     : treat the list as the keys of a hash with values 1 .. N
-
-#    &Date_InitLists([$lang{"month_name"},$lang{"month_abb"}],
-#             [\$Month,"lc,sort,back"],
-#             [\@Month,\@Mon],
-#             [\%Month,1]);
-
-# This is used in Date_Init to prepare regular expressions.  A list of
-# items is passed in (either as a space separated string, or a reference to
-# a list) and a regular expression which matches any one of the items is
-# prepared.  The regular expression will be of one of the forms:
-#   "(a|b)"       @list not empty, back option included
-#   "(?:a|b)"     @list not empty
-#   "()"          @list empty,     back option included
-#   ""            @list empty
-# $options is a string which contains any of the following strings:
-#   back     : the regular expression has a backreference
-#   opt      : the regular expression is optional and a "?" is appended in
-#              the first two forms
-#   optws    : the regular expression is optional and may be replaced by
-#              whitespace
-#   optWs    : the regular expression is optional, but if not present, must
-#              be replaced by whitespace
-#   sort     : the items in the list are sorted by length (longest first)
-#   lc       : the string is lowercased
-#   under    : any underscores are converted to spaces
-#   pre      : it may be preceded by whitespace
-#   Pre      : it must be preceded by whitespace
-#   PRE      : it must be preceded by whitespace or the start
-#   post     : it may be followed by whitespace
-#   Post     : it must be followed by whitespace
-#   POST     : it must be followed by whitespace or the end
-# Spaces due to pre/post options will not be included in the back reference.
-#
-# If $array is included, then the elements will also be returned as a list.
-# $array is a string which may contain any of the following:
-#   keys     : treat the list as a hash and only the keys go into the regexp
-#   key0     : treat the list as the values of a hash with keys 0 .. N-1
-#   key1     : treat the list as the values of a hash with keys 1 .. N
-#   val0     : treat the list as the keys of a hash with values 0 .. N-1
-#   val1     : treat the list as the keys of a hash with values 1 .. N
-sub Date_Regexp {
-  print "DEBUG: Date_Regexp\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($list,$options,$array)=@_;
-  my(@list,$ret,%hash,$i)=();
-  local($_)=();
-  $options=""  if (! defined $options);
-  $array=""    if (! defined $array);
-
-  my($sort,$lc,$under)=(0,0,0);
-  $sort =1  if ($options =~ /sort/i);
-  $lc   =1  if ($options =~ /lc/i);
-  $under=1  if ($options =~ /under/i);
-  my($back,$opt,$pre,$post,$ws)=("?:","","","","");
-  $back =""          if ($options =~ /back/i);
-  $opt  ="?"         if ($options =~ /opt/i);
-  $pre  ='\s*'       if ($options =~ /pre/);
-  $pre  ='\s+'       if ($options =~ /Pre/);
-  $pre  ='(?:\s+|^)' if ($options =~ /PRE/);
-  $post ='\s*'       if ($options =~ /post/);
-  $post ='\s+'       if ($options =~ /Post/);
-  $post ='(?:$|\s+)' if ($options =~ /POST/);
-  $ws   ='\s*'       if ($options =~ /optws/);
-  $ws   ='\s+'       if ($options =~ /optws/);
-
-  my($hash,$keys,$key0,$key1,$val0,$val1)=(0,0,0,0,0,0);
-  $keys =1     if ($array =~ /keys/i);
-  $key0 =1     if ($array =~ /key0/i);
-  $key1 =1     if ($array =~ /key1/i);
-  $val0 =1     if ($array =~ /val0/i);
-  $val1 =1     if ($array =~ /val1/i);
-  $hash =1     if ($keys or $key0 or $key1 or $val0 or $val1);
-
-  my($ref)=ref $list;
-  if (! $ref) {
-    $list =~ s/\s*$//;
-    $list =~ s/^\s*//;
-    $list =~ s/\s+/&&&/g;
-  } elsif ($ref eq "ARRAY") {
-    $list = join("&&&",@$list);
-  } else {
-    confess "ERROR: Date_Regexp.\n";
-  }
-
-  if (! $list) {
-    if ($back eq "") {
-      return "()";
-    } else {
-      return "";
-    }
-  }
-
-  $list=lc($list)  if ($lc);
-  $list=~ s/_/ /g  if ($under);
-  @list=split(/&&&/,$list);
-  if ($keys) {
-    %hash=@list;
-    @list=keys %hash;
-  } elsif ($key0 or $key1 or $val0 or $val1) {
-    $i=0;
-    $i=1  if ($key1 or $val1);
-    if ($key0 or $key1) {
-      %hash= map { $_,$i++ } @list;
-    } else {
-      %hash= map { $i++,$_ } @list;
-    }
-  }
-  @list=sort sortByLength(@list)  if ($sort);
-
-  $ret="($back" . join("|",@list) . ")";
-  $ret="(?:$pre$ret$post)"  if ($pre or $post);
-  $ret.=$opt;
-  $ret="(?:$ret|$ws)"  if ($ws);
-
-  if ($array and $hash) {
-    return ($ret,%hash);
-  } elsif ($array) {
-    return ($ret,@list);
-  } else {
-    return $ret;
-  }
-}
-
-# This will produce a delta with the correct number of signs.  At most two
-# signs will be in it normally (one before the year, and one in front of
-# the day), but if appropriate, signs will be in front of all elements.
-# Also, as many of the signs will be equivalent as possible.
-sub Delta_Normalize {
-  print "DEBUG: Delta_Normalize\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($delta,$mode)=@_;
-  return "" if (! $delta);
-  return "+0:+0:+0:+0:+0:+0:+0"
-    if ($delta =~ /^([+-]?0+:){6}[+-]?0+$/ and $Cnf{"DeltaSigns"});
-  return "+0:0:0:0:0:0:0" if ($delta =~ /^([+-]?0+:){6}[+-]?0+$/);
-
-  my($tmp,$sign1,$sign2,$len)=();
-
-  # Calculate the length of the day in minutes
-  $len=24*60;
-  $len=$Curr{"WDlen"}  if ($mode==2 || $mode==3);
-
-  # We have to get the sign of every component explicitely so that a "-0"
-  # or "+0" doesn't get lost by treating it numerically (i.e. "-0:0:2" must
-  # be a negative delta).
-
-  my($y,$mon,$w,$d,$h,$m,$s)=&Delta_Split($delta);
-
-  # We need to make sure that the signs of all parts of a delta are the
-  # same.  The easiest way to do this is to convert all of the large
-  # components to the smallest ones, then convert the smaller components
-  # back to the larger ones.
-
-  # Do the year/month part
-
-  $mon += $y*12;                         # convert y to m
-  $sign1="+";
-  if ($mon<0) {
-    $mon *= -1;
-    $sign1="-";
-  }
-
-  $y    = $mon/12;                       # convert m to y
-  $mon -= $y*12;
-
-  $y=0    if ($y eq "-0");               # get around silly -0 problem
-  $mon=0  if ($mon eq "-0");
-
-  # Do the wk/day/hour/min/sec part
-
-  {
-    # Unfortunately, $s is overflowing for dates more than ~70 years
-    # apart.
-    no integer;
-
-    if ($mode==3 || $mode==2) {
-      $s += $d*$len*60 + $h*3600 + $m*60;        # convert d/h/m to s
-    } else {
-      $s += ($d+7*$w)*$len*60 + $h*3600 + $m*60; # convert w/d/h/m to s
-    }
-    $sign2="+";
-    if ($s<0) {
-      $s*=-1;
-      $sign2="-";
-    }
-
-    $m  = int($s/60);                    # convert s to m
-    $s -= $m*60;
-    $d  = int($m/$len);                  # convert m to d
-    $m -= $d*$len;
-
-    # The rest should be fine.
-  }
-  $h  = $m/60;                           # convert m to h
-  $m -= $h*60;
-  if ($mode == 3 || $mode == 2) {
-    $w  = $w*1;                          # get around +0 problem
-  } else {
-    $w  = $d/7;                          # convert d to w
-    $d -= $w*7;
-  }
-
-  $w=0    if ($w eq "-0");               # get around silly -0 problem
-  $d=0    if ($d eq "-0");
-  $h=0    if ($h eq "-0");
-  $m=0    if ($m eq "-0");
-  $s=0    if ($s eq "-0");
-
-  # Only include two signs if necessary
-  $sign1=$sign2  if ($y==0 and $mon==0);
-  $sign2=$sign1  if ($w==0 and $d==0 and $h==0 and $m==0 and $s==0);
-  $sign2=""  if ($sign1 eq $sign2  and  ! $Cnf{"DeltaSigns"});
-
-  if ($Cnf{"DeltaSigns"}) {
-    return "$sign1$y:$sign1$mon:$sign2$w:$sign2$d:$sign2$h:$sign2$m:$sign2$s";
-  } else {
-    return "$sign1$y:$mon:$sign2$w:$d:$h:$m:$s";
-  }
-}
-
-# This checks a delta to make sure it is valid.  If it is, it splits
-# it and returns the elements with a sign on each.  The 2nd argument
-# specifies the default sign.  Blank elements are set to 0.  If the
-# third element is non-nil, exactly 7 elements must be included.
-sub Delta_Split {
-  print "DEBUG: Delta_Split\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($delta,$sign,$exact)=@_;
-  my(@delta)=split(/:/,$delta);
-  return ()  if ($exact  and $#delta != 6);
-  my($i)=();
-  $sign="+"  if (! defined $sign);
-  for ($i=0; $i<=$#delta; $i++) {
-    $delta[$i]="0"  if (! $delta[$i]);
-    return ()  if ($delta[$i] !~ /^[+-]?\d+$/);
-    $sign = ($delta[$i] =~ s/^([+-])// ? $1 : $sign);
-    $delta[$i] = $sign.$delta[$i];
-  }
-  @delta;
-}
-
-# Reads up to 3 arguments.  $h may contain the time in any international
-# format.  Any empty elements are set to 0.
-sub Date_ParseTime {
-  print "DEBUG: Date_ParseTime\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($h,$m,$s)=@_;
-  my($t)=&CheckTime("one");
-
-  if (defined $h  and  $h =~ /$t/) {
-    $h=$1;
-    $m=$2;
-    $s=$3   if (defined $3);
-  }
-  $h="00"  if (! defined $h);
-  $m="00"  if (! defined $m);
-  $s="00"  if (! defined $s);
-
-  ($h,$m,$s);
-}
-
-# Forms a date with the 6 elements passed in (all of which must be defined).
-# No check as to validity is made.
-sub Date_Join {
-  print "DEBUG: Date_Join\n"  if ($Curr{"Debug"} =~ /trace/);
-  foreach (0 .. $#_) {
-      croak "undefined arg $_ to Date_Join()" if not defined $_[$_];
-  }
-  my($y,$m,$d,$h,$mn,$s)=@_;
-  my($ym,$md,$dh,$hmn,$mns)=();
-
-  if      ($Cnf{"Internal"} == 0) {
-    $ym=$md=$dh="";
-    $hmn=$mns=":";
-
-  } elsif ($Cnf{"Internal"} == 1) {
-    $ym=$md=$dh=$hmn=$mns="";
-
-  } elsif ($Cnf{"Internal"} == 2) {
-    $ym=$md="-";
-    $dh=" ";
-    $hmn=$mns=":";
-
-  } else {
-    confess "ERROR: Invalid internal format in Date_Join.\n";
-  }
-  $m="0$m"    if (length($m)==1);
-  $d="0$d"    if (length($d)==1);
-  $h="0$h"    if (length($h)==1);
-  $mn="0$mn"  if (length($mn)==1);
-  $s="0$s"    if (length($s)==1);
-  "$y$ym$m$md$d$dh$h$hmn$mn$mns$s";
-}
-
-# This checks a time.  If it is valid, it splits it and returns 3 elements.
-# If "one" or "two" is passed in, a regexp with 1/2 or 2 digit hours is
-# returned.
-sub CheckTime {
-  print "DEBUG: CheckTime\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($time)=@_;
-  my($h)='(?:0?[0-9]|1[0-9]|2[0-3])';
-  my($h2)='(?:0[0-9]|1[0-9]|2[0-3])';
-  my($m)='[0-5][0-9]';
-  my($s)=$m;
-  my($hm)="(?:". $Lang{$Cnf{"Language"}}{"SepHM"} ."|:)";
-  my($ms)="(?:". $Lang{$Cnf{"Language"}}{"SepMS"} ."|:)";
-  my($ss)=$Lang{$Cnf{"Language"}}{"SepSS"};
-  my($t)="^($h)$hm($m)(?:$ms($s)(?:$ss\\d+)?)?\$";
-  if ($time eq "one") {
-    return $t;
-  } elsif ($time eq "two") {
-    $t="^($h2)$hm($m)(?:$ms($s)(?:$ss\\d+)?)?\$";
-    return $t;
-  }
-
-  if ($time =~ /$t/i) {
-    ($h,$m,$s)=($1,$2,$3);
-    $h="0$h" if (length($h)<2);
-    $m="0$m" if (length($m)<2);
-    $s="00"  if (! defined $s);
-    return ($h,$m,$s);
-  } else {
-    return ();
-  }
-}
-
-# This checks a recurrence.  If it is valid, it splits it and returns the
-# elements.  Otherwise, it returns an empty list.
-#    ($recur0,$recur1,$flags,$dateb,$date0,$date1)=&Recur_Split($recur);
-sub Recur_Split {
-  print "DEBUG: Recur_Split\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($recur)=@_;
-  my(@ret,@tmp);
-
-  my($R)  = '(\*?(?:[-,0-9]+[:\*]){6}[-,0-9]+)';
-  my($F)  = '(?:\*([^*]*))';
-  my($DB,$D0,$D1);
-  $DB=$D0=$D1=$F;
-
-  if ($recur =~ /^$R$F?$DB?$D0?$D1?$/) {
-    @ret=($1,$2,$3,$4,$5);
-    @tmp=split(/\*/,shift(@ret));
-    return ()  if ($#tmp>1);
-    return (@tmp,"",@ret)  if ($#tmp==0);
-    return (@tmp,@ret);
-  }
-  return ();
-}
-
-# This checks a date.  If it is valid, it splits it and returns the elements.
-# If no date is passed in, it returns a regular expression for the date.
-#
-# The optional second argument says 'I really expect this to be a
-# valid Date::Manip object, please throw an exception if it is
-# not'.  Otherwise, errors are signalled by returning ().
-#
-sub Date_Split {
-  print "DEBUG: Date_Split\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($date, $definitely_valid)=@_;
-  $definitely_valid = 0 if not defined $definitely_valid;
-  my($ym,$md,$dh,$hmn,$mns)=();
-  my($y)='(\d{4})';
-  my($m)='(0[1-9]|1[0-2])';
-  my($d)='(0[1-9]|[1-2][0-9]|3[0-1])';
-  my($h)='([0-1][0-9]|2[0-3])';
-  my($mn)='([0-5][0-9])';
-  my($s)=$mn;
-
-  if      ($Cnf{"Internal"} == 0) {
-    $ym=$md=$dh="";
-    $hmn=$mns=":";
-
-  } elsif ($Cnf{"Internal"} == 1) {
-    $ym=$md=$dh=$hmn=$mns="";
-
-  } elsif ($Cnf{"Internal"} == 2) {
-    $ym=$md="-";
-    $dh=" ";
-    $hmn=$mns=":";
-
-  } else {
-    confess "ERROR: Invalid internal format in Date_Split.\n";
-  }
-
-  my($t)="^$y$ym$m$md$d$dh$h$hmn$mn$mns$s\$";
-
-  if (not defined $date or $date eq '') {
-      if ($definitely_valid) {
-	  die "bad date '$date'";
-      } else {
-	  return $t;
-      }
-  }
-
-  if ($date =~ /$t/) {
-    ($y,$m,$d,$h,$mn,$s)=($1,$2,$3,$4,$5,$6);
-    my(@d_in_m)=(0,31,28,31,30,31,30,31,31,30,31,30,31);
-    $d_in_m[2]=29  if (&Date_LeapYear($y));
-    if ($d>$d_in_m[$m]) {
-	my $msg = "invalid date $date: day $d of month $m, but only $d_in_m[$m] days in that month";
-	if ($definitely_valid) {
-	    die $msg;
-	}
-	else {
-	    warn $msg;
-	    return ();
-	}
-    }
-    return ($y,$m,$d,$h,$mn,$s);
-  }
-
-  if ($definitely_valid) {
-      die "invalid date $date: doesn't match regexp $t";
-  }
-  return ();
-}
-
-# This returns the date easter occurs on for a given year as ($month,$day).
-# This is from the Calendar FAQ.
-sub Date_Easter {
-  my($y)=@_;
-  $y=&Date_FixYear($y)  if (length($y)==2);
-
-  my($c) = $y/100;
-  my($g) = $y % 19;
-  my($k) = ($c-17)/25;
-  my($i) = ($c - $c/4 - ($c-$k)/3 + 19*$g + 15) % 30;
-  $i     = $i - ($i/28)*(1 - ($i/28)*(29/($i+1))*((21-$g)/11));
-  my($j) = ($y + $y/4 + $i + 2 - $c + $c/4) % 7;
-  my($l) = $i-$j;
-  my($m) = 3 + ($l+40)/44;
-  my($d) = $l + 28 - 31*($m/4);
-  return ($m,$d);
-}
-
-# This takes a list of years, months, WeekOfMonth's, and optionally
-# DayOfWeek's, and returns a list of dates.  Optionally, a list of dates
-# can be passed in as the 1st argument (with the 2nd argument the null list)
-# and the year/month of these will be used.
-#
-# If $FDn is non-zero, the first week of the month contains the first
-# occurence of this day (1=Monday).  If $FIn is non-zero, the first week of
-# the month contains the date (i.e. $FIn'th day of the month).
-sub Date_Recur_WoM {
-  my($y,$m,$w,$d,$FDn,$FIn)=@_;
-  my(@y)=@$y;
-  my(@m)=@$m;
-  my(@w)=@$w;
-  my(@d)=@$d;
-  my($date0,$date1,@tmp,@date,$d0,$d1,@tmp2)=();
-
-  if (@m) {
-    @tmp=();
-    foreach $y (@y) {
-      return ()  if (length($y)==1 || length($y)==3 || ! &IsInt($y,0,9999));
-      $y=&Date_FixYear($y)  if (length($y)==2);
-      push(@tmp,$y);
-    }
-    @y=sort { $a<=>$b } (@tmp);
-
-    return ()  if (! @m);
-    foreach $m (@m) {
-      return ()  if (! &IsInt($m,1,12));
-    }
-    @m=sort { $a<=>$b } (@m);
-
-    @tmp=@tmp2=();
-    foreach $y (@y) {
-      foreach $m (@m) {
-        push(@tmp,$y);
-        push(@tmp2,$m);
-      }
-    }
-
-    @y=@tmp;
-    @m=@tmp2;
-
-  } else {
-    foreach $d0 (@y) {
-      @tmp=&Date_Split($d0);
-      return ()  if (! @tmp);
-      push(@tmp2,$tmp[0]);
-      push(@m,$tmp[1]);
-    }
-    @y=@tmp2;
-  }
-
-  return ()  if (! @w);
-  foreach $w (@w) {
-    return ()  if ($w==0  ||  ! &IsInt($w,-5,5));
-  }
-
-  if (@d) {
-    foreach $d (@d) {
-      return ()  if (! &IsInt($d,1,7));
-    }
-    @d=sort { $a<=>$b } (@d);
-  }
-
-  @date=();
-  foreach $y (@y) {
-    $m=shift(@m);
-
-    # Find 1st day of this month and next month
-    $date0=&Date_Join($y,$m,1,0,0,0);
-    $date1=&DateCalc($date0,"+0:1:0:0:0:0:0");
-
-    if (@d) {
-      foreach $d (@d) {
-        # Find 1st occurence of DOW (in both months)
-        $d0=&Date_GetNext($date0,$d,1);
-        $d1=&Date_GetNext($date1,$d,1);
-
-        @tmp=();
-        while (&Date_Cmp($d0,$d1)<0) {
-          push(@tmp,$d0);
-          $d0=&DateCalc($d0,"+0:0:1:0:0:0:0");
-        }
-
-        @tmp2=();
-        foreach $w (@w) {
-          if ($w>0) {
-            push(@tmp2,$tmp[$w-1]);
-          } else {
-            push(@tmp2,$tmp[$#tmp+1+$w]);
-          }
-        }
-        @tmp2=sort(@tmp2);
-        push(@date,@tmp2);
-      }
-
-    } else {
-      # Find 1st day of 1st week
-      if ($FDn != 0) {
-        $date0=&Date_GetNext($date0,$FDn,1);
-      } else {
-        $date0=&Date_Join($y,$m,$FIn,0,0,0);
-      }
-      $date0=&Date_GetPrev($date0,$Cnf{"FirstDay"},1);
-
-      # Find 1st day of 1st week of next month
-      if ($FDn != 0) {
-        $date1=&Date_GetNext($date1,$FDn,1);
-      } else {
-        $date1=&DateCalc($date1,"+0:0:0:".($FIn-1).":0:0:0")  if ($FIn>1);
-      }
-      $date1=&Date_GetPrev($date1,$Cnf{"FirstDay"},1);
-
-      @tmp=();
-      while (&Date_Cmp($date0,$date1)<0) {
-        push(@tmp,$date0);
-        $date0=&DateCalc($date0,"+0:0:1:0:0:0:0");
-      }
-
-      @tmp2=();
-      foreach $w (@w) {
-        if ($w>0) {
-          push(@tmp2,$tmp[$w-1]);
-        } else {
-          push(@tmp2,$tmp[$#tmp+1+$w]);
-        }
-      }
-      @tmp2=sort(@tmp2);
-      push(@date,@tmp2);
-    }
-  }
-
-  @date;
-}
-
-# This returns a sorted list of dates formed by adding/subtracting
-# $delta to $dateb in the range $date0<=$d<$dateb.  The first date int
-# the list is actually the first date<$date0 and the last date in the
-# list is the first date>=$date1 (because sometimes the set part will
-# move the date back into the range).
-sub Date_Recur {
-  my($date0,$date1,$dateb,$delta)=@_;
-  my(@ret,$d)=();
-
-  while (&Date_Cmp($dateb,$date0)<0) {
-    $dateb=&DateCalc_DateDelta($dateb,$delta);
-  }
-  while (&Date_Cmp($dateb,$date1)>=0) {
-    $dateb=&DateCalc_DateDelta($dateb,"-$delta");
-  }
-
-  # Add the dates $date0..$dateb
-  $d=$dateb;
-  while (&Date_Cmp($d,$date0)>=0) {
-    unshift(@ret,$d);
-    $d=&DateCalc_DateDelta($d,"-$delta");
-  }
-  # Add the first date earler than the range
-  unshift(@ret,$d);
-
-  # Add the dates $dateb..$date1
-  $d=&DateCalc_DateDelta($dateb,$delta);
-  while (&Date_Cmp($d,$date1)<0) {
-    push(@ret,$d);
-    $d=&DateCalc_DateDelta($d,$delta);
-  }
-  # Add the first date later than the range
-  push(@ret,$d);
-
-  @ret;
-}
-
-# This sets the values in each date of a recurrence.
-#
-# $h,$m,$s can each be values or lists "1-2,4".  If any are equal to "-1",
-# they are not set (and none of the larger elements are set).
-sub Date_RecurSetTime {
-  my($date0,$date1,$dates,$h,$m,$s)=@_;
-  my(@dates)=@$dates;
-  my(@h,@m,@s,$date,@tmp)=();
-
-  $m="-1"  if ($s eq "-1");
-  $h="-1"  if ($m eq "-1");
-
-  if ($h ne "-1") {
-    @h=&ReturnList($h);
-    return ()  if ! (@h);
-    @h=sort { $a<=>$b } (@h);
-
-    @tmp=();
-    foreach $date (@dates) {
-      foreach $h (@h) {
-        push(@tmp,&Date_SetDateField($date,"h",$h,1));
-      }
-    }
-    @dates=@tmp;
-  }
-
-  if ($m ne "-1") {
-    @m=&ReturnList($m);
-    return ()  if ! (@m);
-    @m=sort { $a<=>$b } (@m);
-
-    @tmp=();
-    foreach $date (@dates) {
-      foreach $m (@m) {
-        push(@tmp,&Date_SetDateField($date,"mn",$m,1));
-      }
-    }
-    @dates=@tmp;
-  }
-
-  if ($s ne "-1") {
-    @s=&ReturnList($s);
-    return ()  if ! (@s);
-    @s=sort { $a<=>$b } (@s);
-
-    @tmp=();
-    foreach $date (@dates) {
-      foreach $s (@s) {
-        push(@tmp,&Date_SetDateField($date,"s",$s,1));
-      }
-    }
-    @dates=@tmp;
-  }
-
-  @tmp=();
-  foreach $date (@dates) {
-    push(@tmp,$date)  if (&Date_Cmp($date,$date0)>=0  &&
-                          &Date_Cmp($date,$date1)<0  &&
-                          &Date_Split($date));
-  }
-
-  @tmp;
-}
-
-sub DateCalc_DateDate {
-  print "DEBUG: DateCalc_DateDate\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($D1,$D2,$mode)=@_;
-  my(@d_in_m)=(0,31,28,31,30,31,30,31,31,30,31,30,31);
-  $mode=0  if (! defined $mode);
-
-  # Exact mode
-  if ($mode==0) {
-    my($y1,$m1,$d1,$h1,$mn1,$s1)=&Date_Split($D1, 1);
-    my($y2,$m2,$d2,$h2,$mn2,$s2)=&Date_Split($D2, 1);
-    my($i,@delta,$d,$delta,$y)=();
-
-    # form the delta for hour/min/sec
-    $delta[4]=$h2-$h1;
-    $delta[5]=$mn2-$mn1;
-    $delta[6]=$s2-$s1;
-
-    # form the delta for yr/mon/day
-    $delta[0]=$delta[1]=0;
-    $d=0;
-    if ($y2>$y1) {
-      $d=&Date_DaysInYear($y1) - &Date_DayOfYear($m1,$d1,$y1);
-      $d+=&Date_DayOfYear($m2,$d2,$y2);
-      for ($y=$y1+1; $y<$y2; $y++) {
-        $d+= &Date_DaysInYear($y);
-      }
-    } elsif ($y2<$y1) {
-      $d=&Date_DaysInYear($y2) - &Date_DayOfYear($m2,$d2,$y2);
-      $d+=&Date_DayOfYear($m1,$d1,$y1);
-      for ($y=$y2+1; $y<$y1; $y++) {
-        $d+= &Date_DaysInYear($y);
-      }
-      $d *= -1;
-    } else {
-      $d=&Date_DayOfYear($m2,$d2,$y2) - &Date_DayOfYear($m1,$d1,$y1);
-    }
-    $delta[2]=0;
-    $delta[3]=$d;
-
-    for ($i=0; $i<7; $i++) {
-      $delta[$i]="+".$delta[$i]  if ($delta[$i]>=0);
-    }
-
-    $delta=join(":",@delta);
-    $delta=&Delta_Normalize($delta,0);
-    return $delta;
-  }
-
-  my($date1,$date2)=($D1,$D2);
-  my($tmp,$sign,$err,@tmp)=();
-
-  # make sure both are work days
-  if ($mode==2 || $mode==3) {
-    $date1=&Date_NextWorkDay($date1,0,1);
-    $date2=&Date_NextWorkDay($date2,0,1);
-  }
-
-  # make sure date1 comes before date2
-  if (&Date_Cmp($date1,$date2)>0) {
-    $sign="-";
-    $tmp=$date1;
-    $date1=$date2;
-    $date2=$tmp;
-  } else {
-    $sign="+";
-  }
-  if (&Date_Cmp($date1,$date2)==0) {
-    return "+0:+0:+0:+0:+0:+0:+0"  if ($Cnf{"DeltaSigns"});
-    return "+0:0:0:0:0:0:0";
-  }
-
-  my($y1,$m1,$d1,$h1,$mn1,$s1)=&Date_Split($date1, 1);
-  my($y2,$m2,$d2,$h2,$mn2,$s2)=&Date_Split($date2, 1);
-  my($dy,$dm,$dw,$dd,$dh,$dmn,$ds,$ddd)=(0,0,0,0,0,0,0,0);
-
-  if ($mode != 3) {
-
-    # Do years
-    $dy=$y2-$y1;
-    $dm=0;
-    if ($dy>0) {
-      $tmp=&DateCalc_DateDelta($date1,"+$dy:0:0:0:0:0:0",\$err,0);
-      if (&Date_Cmp($tmp,$date2)>0) {
-        $dy--;
-        $tmp=$date1;
-        $tmp=&DateCalc_DateDelta($date1,"+$dy:0:0:0:0:0:0",\$err,0)
-          if ($dy>0);
-        $dm=12;
-      }
-      $date1=$tmp;
-    }
-
-    # Do months
-    $dm+=$m2-$m1;
-    if ($dm>0) {
-      $tmp=&DateCalc_DateDelta($date1,"+0:$dm:0:0:0:0:0",\$err,0);
-      if (&Date_Cmp($tmp,$date2)>0) {
-        $dm--;
-        $tmp=$date1;
-        $tmp=&DateCalc_DateDelta($date1,"+0:$dm:0:0:0:0:0",\$err,0)
-          if ($dm>0);
-      }
-      $date1=$tmp;
-    }
-
-    # At this point, check to see that we're on a business day again so that
-    # Aug 3 (Monday) -> Sep 3 (Sunday) -> Sep 4 (Monday)  = 1 month
-    if ($mode==2) {
-      if (! &Date_IsWorkDay($date1,0)) {
-        $date1=&Date_NextWorkDay($date1,0,1);
-      }
-    }
-  }
-
-  # Do days
-  if ($mode==2 || $mode==3) {
-    $dd=0;
-    while (1) {
-      $tmp=&Date_NextWorkDay($date1,1,1);
-      if (&Date_Cmp($tmp,$date2)<=0) {
-        $dd++;
-        $date1=$tmp;
-      } else {
-        last;
-      }
-    }
-
-  } else {
-    ($y1,$m1,$d1)=( &Date_Split($date1, 1) )[0..2];
-    $dd=0;
-    # If we're jumping across months, set $d1 to the first of the next month
-    # (or possibly the 0th of next month which is equivalent to the last day
-    # of this month)
-    if ($m1!=$m2) {
-      $d_in_m[2]=29  if (&Date_LeapYear($y1));
-      $dd=$d_in_m[$m1]-$d1+1;
-      $d1=1;
-      $tmp=&DateCalc_DateDelta($date1,"+0:0:0:$dd:0:0:0",\$err,0);
-      if (&Date_Cmp($tmp,$date2)>0) {
-        $dd--;
-        $d1--;
-        $tmp=&DateCalc_DateDelta($date1,"+0:0:0:$dd:0:0:0",\$err,0);
-      }
-      $date1=$tmp;
-    }
-
-    $ddd=0;
-    if ($d1<$d2) {
-      $ddd=$d2-$d1;
-      $tmp=&DateCalc_DateDelta($date1,"+0:0:0:$ddd:0:0:0",\$err,0);
-      if (&Date_Cmp($tmp,$date2)>0) {
-        $ddd--;
-        $tmp=&DateCalc_DateDelta($date1,"+0:0:0:$ddd:0:0:0",\$err,0);
-      }
-      $date1=$tmp;
-    }
-    $dd+=$ddd;
-  }
-
-  # in business mode, make sure h1 comes before h2 (if not find delta between
-  # now and end of day and move to start of next business day)
-  $d1=( &Date_Split($date1, 1) )[2];
-  $dh=$dmn=$ds=0;
-  if ($mode==2 || $mode==3  and  $d1 != $d2) {
-    $tmp=&Date_SetTime($date1,$Cnf{"WorkDayEnd"});
-    $tmp=&DateCalc_DateDelta($tmp,"+0:0:0:0:0:1:0")
-      if ($Cnf{"WorkDay24Hr"});
-    $tmp=&DateCalc_DateDate($date1,$tmp,0);
-    ($tmp,$tmp,$tmp,$tmp,$dh,$dmn,$ds)=&Delta_Split($tmp);
-    $date1=&Date_NextWorkDay($date1,1,0);
-    $date1=&Date_SetTime($date1,$Cnf{"WorkDayBeg"});
-    $d1=( &Date_Split($date1, 1) )[2];
-    confess "ERROR: DateCalc DateDate Business.\n"  if ($d1 != $d2);
-  }
-
-  # Hours, minutes, seconds
-  $tmp=&DateCalc_DateDate($date1,$date2,0);
-  @tmp=&Delta_Split($tmp);
-  $dh  += $tmp[4];
-  $dmn += $tmp[5];
-  $ds  += $tmp[6];
-
-  $tmp="$sign$dy:$dm:0:$dd:$dh:$dmn:$ds";
-  &Delta_Normalize($tmp,$mode);
-}
-
-sub DateCalc_DeltaDelta {
-  print "DEBUG: DateCalc_DeltaDelta\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($D1,$D2,$mode)=@_;
-  my(@delta1,@delta2,$i,$delta,@delta)=();
-  $mode=0  if (! defined $mode);
-
-  @delta1=&Delta_Split($D1);
-  @delta2=&Delta_Split($D2);
-  for ($i=0; $i<7; $i++) {
-    $delta[$i]=$delta1[$i]+$delta2[$i];
-    $delta[$i]="+".$delta[$i]  if ($delta[$i]>=0);
-  }
-
-  $delta=join(":",@delta);
-  $delta=&Delta_Normalize($delta,$mode);
-  return $delta;
-}
-
-sub DateCalc_DateDelta {
-  print "DEBUG: DateCalc_DateDelta\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($D1,$D2,$errref,$mode)=@_;
-  my($date)=();
-  my(@d_in_m)=(0,31,28,31,30,31,30,31,31,30,31,30,31);
-  my($h1,$m1,$h2,$m2,$len,$hh,$mm)=();
-  $mode=0  if (! defined $mode);
-
-  if ($mode==2 || $mode==3) {
-    $h1=$Curr{"WDBh"};
-    $m1=$Curr{"WDBm"};
-    $h2=$Curr{"WDEh"};
-    $m2=$Curr{"WDEm"};
-    $hh=$h2-$h1;
-    $mm=$m2-$m1;
-    if ($mm<0) {
-      $hh--;
-      $mm+=60;
-    }
-  }
-
-  # Date, delta
-  my($y,$m,$d,$h,$mn,$s)=&Date_Split($D1, 1);
-  my($dy,$dm,$dw,$dd,$dh,$dmn,$ds)=&Delta_Split($D2);
-
-  # do the month/year part
-  $y+=$dy;
-  while (length($y)<4) {
-    $y = "0$y";
-  }
-  &ModuloAddition(-12,$dm,\$m,\$y);   # -12 means 1-12 instead of 0-11
-  $d_in_m[2]=29  if (&Date_LeapYear($y));
-
-  # if we have gone past the last day of a month, move the date back to
-  # the last day of the month
-  if ($d>$d_in_m[$m]) {
-    $d=$d_in_m[$m];
-  }
-
-  # do the week part
-  if ($mode==0  ||  $mode==1) {
-    $dd += $dw*7;
-  } else {
-    $date=&DateCalc_DateDelta(&Date_Join($y,$m,$d,$h,$mn,$s),
-                              "+0:0:$dw:0:0:0:0",0);
-    ($y,$m,$d,$h,$mn,$s)=&Date_Split($date, 1);
-  }
-
-  # in business mode, set the day to a work day at this point so the h/mn/s
-  # stuff will work out
-  if ($mode==2 || $mode==3) {
-    $d=$d_in_m[$m] if ($d>$d_in_m[$m]);
-    $date=&Date_NextWorkDay(&Date_Join($y,$m,$d,$h,$mn,$s),0,1);
-    ($y,$m,$d,$h,$mn,$s)=&Date_Split($date, 1);
-  }
-
-  # seconds, minutes, hours
-  &ModuloAddition(60,$ds,\$s,\$mn);
-  if ($mode==2 || $mode==3) {
-    while (1) {
-      &ModuloAddition(60,$dmn,\$mn,\$h);
-      $h+= $dh;
-
-      if ($h>$h2  or  $h==$h2 && $mn>$m2) {
-        $dh=$h-$h2;
-        $dmn=$mn-$m2;
-        $h=$h1;
-        $mn=$m1;
-        $dd++;
-
-      } elsif ($h<$h1  or  $h==$h1 && $mn<$m1) {
-        $dh=$h-$h1;
-        $dmn=$m1-$mn;
-        $h=$h2;
-        $mn=$m2;
-        $dd--;
-
-      } elsif ($h==$h2  &&  $mn==$m2) {
-        $dd++;
-        $dh=-$hh;
-        $dmn=-$mm;
-
-      } else {
-        last;
-      }
-    }
-
-  } else {
-    &ModuloAddition(60,$dmn,\$mn,\$h);
-    &ModuloAddition(24,$dh,\$h,\$d);
-  }
-
-  # If we have just gone past the last day of the month, we need to make
-  # up for this:
-  if ($d>$d_in_m[$m]) {
-    $dd+= $d-$d_in_m[$m];
-    $d=$d_in_m[$m];
-  }
-
-  # days
-  if ($mode==2 || $mode==3) {
-    if ($dd>=0) {
-      $date=&Date_NextWorkDay(&Date_Join($y,$m,$d,$h,$mn,$s),$dd,1);
-    } else {
-      $date=&Date_PrevWorkDay(&Date_Join($y,$m,$d,$h,$mn,$s),-$dd,1);
-    }
-    ($y,$m,$d,$h,$mn,$s)=&Date_Split($date, 1);
-
-  } else {
-    $d_in_m[2]=29  if (&Date_LeapYear($y));
-    $d=$d_in_m[$m]  if ($d>$d_in_m[$m]);
-    $d += $dd;
-    while ($d<1) {
-      $m--;
-      if ($m==0) {
-        $m=12;
-        $y--;
-        if (&Date_LeapYear($y)) {
-          $d_in_m[2]=29;
-        } else {
-          $d_in_m[2]=28;
-        }
-      }
-      $d += $d_in_m[$m];
-    }
-    while ($d>$d_in_m[$m]) {
-      $d -= $d_in_m[$m];
-      $m++;
-      if ($m==13) {
-        $m=1;
-        $y++;
-        if (&Date_LeapYear($y)) {
-          $d_in_m[2]=29;
-        } else {
-          $d_in_m[2]=28;
-        }
-      }
-    }
-  }
-
-  if ($y<0 or $y>9999) {
-    $$errref=3;
-    return;
-  }
-  &Date_Join($y,$m,$d,$h,$mn,$s);
-}
-
-sub Date_UpdateHolidays {
-  print "DEBUG: Date_UpdateHolidays\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($year)=@_;
-  $Holiday{"year"}=$year;
-  $Holiday{"dates"}{$year}={};
-
-  my($date,$delta,$err)=();
-  my($key,@tmp,$tmp);
-
-  foreach $key (keys %{ $Holiday{"desc"} }) {
-    @tmp=&Recur_Split($key);
-    if (@tmp) {
-      $tmp=&ParseDateString("${year}010100:00:00");
-      ($date)=&ParseRecur($key,$tmp,$tmp,($year+1)."-01-01");
-      next  if (! $date);
-
-    } elsif ($key =~ /^(.*)([+-].*)$/) {
-      # Date +/- Delta
-      ($date,$delta)=($1,$2);
-      $tmp=&ParseDateString("$date $year");
-      if ($tmp) {
-        $date=$tmp;
-      } else {
-        $date=&ParseDateString($date);
-        next  if ($date !~ /^$year/);
-      }
-      $date=&DateCalc($date,$delta,\$err,0);
-
-    } else {
-      # Date
-      $date=$key;
-      $tmp=&ParseDateString("$date $year");
-      if ($tmp) {
-        $date=$tmp;
-      } else {
-        $date=&ParseDateString($date);
-        next  if ($date !~ /^$year/);
-      }
-    }
-    $Holiday{"dates"}{$year}{$date}=$Holiday{"desc"}{$key};
-  }
-}
-
-# This sets a Date::Manip config variable.
-sub Date_SetConfigVariable {
-  print "DEBUG: Date_SetConfigVariable\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($var,$val)=@_;
-
-  # These are most appropriate for command line options instead of in files.
-  $Cnf{"PathSep"}=$val,          return  if ($var =~ /^PathSep$/i);
-  $Cnf{"PersonalCnf"}=$val,      return  if ($var =~ /^PersonalCnf$/i);
-  $Cnf{"PersonalCnfPath"}=$val,  return  if ($var =~ /^PersonalCnfPath$/i);
-  &EraseHolidays(),              return  if ($var =~ /^EraseHolidays$/i);
-  $Cnf{"IgnoreGlobalCnf"}=1,     return  if ($var =~ /^IgnoreGlobalCnf$/i);
-  $Cnf{"GlobalCnf"}=$val,        return  if ($var =~ /^GlobalCnf$/i);
-
-  $Curr{"InitLang"}=1,
-  $Cnf{"Language"}=$val,         return  if ($var =~ /^Language$/i);
-  $Cnf{"DateFormat"}=$val,       return  if ($var =~ /^DateFormat$/i);
-  $Cnf{"TZ"}=$val,               return  if ($var =~ /^TZ$/i);
-  $Cnf{"ConvTZ"}=$val,           return  if ($var =~ /^ConvTZ$/i);
-  $Cnf{"Internal"}=$val,         return  if ($var =~ /^Internal$/i);
-  $Cnf{"FirstDay"}=$val,         return  if ($var =~ /^FirstDay$/i);
-  $Cnf{"WorkWeekBeg"}=$val,      return  if ($var =~ /^WorkWeekBeg$/i);
-  $Cnf{"WorkWeekEnd"}=$val,      return  if ($var =~ /^WorkWeekEnd$/i);
-  $Cnf{"WorkDayBeg"}=$val,
-  $Curr{"ResetWorkDay"}=1,       return  if ($var =~ /^WorkDayBeg$/i);
-  $Cnf{"WorkDayEnd"}=$val,
-  $Curr{"ResetWorkDay"}=1,       return  if ($var =~ /^WorkDayEnd$/i);
-  $Cnf{"WorkDay24Hr"}=$val,
-  $Curr{"ResetWorkDay"}=1,       return  if ($var =~ /^WorkDay24Hr$/i);
-  $Cnf{"DeltaSigns"}=$val,       return  if ($var =~ /^DeltaSigns$/i);
-  $Cnf{"Jan1Week1"}=$val,        return  if ($var =~ /^Jan1Week1$/i);
-  $Cnf{"YYtoYYYY"}=$val,         return  if ($var =~ /^YYtoYYYY$/i);
-  $Cnf{"UpdateCurrTZ"}=$val,     return  if ($var =~ /^UpdateCurrTZ$/i);
-  $Cnf{"IntCharSet"}=$val,       return  if ($var =~ /^IntCharSet$/i);
-  $Curr{"DebugVal"}=$val,        return  if ($var =~ /^Debug$/i);
-  $Cnf{"TomorrowFirst"}=$val,    return  if ($var =~ /^TomorrowFirst$/i);
-  $Cnf{"ForceDate"}=$val,        return  if ($var =~ /^ForceDate$/i);
-
-  confess "ERROR: Unknown configuration variable $var in Date::Manip.\n";
-}
-
-sub EraseHolidays {
-  print "DEBUG: EraseHolidays\n"  if ($Curr{"Debug"} =~ /trace/);
-
-  $Cnf{"EraseHolidays"}=0;
-  delete $Holiday{"list"};
-  $Holiday{"list"}={};
-  delete $Holiday{"desc"};
-  $Holiday{"desc"}={};
-  $Holiday{"dates"}={};
-}
-
-# This returns a pointer to a list of times and events in the format
-#    [ date, [ events ], date, [ events ], ... ]
-# where each list of events are events that are in effect at the date
-# immediately preceding the list.
-#
-# This takes either one date or two dates as arguments.
-sub Events_Calc {
-  print "DEBUG: Events_Calc\n"  if ($Curr{"Debug"} =~ /trace/);
-
-  my($date0,$date1)=@_;
-
-  my($tmp);
-  $date0=&ParseDateString($date0);
-  return undef  if (! $date0);
-  if ($date1) {
-    $date1=&ParseDateString($date1);
-    if (&Date_Cmp($date0,$date1)>0) {
-      $tmp=$date1;
-      $date1=$date0;
-      $date0=$tmp;
-    }
-  } else {
-    $date1=&DateCalc_DateDelta($date0,"+0:0:0:0:0:0:1");
-  }
-
-  #
-  #   [ d0,d1,del,name ]     => [ d0, d1+del )
-  #   [ d0,0,del,name ]      => [ d0, d0+del )
-  #
-  my(%ret,$d0,$d1,$del,$name,$c0,$c1);
-  my(@tmp)=@{ $Events{"dates"} };
- DATE: while (@tmp) {
-    ($d0,$d1,$del,$name)=splice(@tmp,0,4);
-    $d0=&ParseDateString($d0);
-    $d1=&ParseDateString($d1)   if ($d1);
-    $del=&ParseDateDelta($del)  if ($del);
-    if ($d1) {
-      if ($del) {
-        $d1=&DateCalc_DateDelta($d1,$del);
-      }
-    } else {
-      $d1=&DateCalc_DateDelta($d0,$del);
-    }
-    if (&Date_Cmp($d0,$d1)>0) {
-      $tmp=$d1;
-      $d1=$d0;
-      $d0=$tmp;
-    }
-    #         [ date0,date1 )
-    # [ d0,d1 )      OR     [ d0,d1 )
-    next DATE  if (&Date_Cmp($d1,$date0)<=0  ||
-                   &Date_Cmp($d0,$date1)>=0);
-    #      [ date0,date1 )
-    # [ d0,d1 )
-    # [ d0,                  d1 )
-    if (&Date_Cmp($d0,$date0)<=0) {
-      push @{ $ret{$date0} },$name;
-      push @{ $ret{$d1} },"!$name"  if (&Date_Cmp($d1,$date1)<0);
-      next DATE;
-    }
-    #      [ date0,date1 )
-    #                 [ d0,d1 )
-    if (&Date_Cmp($d1,$date1)>=0) {
-      push @{ $ret{$d0} },$name;
-      next DATE;
-    }
-    #      [ date0,date1 )
-    #         [ d0,d1 )
-    push @{ $ret{$d0} },$name;
-    push @{ $ret{$d1} },"!$name";
-  }
-
-  #
-  #   [ recur,delta0,delta1,name ]   => [ {date-delta0},{date+delta1} )
-  #
-  my($rec,$del0,$del1,@d);
-  @tmp=@{ $Events{"recur"} };
- RECUR: while (@tmp) {
-    ($rec,$del0,$del1,$name)=splice(@tmp,0,4);
-    @d=();
-
-  }
-
-  # Sort them AND take into account the "!$name" entries.
-  my(%tmp,$date,@tmp2,@ret);
-  @d=sort { &Date_Cmp($a,$b) } keys %ret;
-  foreach $date (@d) {
-    @tmp=@{ $ret{$date} };
-    @tmp2=();
-    foreach $tmp (@tmp) {
-      push(@tmp2,$tmp), next  if ($tmp =~ /^!/);
-      $tmp{$tmp}=1;
-    }
-    foreach $tmp (@tmp2) {
-      $tmp =~ s/^!//;
-      delete $tmp{$tmp};
-    }
-    push(@ret,$date,[ keys %tmp ]);
-  }
-
-  return \@ret;
-}
-
-# This parses the raw events list
-sub Events_ParseRaw {
-  print "DEBUG: Events_ParseRaw\n"  if ($Curr{"Debug"} =~ /trace/);
-
-  # Only need to be parsed once
-  my($force)=@_;
-  $Events{"parsed"}=0  if ($force);
-  return  if ($Events{"parsed"});
-  $Events{"parsed"}=1;
-
-  my(@events)=@{ $Events{"raw"} };
-  my($event,$name,@event,$date0,$date1,$tmp,$delta,$recur0,$recur1,@recur,$r,
-     $recur);
- EVENT: while (@events) {
-    ($event,$name)=splice(@events,0,2);
-    @event=split(/\s*;\s*/,$event);
-
-    if ($#event == 0) {
-
-      if ($date0=&ParseDateString($event[0])) {
-        #
-        # date = event
-        #
-        $tmp=&ParseDateString("$event[0] 00:00:00");
-        if ($tmp  &&  $tmp eq $date0) {
-          $delta="+0:0:0:1:0:0:0";
-        } else {
-          $delta="+0:0:0:0:1:0:0";
-        }
-        push @{ $Events{"dates"} },($date0,0,$delta,$name);
-
-      } elsif ($recur=&ParseRecur($event[0])) {
-        #
-        # recur = event
-        #
-        ($recur0,$recur1)=&Recur_Split($recur);
-        if ($recur0) {
-          if ($recur1) {
-            $r="$recur0:$recur1";
-          } else {
-            $r=$recur0;
-          }
-        } else {
-          $r=$recur1;
-        }
-        (@recur)=split(/:/,$r);
-        if (pop(@recur)==0  &&  pop(@recur)==0  &&  pop(@recur)==0) {
-          $delta="+0:0:0:1:0:0:0";
-        } else {
-          $delta="+0:0:0:0:1:0:0";
-        }
-        push @{ $Events{"recur"} },($recur,0,$delta,$name);
-
-      } else {
-        # ??? = event
-        warn "WARNING: illegal event ignored [ @event ]\n";
-        next EVENT;
-      }
-
-    } elsif ($#event == 1) {
-
-      if ($date0=&ParseDateString($event[0])) {
-
-        if ($date1=&ParseDateString($event[1])) {
-          #
-          # date ; date = event
-          #
-          $tmp=&ParseDateString("$event[1] 00:00:00");
-          if ($tmp  &&  $tmp eq $date1) {
-            $date1=&DateCalc_DateDelta($date1,"+0:0:0:1:0:0:0");
-          }
-          push @{ $Events{"dates"} },($date0,$date1,0,$name);
-
-        } elsif ($delta=&ParseDateDelta($event[1])) {
-          #
-          # date ; delta = event
-          #
-          push @{ $Events{"dates"} },($date0,0,$delta,$name);
-
-        } else {
-          # date ; ??? = event
-          warn "WARNING: illegal event ignored [ @event ]\n";
-          next EVENT;
-        }
-
-      } elsif ($recur=&ParseRecur($event[0])) {
-
-        if ($delta=&ParseDateDelta($event[1])) {
-          #
-          # recur ; delta = event
-          #
-          push @{ $Events{"recur"} },($recur,0,$delta,$name);
-
-        } else {
-          # recur ; ??? = event
-          warn "WARNING: illegal event ignored [ @event ]\n";
-          next EVENT;
-        }
-
-      } else {
-        # ??? ; ??? = event
-        warn "WARNING: illegal event ignored [ @event ]\n";
-        next EVENT;
-      }
-
-    } else {
-      # date ; delta0 ; delta1 = event
-      # recur ; delta0 ; delta1 = event
-      # ??? ; ??? ; ??? ... = event
-      warn "WARNING: illegal event ignored [ @event ]\n";
-      next EVENT;
-    }
-  }
-}
-
-# This reads an init file.
-sub Date_InitFile {
-  print "DEBUG: Date_InitFile\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($file)=@_;
-  my($in)=new IO::File;
-  local($_)=();
-  my($section)="vars";
-  my($var,$val,$recur,$name)=();
-
-  $in->open($file)  ||  return;
-  while(defined ($_=<$in>)) {
-    chomp;
-    s/^\s+//;
-    s/\s+$//;
-    next  if (! $_  or  /^\#/);
-
-    if (/^\*holiday/i) {
-      $section="holiday";
-      &EraseHolidays()  if ($section =~ /holiday/i  &&  $Cnf{"EraseHolidays"});
-      next;
-    } elsif (/^\*events/i) {
-      $section="events";
-      next;
-    }
-
-    if ($section =~ /var/i) {
-      confess "ERROR: invalid Date::Manip config file line.\n  $_\n"
-        if (! /(.*\S)\s*=\s*(.*)$/);
-      ($var,$val)=($1,$2);
-      &Date_SetConfigVariable($var,$val);
-
-    } elsif ($section =~ /holiday/i) {
-      confess "ERROR: invalid Date::Manip config file line.\n  $_\n"
-        if (! /(.*\S)\s*=\s*(.*)$/);
-      ($recur,$name)=($1,$2);
-      $name=""  if (! defined $name);
-      $Holiday{"desc"}{$recur}=$name;
-
-    } elsif ($section =~ /events/i) {
-      confess "ERROR: invalid Date::Manip config file line.\n  $_\n"
-        if (! /(.*\S)\s*=\s*(.*)$/);
-      ($val,$var)=($1,$2);
-      push @{ $Events{"raw"} },($val,$var);
-
-    } else {
-      # A section not currently used by Date::Manip (but may be
-      # used by some extension to it).
-      next;
-    }
-  }
-  close($in);
-}
-
-# $flag=&Date_TimeCheck(\$h,\$mn,\$s,\$ampm);
-#   Returns 1 if any of the fields are bad.  All fields are optional, and
-#   all possible checks are done on the data.  If a field is not passed in,
-#   it is set to default values.  If data is missing, appropriate defaults
-#   are supplied.
-sub Date_TimeCheck {
-  print "DEBUG: Date_TimeCheck\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($h,$mn,$s,$ampm)=@_;
-  my($tmp1,$tmp2,$tmp3)=();
-
-  $$h=""     if (! defined $$h);
-  $$mn=""    if (! defined $$mn);
-  $$s=""     if (! defined $$s);
-  $$ampm=""  if (! defined $$ampm);
-  $$ampm=uc($$ampm)  if ($$ampm);
-
-  # Check hour
-  $tmp1=$Lang{$Cnf{"Language"}}{"AmPm"};
-  $tmp2="";
-  if ($$ampm =~ /^$tmp1$/i) {
-    $tmp3=$Lang{$Cnf{"Language"}}{"AM"};
-    $tmp2="AM"  if ($$ampm =~ /^$tmp3$/i);
-    $tmp3=$Lang{$Cnf{"Language"}}{"PM"};
-    $tmp2="PM"  if ($$ampm =~ /^$tmp3$/i);
-  } elsif ($$ampm) {
-    return 1;
-  }
-  if ($tmp2 eq "AM" || $tmp2 eq "PM") {
-    $$h="0$$h"    if (length($$h)==1);
-    return 1      if ($$h<1 || $$h>12);
-    $$h="00"      if ($tmp2 eq "AM"  and  $$h==12);
-    $$h += 12     if ($tmp2 eq "PM"  and  $$h!=12);
-  } else {
-    $$h="00"      if ($$h eq "");
-    $$h="0$$h"    if (length($$h)==1);
-    return 1      if (! &IsInt($$h,0,23));
-    $tmp2="AM"    if ($$h<12);
-    $tmp2="PM"    if ($$h>=12);
-  }
-  $$ampm=$Lang{$Cnf{"Language"}}{"AMstr"};
-  $$ampm=$Lang{$Cnf{"Language"}}{"PMstr"}  if ($tmp2 eq "PM");
-
-  # Check minutes
-  $$mn="00"       if ($$mn eq "");
-  $$mn="0$$mn"    if (length($$mn)==1);
-  return 1        if (! &IsInt($$mn,0,59));
-
-  # Check seconds
-  $$s="00"        if ($$s eq "");
-  $$s="0$$s"      if (length($$s)==1);
-  return 1        if (! &IsInt($$s,0,59));
-
-  return 0;
-}
-
-# $flag=&Date_DateCheck(\$y,\$m,\$d,\$h,\$mn,\$s,\$ampm,\$wk);
-#   Returns 1 if any of the fields are bad.  All fields are optional, and
-#   all possible checks are done on the data.  If a field is not passed in,
-#   it is set to default values.  If data is missing, appropriate defaults
-#   are supplied.
-#
-#   If the flag UpdateHolidays is set, the year is set to
-#   CurrHolidayYear.
-sub Date_DateCheck {
-  print "DEBUG: Date_DateCheck\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($y,$m,$d,$h,$mn,$s,$ampm,$wk)=@_;
-  my($tmp1,$tmp2,$tmp3)=();
-
-  my(@d_in_m)=(0,31,28,31,30,31,30,31,31,30,31,30,31);
-  my($curr_y)=$Curr{"Y"};
-  my($curr_m)=$Curr{"M"};
-  my($curr_d)=$Curr{"D"};
-  $$m=1, $$d=1  if (defined $$y and ! defined $$m and ! defined $$d);
-  $$y=""     if (! defined $$y);
-  $$m=""     if (! defined $$m);
-  $$d=""     if (! defined $$d);
-  $$wk=""    if (! defined $$wk);
-  $$d=$curr_d  if ($$y eq "" and $$m eq "" and $$d eq "");
-
-  # Check year.
-  $$y=$curr_y             if ($$y eq "");
-  $$y=&Date_FixYear($$y)  if (length($$y)<4);
-  return 1                if (! &IsInt($$y,0,9999));
-  $d_in_m[2]=29           if (&Date_LeapYear($$y));
-
-  # Check month
-  $$m=$curr_m             if ($$m eq "");
-  $$m=$Lang{$Cnf{"Language"}}{"MonthH"}{lc($$m)}
-    if (exists $Lang{$Cnf{"Language"}}{"MonthH"}{lc($$m)});
-  $$m="0$$m"              if (length($$m)==1);
-  return 1                if (! &IsInt($$m,1,12));
-
-  # Check day
-  $$d="01"                if ($$d eq "");
-  $$d="0$$d"              if (length($$d)==1);
-  return 1                if (! &IsInt($$d,1,$d_in_m[$$m]));
-  if ($$wk) {
-    $tmp1=&Date_DayOfWeek($$m,$$d,$$y);
-    $tmp2=$Lang{$Cnf{"Language"}}{"WeekH"}{lc($$wk)}
-      if (exists $Lang{$Cnf{"Language"}}{"WeekH"}{lc($$wk)});
-    return 1      if ($tmp1 != $tmp2);
-  }
-
-  return &Date_TimeCheck($h,$mn,$s,$ampm);
-}
-
-# Takes a year in 2 digit form and returns it in 4 digit form
-sub Date_FixYear {
-  print "DEBUG: Date_FixYear\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($y)=@_;
-  my($curr_y)=$Curr{"Y"};
-  $y=$curr_y  if (! defined $y  or  ! $y);
-  return $y  if (length($y)==4);
-  confess "ERROR: Invalid year ($y)\n"  if (length($y)!=2);
-  my($y1,$y2)=();
-
-  if (lc($Cnf{"YYtoYYYY"}) eq "c") {
-    $y1=substring($y,0,2);
-    $y="$y1$y";
-
-  } elsif ($Cnf{"YYtoYYYY"} =~ /^c(\d{2})$/i) {
-    $y1=$1;
-    $y="$y1$y";
-
-  } elsif ($Cnf{"YYtoYYYY"} =~ /^c(\d{2})(\d{2})$/i) {
-    $y1="$1$2";
-    $y ="$1$y";
-    $y += 100  if ($y<$y1);
-
-  } else {
-    $y1=$curr_y-$Cnf{"YYtoYYYY"};
-    $y2=$y1+99;
-    $y="19$y";
-    while ($y<$y1) {
-      $y+=100;
-    }
-    while ($y>$y2) {
-      $y-=100;
-    }
-  }
-  $y;
-}
-
-# &Date_NthWeekOfYear($y,$n);
-#   Returns a list of (YYYY,MM,DD) for the 1st day of the Nth week of the
-#   year.
-# &Date_NthWeekOfYear($y,$n,$dow,$flag);
-#   Returns a list of (YYYY,MM,DD) for the Nth DoW of the year.  If flag
-#   is nil, the first DoW of the year may actually be in the previous
-#   year (since the 1st week may include days from the previous year).
-#   If flag is non-nil, the 1st DoW of the year refers to the 1st one
-#   actually in the year
-sub Date_NthWeekOfYear {
-  print "DEBUG: Date_NthWeekOfYear\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($y,$n,$dow,$flag)=@_;
-  my($m,$d,$err,$tmp,$date,%dow)=();
-  $y=$Curr{"Y"}  if (! defined $y  or  ! $y);
-  $n=1       if (! defined $n  or  $n eq "");
-  return ()  if ($n<0  ||  $n>53);
-  if (defined $dow) {
-    $dow=lc($dow);
-    %dow=%{ $Lang{$Cnf{"Language"}}{"WeekH"} };
-    $dow=$dow{$dow}  if (exists $dow{$dow});
-    return ()  if ($dow<1 || $dow>7);
-    $flag=""   if (! defined $flag);
-  } else {
-    $dow="";
-    $flag="";
-  }
-
-  $y=&Date_FixYear($y)  if (length($y)<4);
-  if ($Cnf{"Jan1Week1"}) {
-    $date=&Date_Join($y,1,1,0,0,0);
-  } else {
-    $date=&Date_Join($y,1,4,0,0,0);
-  }
-  $date=&Date_GetPrev($date,$Cnf{"FirstDay"},1);
-  $date=&Date_GetNext($date,$dow,1)  if ($dow ne "");
-
-  if ($flag) {
-    ($tmp)=&Date_Split($date, 1);
-    $n++  if ($tmp != $y);
-  }
-
-  if ($n>1) {
-    $date=&DateCalc_DateDelta($date,"+0:0:". ($n-1) . ":0:0:0:0",\$err,0);
-  } elsif ($n==0) {
-    $date=&DateCalc_DateDelta($date,"-0:0:1:0:0:0:0",\$err,0);
-  }
-  ($y,$m,$d)=&Date_Split($date, 1);
-  ($y,$m,$d);
-}
-
-########################################################################
-# LANGUAGE INITIALIZATION
-########################################################################
-
-# 8-bit international characters can be gotten by "\xXX".  I don't know
-# how to get 16-bit characters.  I've got to read up on perllocale.
-sub Char_8Bit {
-  my($hash)=@_;
-
-  #   grave `
-  #     A`    00c0     a`    00e0
-  #     E`    00c8     e`    00e8
-  #     I`    00cc     i`    00ec
-  #     O`    00d2     o`    00f2
-  #     U`    00d9     u`    00f9
-  #     W`    1e80     w`    1e81
-  #     Y`    1ef2     y`    1ef3
-
-  $$hash{"A`"} = "\xc0";   #   LATIN CAPITAL LETTER A WITH GRAVE
-  $$hash{"E`"} = "\xc8";   #   LATIN CAPITAL LETTER E WITH GRAVE
-  $$hash{"I`"} = "\xcc";   #   LATIN CAPITAL LETTER I WITH GRAVE
-  $$hash{"O`"} = "\xd2";   #   LATIN CAPITAL LETTER O WITH GRAVE
-  $$hash{"U`"} = "\xd9";   #   LATIN CAPITAL LETTER U WITH GRAVE
-  $$hash{"a`"} = "\xe0";   #   LATIN SMALL LETTER A WITH GRAVE
-  $$hash{"e`"} = "\xe8";   #   LATIN SMALL LETTER E WITH GRAVE
-  $$hash{"i`"} = "\xec";   #   LATIN SMALL LETTER I WITH GRAVE
-  $$hash{"o`"} = "\xf2";   #   LATIN SMALL LETTER O WITH GRAVE
-  $$hash{"u`"} = "\xf9";   #   LATIN SMALL LETTER U WITH GRAVE
-
-  #   acute '
-  #     A'    00c1     a'    00e1
-  #     C'    0106     c'    0107
-  #     E'    00c9     e'    00e9
-  #     I'    00cd     i'    00ed
-  #     L'    0139     l'    013a
-  #     N'    0143     n'    0144
-  #     O'    00d3     o'    00f3
-  #     R'    0154     r'    0155
-  #     S'    015a     s'    015b
-  #     U'    00da     u'    00fa
-  #     W'    1e82     w'    1e83
-  #     Y'    00dd     y'    00fd
-  #     Z'    0179     z'    017a
-
-  $$hash{"A'"} = "\xc1";   #   LATIN CAPITAL LETTER A WITH ACUTE
-  $$hash{"E'"} = "\xc9";   #   LATIN CAPITAL LETTER E WITH ACUTE
-  $$hash{"I'"} = "\xcd";   #   LATIN CAPITAL LETTER I WITH ACUTE
-  $$hash{"O'"} = "\xd3";   #   LATIN CAPITAL LETTER O WITH ACUTE
-  $$hash{"U'"} = "\xda";   #   LATIN CAPITAL LETTER U WITH ACUTE
-  $$hash{"Y'"} = "\xdd";   #   LATIN CAPITAL LETTER Y WITH ACUTE
-  $$hash{"a'"} = "\xe1";   #   LATIN SMALL LETTER A WITH ACUTE
-  $$hash{"e'"} = "\xe9";   #   LATIN SMALL LETTER E WITH ACUTE
-  $$hash{"i'"} = "\xed";   #   LATIN SMALL LETTER I WITH ACUTE
-  $$hash{"o'"} = "\xf3";   #   LATIN SMALL LETTER O WITH ACUTE
-  $$hash{"u'"} = "\xfa";   #   LATIN SMALL LETTER U WITH ACUTE
-  $$hash{"y'"} = "\xfd";   #   LATIN SMALL LETTER Y WITH ACUTE
-
-  #   double acute "         "
-  #     O"    0150     o"    0151
-  #     U"    0170     u"    0171
-
-  #   circumflex ^
-  #     A^    00c2     a^    00e2
-  #     C^    0108     c^    0109
-  #     E^    00ca     e^    00ea
-  #     G^    011c     g^    011d
-  #     H^    0124     h^    0125
-  #     I^    00ce     i^    00ee
-  #     J^    0134     j^    0135
-  #     O^    00d4     o^    00f4
-  #     S^    015c     s^    015d
-  #     U^    00db     u^    00fb
-  #     W^    0174     w^    0175
-  #     Y^    0176     y^    0177
-
-  $$hash{"A^"} = "\xc2";   #   LATIN CAPITAL LETTER A WITH CIRCUMFLEX
-  $$hash{"E^"} = "\xca";   #   LATIN CAPITAL LETTER E WITH CIRCUMFLEX
-  $$hash{"I^"} = "\xce";   #   LATIN CAPITAL LETTER I WITH CIRCUMFLEX
-  $$hash{"O^"} = "\xd4";   #   LATIN CAPITAL LETTER O WITH CIRCUMFLEX
-  $$hash{"U^"} = "\xdb";   #   LATIN CAPITAL LETTER U WITH CIRCUMFLEX
-  $$hash{"a^"} = "\xe2";   #   LATIN SMALL LETTER A WITH CIRCUMFLEX
-  $$hash{"e^"} = "\xea";   #   LATIN SMALL LETTER E WITH CIRCUMFLEX
-  $$hash{"i^"} = "\xee";   #   LATIN SMALL LETTER I WITH CIRCUMFLEX
-  $$hash{"o^"} = "\xf4";   #   LATIN SMALL LETTER O WITH CIRCUMFLEX
-  $$hash{"u^"} = "\xfb";   #   LATIN SMALL LETTER U WITH CIRCUMFLEX
-
-  #   tilde ~
-  #     A~    00c3    a~    00e3
-  #     I~    0128    i~    0129
-  #     N~    00d1    n~    00f1
-  #     O~    00d5    o~    00f5
-  #     U~    0168    u~    0169
-
-  $$hash{"A~"} = "\xc3";   #   LATIN CAPITAL LETTER A WITH TILDE
-  $$hash{"N~"} = "\xd1";   #   LATIN CAPITAL LETTER N WITH TILDE
-  $$hash{"O~"} = "\xd5";   #   LATIN CAPITAL LETTER O WITH TILDE
-  $$hash{"a~"} = "\xe3";   #   LATIN SMALL LETTER A WITH TILDE
-  $$hash{"n~"} = "\xf1";   #   LATIN SMALL LETTER N WITH TILDE
-  $$hash{"o~"} = "\xf5";   #   LATIN SMALL LETTER O WITH TILDE
-
-  #   macron -
-  #     A-    0100    a-    0101
-  #     E-    0112    e-    0113
-  #     I-    012a    i-    012b
-  #     O-    014c    o-    014d
-  #     U-    016a    u-    016b
-
-  #   breve ( [half circle up]
-  #     A(    0102    a(    0103
-  #     G(    011e    g(    011f
-  #     U(    016c    u(    016d
-
-  #   dot .
-  #     C.    010a    c.    010b
-  #     E.    0116    e.    0117
-  #     G.    0120    g.    0121
-  #     I.    0130
-  #     Z.    017b    z.    017c
-
-  #   diaeresis :  [side by side dots]
-  #     A:    00c4    a:    00e4
-  #     E:    00cb    e:    00eb
-  #     I:    00cf    i:    00ef
-  #     O:    00d6    o:    00f6
-  #     U:    00dc    u:    00fc
-  #     W:    1e84    w:    1e85
-  #     Y:    0178    y:    00ff
-
-  $$hash{"A:"} = "\xc4";   #   LATIN CAPITAL LETTER A WITH DIAERESIS
-  $$hash{"E:"} = "\xcb";   #   LATIN CAPITAL LETTER E WITH DIAERESIS
-  $$hash{"I:"} = "\xcf";   #   LATIN CAPITAL LETTER I WITH DIAERESIS
-  $$hash{"O:"} = "\xd6";   #   LATIN CAPITAL LETTER O WITH DIAERESIS
-  $$hash{"U:"} = "\xdc";   #   LATIN CAPITAL LETTER U WITH DIAERESIS
-  $$hash{"a:"} = "\xe4";   #   LATIN SMALL LETTER A WITH DIAERESIS
-  $$hash{"e:"} = "\xeb";   #   LATIN SMALL LETTER E WITH DIAERESIS
-  $$hash{"i:"} = "\xef";   #   LATIN SMALL LETTER I WITH DIAERESIS
-  $$hash{"o:"} = "\xf6";   #   LATIN SMALL LETTER O WITH DIAERESIS
-  $$hash{"u:"} = "\xfc";   #   LATIN SMALL LETTER U WITH DIAERESIS
-  $$hash{"y:"} = "\xff";   #   LATIN SMALL LETTER Y WITH DIAERESIS
-
-  #   ring o
-  #     U0    016e    u0    016f
-
-  #   cedilla ,  [squiggle down and left below the letter]
-  #     ,C    00c7    ,c    00e7
-  #     ,G    0122    ,g    0123
-  #     ,K    0136    ,k    0137
-  #     ,L    013b    ,l    013c
-  #     ,N    0145    ,n    0146
-  #     ,R    0156    ,r    0157
-  #     ,S    015e    ,s    015f
-  #     ,T    0162    ,t    0163
-
-  $$hash{",C"} = "\xc7";   #   LATIN CAPITAL LETTER C WITH CEDILLA
-  $$hash{",c"} = "\xe7";   #   LATIN SMALL LETTER C WITH CEDILLA
-
-  #   ogonek ;  [squiggle down and right below the letter]
-  #     A;    0104    a;    0105
-  #     E;    0118    e;    0119
-  #     I;    012e    i;    012f
-  #     U;    0172    u;    0173
-
-  #   caron <  [little v on top]
-  #     A<    01cd    a<    01ce
-  #     C<    010c    c<    010d
-  #     D<    010e    d<    010f
-  #     E<    011a    e<    011b
-  #     L<    013d    l<    013e
-  #     N<    0147    n<    0148
-  #     R<    0158    r<    0159
-  #     S<    0160    s<    0161
-  #     T<    0164    t<    0165
-  #     Z<    017d    z<    017e
-
-
-  # Other characters
-
-  # First character is below, 2nd character is above
-  $$hash{"||"} = "\xa6";   #   BROKEN BAR
-  $$hash{" :"} = "\xa8";   #   DIAERESIS
-  $$hash{"-a"} = "\xaa";   #   FEMININE ORDINAL INDICATOR
-  #$$hash{" -"}= "\xaf";   #   MACRON   (narrow bar)
-  $$hash{" -"} = "\xad";   #   HYPHEN   (wide bar)
-  $$hash{" o"} = "\xb0";   #   DEGREE SIGN
-  $$hash{"-+"} = "\xb1";   #   PLUS\342\200\220MINUS SIGN
-  $$hash{" 1"} = "\xb9";   #   SUPERSCRIPT ONE
-  $$hash{" 2"} = "\xb2";   #   SUPERSCRIPT TWO
-  $$hash{" 3"} = "\xb3";   #   SUPERSCRIPT THREE
-  $$hash{" '"} = "\xb4";   #   ACUTE ACCENT
-  $$hash{"-o"} = "\xba";   #   MASCULINE ORDINAL INDICATOR
-  $$hash{" ."} = "\xb7";   #   MIDDLE DOT
-  $$hash{", "} = "\xb8";   #   CEDILLA
-  $$hash{"Ao"} = "\xc5";   #   LATIN CAPITAL LETTER A WITH RING ABOVE
-  $$hash{"ao"} = "\xe5";   #   LATIN SMALL LETTER A WITH RING ABOVE
-  $$hash{"ox"} = "\xf0";   #   LATIN SMALL LETTER ETH
-
-  # upside down characters
-
-  $$hash{"ud!"} = "\xa1";  #   INVERTED EXCLAMATION MARK
-  $$hash{"ud?"} = "\xbf";  #   INVERTED QUESTION MARK
-
-  # overlay characters
-
-  $$hash{"X o"} = "\xa4";  #   CURRENCY SIGN
-  $$hash{"Y ="} = "\xa5";  #   YEN SIGN
-  $$hash{"S o"} = "\xa7";  #   SECTION SIGN
-  $$hash{"O c"} = "\xa9";  #   COPYRIGHT SIGN    Copyright
-  $$hash{"O R"} = "\xae";  #   REGISTERED SIGN
-  $$hash{"D -"} = "\xd0";  #   LATIN CAPITAL LETTER ETH
-  $$hash{"O /"} = "\xd8";  #   LATIN CAPITAL LETTER O WITH STROKE
-  $$hash{"o /"} = "\xf8";  #   LATIN SMALL LETTER O WITH STROKE
-
-  # special names
-
-  $$hash{"1/4"} = "\xbc";  #   VULGAR FRACTION ONE QUARTER
-  $$hash{"1/2"} = "\xbd";  #   VULGAR FRACTION ONE HALF
-  $$hash{"3/4"} = "\xbe";  #   VULGAR FRACTION THREE QUARTERS
-  $$hash{"<<"}  = "\xab";  #   LEFT POINTING DOUBLE ANGLE QUOTATION MARK
-  $$hash{">>"}  = "\xbb";  #   RIGHT POINTING DOUBLE ANGLE QUOTATION MARK
-  $$hash{"cent"}= "\xa2";  #   CENT SIGN
-  $$hash{"lb"}  = "\xa3";  #   POUND SIGN
-  $$hash{"mu"}  = "\xb5";  #   MICRO SIGN
-  $$hash{"beta"}= "\xdf";  #   LATIN SMALL LETTER SHARP S
-  $$hash{"para"}= "\xb6";  #   PILCROW SIGN
-  $$hash{"-|"}  = "\xac";  #   NOT SIGN
-  $$hash{"AE"}  = "\xc6";  #   LATIN CAPITAL LETTER AE
-  $$hash{"ae"}  = "\xe6";  #   LATIN SMALL LETTER AE
-  $$hash{"x"}   = "\xd7";  #   MULTIPLICATION SIGN
-  $$hash{"P"}   = "\xde";  #   LATIN CAPITAL LETTER THORN
-  $$hash{"/"}   = "\xf7";  #   DIVISION SIGN
-  $$hash{"p"}   = "\xfe";  #   LATIN SMALL LETTER THORN
-}
-
-# $hashref = &Date_Init_LANGUAGE;
-#   This returns a hash containing all of the initialization for a
-#   specific language.  The hash elements are:
-#
-#   @ month_name      full month names          January February ...
-#   @ month_abb       month abbreviations       Jan Feb ...
-#   @ day_name        day names                 Monday Tuesday ...
-#   @ day_abb         day abbreviations         Mon Tue ...
-#   @ day_char        day character abbrevs     M T ...
-#   @ am              AM notations
-#   @ pm              PM notations
-#
-#   @ num_suff        number with suffix        1st 2nd ...
-#   @ num_word        numbers spelled out       first second ...
-#
-#   $ now             words which mean now      now today ...
-#   $ last            words which mean last     last final ...
-#   $ each            words which mean each     each every ...
-#   $ of              of (as in a member of)    in of ...
-#                     ex.  4th day OF June
-#   $ at              at 4:00                   at
-#   $ on              on Sunday                 on
-#   $ future          in the future             in
-#   $ past            in the past               ago
-#   $ next            next item                 next
-#   $ prev            previous item             last previous
-#   $ later           2 hours later
-#
-#   % offset          a hash of special dates   { tomorrow->0:0:0:1:0:0:0 }
-#   % times           a hash of times           { noon->12:00:00 ... }
-#
-#   $ years           words for year            y yr year ...
-#   $ months          words for month
-#   $ weeks           words for week
-#   $ days            words for day
-#   $ hours           words for hour
-#   $ minutes         words for minute
-#   $ seconds         words for second
-#   % replace
-#       The replace element is quite important, but a bit tricky.  In
-#       English (and probably other languages), one of the abbreviations
-#       for the word month that would be nice is "m".  The problem is that
-#       "m" matches the "m" in "minute" which causes the string to be
-#       improperly matched in some cases.  Hence, the list of abbreviations
-#       for month is given as:
-#         "mon month months"
-#       In order to allow you to enter "m", replacements can be done.
-#       $replace is a list of pairs of words which are matched and replaced
-#       AS ENTIRE WORDS.  Having $replace equal to "m"->"month" means that
-#       the entire word "m" will be replaced with "month".  This allows the
-#       desired abbreviation to be used.  Make sure that replace contains
-#       an even number of words (i.e. all must be pairs).  Any time a
-#       desired abbreviation matches the start of any other, it has to go
-#       here.
-#
-#   $ exact           exact mode                exactly
-#   $ approx          approximate mode          approximately
-#   $ business        business mode             business
-#
-#   r sephm           hour/minute separator     (?::)
-#   r sepms           minute/second separator   (?::)
-#   r sepss           second/fraction separator (?:[.:])
-#
-#   Elements marked with an asterix (@) are returned as a set of lists.
-#   Each list contains the strings for each element.  The first set is used
-#   when the 7-bit ASCII (US) character set is wanted.  The 2nd set is used
-#   when an international character set is available.  Both of the 1st two
-#   sets should be complete (but the 2nd list can be left empty to force the
-#   first set to be used always).  The 3rd set and later can be partial sets
-#   if desired.
-#
-#   Elements marked with a dollar ($) are returned as a simple list of words.
-#
-#   Elements marked with a percent (%) are returned as a hash list.
-#
-#   Elements marked with (r) are regular expression elements which must not
-#   create a back reference.
-#
-# ***NOTE*** Every hash element (unless otherwise noted) MUST be defined in
-# every language.
-
-sub Date_Init_English {
-  print "DEBUG: Date_Init_English\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($d)=@_;
-
-  $$d{"month_name"}=
-    [["January","February","March","April","May","June",
-      "July","August","September","October","November","December"]];
-
-  $$d{"month_abb"}=
-    [["Jan","Feb","Mar","Apr","May","Jun",
-      "Jul","Aug","Sep","Oct","Nov","Dec"],
-     [],
-     ["","","","","","","","","Sept"]];
-
-  $$d{"day_name"}=
-    [["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]];
-  $$d{"day_abb"}=
-    [["Mon","Tue","Wed","Thu","Fri","Sat","Sun"],
-     ["",   "Tues","",  "Thur","",  "",   ""]];
-  $$d{"day_char"}=
-    [["M","T","W","Th","F","Sa","S"]];
-
-  $$d{"num_suff"}=
-    [["1st","2nd","3rd","4th","5th","6th","7th","8th","9th","10th",
-      "11th","12th","13th","14th","15th","16th","17th","18th","19th","20th",
-      "21st","22nd","23rd","24th","25th","26th","27th","28th","29th","30th",
-      "31st"]];
-  $$d{"num_word"}=
-    [["first","second","third","fourth","fifth","sixth","seventh","eighth",
-      "ninth","tenth","eleventh","twelfth","thirteenth","fourteenth",
-      "fifteenth","sixteenth","seventeenth","eighteenth","nineteenth",
-      "twentieth","twenty-first","twenty-second","twenty-third",
-      "twenty-fourth","twenty-fifth","twenty-sixth","twenty-seventh",
-      "twenty-eighth","twenty-ninth","thirtieth","thirty-first"]];
-
-  $$d{"now"}     =["today","now"];
-  $$d{"last"}    =["last","final"];
-  $$d{"each"}    =["each","every"];
-  $$d{"of"}      =["in","of"];
-  $$d{"at"}      =["at"];
-  $$d{"on"}      =["on"];
-  $$d{"future"}  =["in"];
-  $$d{"past"}    =["ago"];
-  $$d{"next"}    =["next"];
-  $$d{"prev"}    =["previous","last"];
-  $$d{"later"}   =["later"];
-
-  $$d{"exact"}   =["exactly"];
-  $$d{"approx"}  =["approximately"];
-  $$d{"business"}=["business"];
-
-  $$d{"offset"}  =["yesterday","-0:0:0:1:0:0:0","tomorrow","+0:0:0:1:0:0:0"];
-  $$d{"times"}   =["noon","12:00:00","midnight","00:00:00"];
-
-  $$d{"years"}   =["y","yr","year","yrs","years"];
-  $$d{"months"}  =["mon","month","months"];
-  $$d{"weeks"}   =["w","wk","wks","week","weeks"];
-  $$d{"days"}    =["d","day","days"];
-  $$d{"hours"}   =["h","hr","hrs","hour","hours"];
-  $$d{"minutes"} =["mn","min","minute","minutes"];
-  $$d{"seconds"} =["s","sec","second","seconds"];
-  $$d{"replace"} =["m","month"];
-
-  $$d{"sephm"}   =':';
-  $$d{"sepms"}   =':';
-  $$d{"sepss"}   ='[.:]';
-
-  $$d{"am"}      = ["AM","A.M."];
-  $$d{"pm"}      = ["PM","P.M."];
-}
-
-sub Date_Init_Italian {
-  print "DEBUG: Date_Init_Italian\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($d)=@_;
-  my(%h)=();
-  &Char_8Bit(\%h);
-  my($i)=$h{"i'"};
-
-  $$d{"month_name"}=
-    [[qw(Gennaio Febbraio Marzo Aprile Maggio Giugno
-         Luglio Agosto Settembre Ottobre Novembre Dicembre)]];
-
-  $$d{"month_abb"}=
-    [[qw(Gen Feb Mar Apr Mag Giu Lug Ago Set Ott Nov Dic)]];
-
-  $$d{"day_name"}=
-    [[qw(Lunedi Martedi Mercoledi Giovedi Venerdi Sabato Domenica)],
-     [qw(Luned${i} Marted${i} Mercoled${i} Gioved${i} Venerd${i})]];
-  $$d{"day_abb"}=
-    [[qw(Lun Mar Mer Gio Ven Sab Dom)]];
-  $$d{"day_char"}=
-    [[qw(L Ma Me G V S D)]];
-
-  $$d{"num_suff"}=
-    [[qw(1mo 2do 3zo 4to 5to 6to 7mo 8vo 9no 10mo 11mo 12mo 13mo 14mo 15mo
-         16mo 17mo 18mo 19mo 20mo 21mo 22mo 23mo 24mo 25mo 26mo 27mo 28mo
-         29mo 3mo 31mo)]];
-  $$d{"num_word"}=
-    [[qw(primo secondo terzo quarto quinto sesto settimo ottavo nono decimo
-         undicesimo dodicesimo tredicesimo quattordicesimo quindicesimo
-         sedicesimo diciassettesimo diciottesimo diciannovesimo ventesimo
-         ventunesimo ventiduesimo ventitreesimo ventiquattresimo
-         venticinquesimo ventiseiesimo ventisettesimo ventottesimo
-         ventinovesimo trentesimo trentunesimo)]];
-
-  $$d{"now"}     =[qw(adesso oggi)];
-  $$d{"last"}    =[qw(ultimo)];
-  $$d{"each"}    =[qw(ogni)];
-  $$d{"of"}      =[qw(della del)];
-  $$d{"at"}      =[qw(alle)];
-  $$d{"on"}      =[qw(di)];
-  $$d{"future"}  =[qw(fra)];
-  $$d{"past"}    =[qw(fa)];
-  $$d{"next"}    =[qw(prossimo)];
-  $$d{"prev"}    =[qw(ultimo)];
-  $$d{"later"}   =[qw(dopo)];
-
-  $$d{"exact"}   =[qw(esattamente)];
-  $$d{"approx"}  =[qw(circa)];
-  $$d{"business"}=[qw(lavorativi lavorativo)];
-
-  $$d{"offset"}  =[qw(ieri -0:0:0:1:0:0:0 domani +0:0:0:1:0:0:0)];
-  $$d{"times"}   =[qw(mezzogiorno 12:00:00 mezzanotte 00:00:00)];
-
-  $$d{"years"}   =[qw(anni anno a)];
-  $$d{"months"}  =[qw(mesi mese mes)];
-  $$d{"weeks"}   =[qw(settimane settimana sett)];
-  $$d{"days"}    =[qw(giorni giorno g)];
-  $$d{"hours"}   =[qw(ore ora h)];
-  $$d{"minutes"} =[qw(minuti minuto min)];
-  $$d{"seconds"} =[qw(secondi secondo sec)];
-  $$d{"replace"} =[qw(s sec m mes)];
-
-  $$d{"sephm"}   =':';
-  $$d{"sepms"}   =':';
-  $$d{"sepss"}   ='[.:]';
-
-  $$d{"am"}      = [qw(AM)];
-  $$d{"pm"}      = [qw(PM)];
-}
-
-sub Date_Init_French {
-  print "DEBUG: Date_Init_French\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($d)=@_;
-  my(%h)=();
-  &Char_8Bit(\%h);
-  my($e)=$h{"e'"};
-  my($u)=$h{"u^"};
-  my($a)=$h{"a'"};
-
-  $$d{"month_name"}=
-    [["janvier","fevrier","mars","avril","mai","juin",
-      "juillet","aout","septembre","octobre","novembre","decembre"],
-     ["janvier","f${e}vrier","mars","avril","mai","juin",
-      "juillet","ao${u}t","septembre","octobre","novembre","d${e}cembre"]];
-  $$d{"month_abb"}=
-    [["jan","fev","mar","avr","mai","juin",
-      "juil","aout","sept","oct","nov","dec"],
-     ["jan","f${e}v","mar","avr","mai","juin",
-      "juil","ao${u}t","sept","oct","nov","d${e}c"]];
-
-  $$d{"day_name"}=
-    [["lundi","mardi","mercredi","jeudi","vendredi","samedi","dimanche"]];
-  $$d{"day_abb"}=
-    [["lun","mar","mer","jeu","ven","sam","dim"]];
-  $$d{"day_char"}=
-    [["l","ma","me","j","v","s","d"]];
-
-  $$d{"num_suff"}=
-    [["1er","2e","3e","4e","5e","6e","7e","8e","9e","10e",
-      "11e","12e","13e","14e","15e","16e","17e","18e","19e","20e",
-      "21e","22e","23e","24e","25e","26e","27e","28e","29e","30e",
-      "31e"]];
-  $$d{"num_word"}=
-    [["premier","deux","trois","quatre","cinq","six","sept","huit","neuf",
-      "dix","onze","douze","treize","quatorze","quinze","seize","dix-sept",
-      "dix-huit","dix-neuf","vingt","vingt et un","vingt-deux","vingt-trois",
-      "vingt-quatre","vingt-cinq","vingt-six","vingt-sept","vingt-huit",
-      "vingt-neuf","trente","trente et un"],
-     ["1re"]];
-
-  $$d{"now"}     =["aujourd'hui","maintenant"];
-  $$d{"last"}    =["dernier"];
-  $$d{"each"}    =["chaque","tous les","toutes les"];
-  $$d{"of"}      =["en","de"];
-  $$d{"at"}      =["a","${a}0"];
-  $$d{"on"}      =["sur"];
-  $$d{"future"}  =["en"];
-  $$d{"past"}    =["il y a"];
-  $$d{"next"}    =["suivant"];
-  $$d{"prev"}    =["precedent","pr${e}c${e}dent"];
-  $$d{"later"}   =["plus tard"];
-
-  $$d{"exact"}   =["exactement"];
-  $$d{"approx"}  =["approximativement"];
-  $$d{"business"}=["professionel"];
-
-  $$d{"offset"}  =["hier","-0:0:0:1:0:0:0","demain","+0:0:0:1:0:0:0"];
-  $$d{"times"}   =["midi","12:00:00","minuit","00:00:00"];
-
-  $$d{"years"}   =["an","annee","ans","annees","ann${e}e","ann${e}es"];
-  $$d{"months"}  =["mois"];
-  $$d{"weeks"}   =["sem","semaine"];
-  $$d{"days"}    =["j","jour","jours"];
-  $$d{"hours"}   =["h","heure","heures"];
-  $$d{"minutes"} =["mn","min","minute","minutes"];
-  $$d{"seconds"} =["s","sec","seconde","secondes"];
-  $$d{"replace"} =["m","mois"];
-
-  $$d{"sephm"}   ='[h:]';
-  $$d{"sepms"}   =':';
-  $$d{"sepss"}   ='[.:,]';
-
-  $$d{"am"}      = ["du matin"];
-  $$d{"pm"}      = ["du soir"];
-}
-
-sub Date_Init_Romanian {
-  print "DEBUG: Date_Init_Romanian\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($d)=@_;
-  my(%h)=();
-  &Char_8Bit(\%h);
-  my($p)=$h{"p"};
-  my($i)=$h{"i^"};
-  my($a)=$h{"a~"};
-  my($o)=$h{"-o"};
-
-  $$d{"month_name"}=
-    [["ianuarie","februarie","martie","aprilie","mai","iunie",
-      "iulie","august","septembrie","octombrie","noiembrie","decembrie"]];
-  $$d{"month_abb"}=
-    [["ian","febr","mart","apr","mai","iun",
-      "iul","aug","sept","oct","nov","dec"],
-     ["","feb"]];
-
-  $$d{"day_name"}=
-    [["luni","marti","miercuri","joi","vineri","simbata","duminica"],
-     ["luni","mar${p}i","miercuri","joi","vineri","s${i}mb${a}t${a}",
-      "duminic${a}"]];
-  $$d{"day_abb"}=
-    [["lun","mar","mie","joi","vin","sim","dum"],
-     ["lun","mar","mie","joi","vin","s${i}m","dum"]];
-  $$d{"day_char"}=
-    [["L","Ma","Mi","J","V","S","D"]];
-
-  $$d{"num_suff"}=
-    [["prima","a doua","a 3-a","a 4-a","a 5-a","a 6-a","a 7-a","a 8-a",
-      "a 9-a","a 10-a","a 11-a","a 12-a","a 13-a","a 14-a","a 15-a",
-      "a 16-a","a 17-a","a 18-a","a 19-a","a 20-a","a 21-a","a 22-a",
-      "a 23-a","a 24-a","a 25-a","a 26-a","a 27-a","a 28-a","a 29-a",
-      "a 30-a","a 31-a"]];
-
-  $$d{"num_word"}=
-    [["prima","a doua","a treia","a patra","a cincea","a sasea","a saptea",
-      "a opta","a noua","a zecea","a unsprezecea","a doisprezecea",
-      "a treisprezecea","a patrusprezecea","a cincisprezecea","a saiprezecea",
-      "a saptesprezecea","a optsprezecea","a nouasprezecea","a douazecea",
-      "a douazecisiuna","a douazecisidoua","a douazecisitreia",
-      "a douazecisipatra","a douazecisicincea","a douazecisisasea",
-      "a douazecisisaptea","a douazecisiopta","a douazecisinoua","a treizecea",
-      "a treizecisiuna"],
-     ["prima","a doua","a treia","a patra","a cincea","a ${o}asea",
-      "a ${o}aptea","a opta","a noua","a zecea","a unsprezecea",
-      "a doisprezecea","a treisprezecea","a patrusprezecea","a cincisprezecea",
-      "a ${o}aiprezecea","a ${o}aptesprezecea","a optsprezecea",
-      "a nou${a}sprezecea","a dou${a}zecea","a dou${a}zeci${o}iuna",
-      "a dou${a}zeci${o}idoua","a dou${a}zeci${o}itreia",
-      "a dou${a}zeci${o}ipatra","a dou${a}zeci${o}icincea",
-      "a dou${a}zeci${o}i${o}asea","a dou${a}zeci${o}i${o}aptea",
-      "a dou${a}zeci${o}iopta","a dou${a}zeci${o}inoua","a treizecea",
-      "a treizeci${o}iuna"],
-     ["intii", "doi", "trei", "patru", "cinci", "sase", "sapte",
-      "opt","noua","zece","unsprezece","doisprezece",
-      "treisprezece","patrusprezece","cincisprezece","saiprezece",
-      "saptesprezece","optsprezece","nouasprezece","douazeci",
-      "douazecisiunu","douazecisidoi","douazecisitrei",
-      "douazecisipatru","douazecisicinci","douazecisisase","douazecisisapte",
-      "douazecisiopt","douazecisinoua","treizeci","treizecisiunu"],
-     ["${i}nt${i}i", "doi", "trei", "patru", "cinci", "${o}ase", "${o}apte",
-      "opt","nou${a}","zece","unsprezece","doisprezece",
-      "treisprezece","patrusprezece","cincisprezece","${o}aiprezece",
-      "${o}aptesprezece","optsprezece","nou${a}sprezece","dou${a}zeci",
-      "dou${a}zeci${o}iunu","dou${a}zeci${o}idoi","dou${a}zeci${o}itrei",
-      "dou${a}zecisipatru","dou${a}zeci${o}icinci","dou${a}zeci${o}i${o}ase",
-      "dou${a}zeci${o}i${o}apte","dou${a}zeci${o}iopt",
-      "dou${a}zeci${o}inou${a}","treizeci","treizeci${o}iunu"]];
-
-  $$d{"now"}     =["acum","azi","astazi","ast${a}zi"];
-  $$d{"last"}    =["ultima"];
-  $$d{"each"}    =["fiecare"];
-  $$d{"of"}      =["din","in","n"];
-  $$d{"at"}      =["la"];
-  $$d{"on"}      =["on"];
-  $$d{"future"}  =["in","${i}n"];
-  $$d{"past"}    =["in urma", "${i}n urm${a}"];
-  $$d{"next"}    =["urmatoarea","urm${a}toarea"];
-  $$d{"prev"}    =["precedenta","ultima"];
-  $$d{"later"}   =["mai tirziu", "mai t${i}rziu"];
-
-  $$d{"exact"}   =["exact"];
-  $$d{"approx"}  =["aproximativ"];
-  $$d{"business"}=["de lucru","lucratoare","lucr${a}toare"];
-
-  $$d{"offset"}  =["ieri","-0:0:0:1:0:0:0",
-                   "alaltaieri", "-0:0:0:2:0:0:0",
-                   "alalt${a}ieri","-0:0:0:2:0:0:0",
-                   "miine","+0:0:0:1:0:0:0",
-                   "m${i}ine","+0:0:0:1:0:0:0",
-                   "poimiine","+0:0:0:2:0:0:0",
-                   "poim${i}ine","+0:0:0:2:0:0:0"];
-  $$d{"times"}   =["amiaza","12:00:00",
-                   "amiaz${a}","12:00:00",
-                   "miezul noptii","00:00:00",
-                   "miezul nop${p}ii","00:00:00"];
-
-  $$d{"years"}   =["ani","an","a"];
-  $$d{"months"}  =["luni","luna","lun${a}","l"];
-  $$d{"weeks"}   =["saptamini","s${a}pt${a}m${i}ni","saptamina",
-                   "s${a}pt${a}m${i}na","sapt","s${a}pt"];
-  $$d{"days"}    =["zile","zi","z"];
-  $$d{"hours"}   =["ore", "ora", "or${a}", "h"];
-  $$d{"minutes"} =["minute","min","m"];
-  $$d{"seconds"} =["secunde","sec",];
-  $$d{"replace"} =["s","secunde"];
-
-  $$d{"sephm"}   =':';
-  $$d{"sepms"}   =':';
-  $$d{"sepss"}   ='[.:,]';
-
-  $$d{"am"}      = ["AM","A.M."];
-  $$d{"pm"}      = ["PM","P.M."];
-}
-
-sub Date_Init_Swedish {
-  print "DEBUG: Date_Init_Swedish\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($d)=@_;
-  my(%h)=();
-  &Char_8Bit(\%h);
-  my($ao)=$h{"ao"};
-  my($o) =$h{"o:"};
-  my($a) =$h{"a:"};
-
-  $$d{"month_name"}=
-    [["Januari","Februari","Mars","April","Maj","Juni",
-      "Juli","Augusti","September","Oktober","November","December"]];
-  $$d{"month_abb"}=
-    [["Jan","Feb","Mar","Apr","Maj","Jun",
-      "Jul","Aug","Sep","Okt","Nov","Dec"]];
-
-  $$d{"day_name"}=
-    [["Mandag","Tisdag","Onsdag","Torsdag","Fredag","Lordag","Sondag"],
-     ["M${ao}ndag","Tisdag","Onsdag","Torsdag","Fredag","L${o}rdag",
-      "S${o}ndag"]];
-  $$d{"day_abb"}=
-    [["Man","Tis","Ons","Tor","Fre","Lor","Son"],
-     ["M${ao}n","Tis","Ons","Tor","Fre","L${o}r","S${o}n"]];
-  $$d{"day_char"}=
-    [["M","Ti","O","To","F","L","S"]];
-
-  $$d{"num_suff"}=
-    [["1:a","2:a","3:e","4:e","5:e","6:e","7:e","8:e","9:e","10:e",
-      "11:e","12:e","13:e","14:e","15:e","16:e","17:e","18:e","19:e","20:e",
-      "21:a","22:a","23:e","24:e","25:e","26:e","27:e","28:e","29:e","30:e",
-      "31:a"]];
-  $$d{"num_word"}=
-    [["forsta","andra","tredje","fjarde","femte","sjatte","sjunde",
-      "attonde","nionde","tionde","elfte","tolfte","trettonde","fjortonde",
-      "femtonde","sextonde","sjuttonde","artonde","nittonde","tjugonde",
-      "tjugoforsta","tjugoandra","tjugotredje","tjugofjarde","tjugofemte",
-      "tjugosjatte","tjugosjunde","tjugoattonde","tjugonionde",
-      "trettionde","trettioforsta"],
-     ["f${o}rsta","andra","tredje","fj${a}rde","femte","sj${a}tte","sjunde",
-      "${ao}ttonde","nionde","tionde","elfte","tolfte","trettonde","fjortonde",
-      "femtonde","sextonde","sjuttonde","artonde","nittonde","tjugonde",
-      "tjugof${o}rsta","tjugoandra","tjugotredje","tjugofj${a}rde","tjugofemte",
-      "tjugosj${a}tte","tjugosjunde","tjugo${ao}ttonde","tjugonionde",
-      "trettionde","trettiof${o}rsta"]];
-
-  $$d{"now"}     =["idag","nu"];
-  $$d{"last"}    =["forra","f${o}rra","senaste"];
-  $$d{"each"}    =["varje"];
-  $$d{"of"}      =["om"];
-  $$d{"at"}      =["kl","kl.","klockan"];
-  $$d{"on"}      =["pa","p${ao}"];
-  $$d{"future"}  =["om"];
-  $$d{"past"}    =["sedan"];
-  $$d{"next"}    =["nasta","n${a}sta"];
-  $$d{"prev"}    =["forra","f${o}rra"];
-  $$d{"later"}   =["senare"];
-
-  $$d{"exact"}   =["exakt"];
-  $$d{"approx"}  =["ungefar","ungef${a}r"];
-  $$d{"business"}=["arbetsdag","arbetsdagar"];
-
-  $$d{"offset"}  =["ig${ao}r","-0:0:0:1:0:0:0","igar","-0:0:0:1:0:0:0",
-                   "imorgon","+0:0:0:1:0:0:0"];
-  $$d{"times"}   =["mitt pa dagen","12:00:00","mitt p${ao} dagen","12:00:00",
-                   "midnatt","00:00:00"];
-
-  $$d{"years"}   =["ar","${ao}r"];
-  $$d{"months"}  =["man","manad","manader","m${ao}n","m${ao}nad","m${ao}nader"];
-  $$d{"weeks"}   =["v","vecka","veckor"];
-  $$d{"days"}    =["d","dag","dagar"];
-  $$d{"hours"}   =["t","tim","timme","timmar"];
-  $$d{"minutes"} =["min","minut","minuter"];
-  $$d{"seconds"} =["s","sek","sekund","sekunder"];
-  $$d{"replace"} =["m","minut"];
-
-  $$d{"sephm"}   ='[.:]';
-  $$d{"sepms"}   =':';
-  $$d{"sepss"}   ='[.:]';
-
-  $$d{"am"}      = ["FM"];
-  $$d{"pm"}      = ["EM"];
-}
-
-sub Date_Init_German {
-  print "DEBUG: Date_Init_German\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($d)=@_;
-  my(%h)=();
-  &Char_8Bit(\%h);
-  my($a)=$h{"a:"};
-  my($u)=$h{"u:"};
-  my($o)=$h{"o:"};
-  my($b)=$h{"beta"};
-
-  $$d{"month_name"}=
-    [["Januar","Februar","Maerz","April","Mai","Juni",
-      "Juli","August","September","Oktober","November","Dezember"],
-    ["J${a}nner","Februar","M${a}rz","April","Mai","Juni",
-      "Juli","August","September","Oktober","November","Dezember"]];
-  $$d{"month_abb"}=
-    [["Jan","Feb","Mar","Apr","Mai","Jun",
-      "Jul","Aug","Sep","Okt","Nov","Dez"],
-     ["J${a}n","Feb","M${a}r","Apr","Mai","Jun",
-      "Jul","Aug","Sep","Okt","Nov","Dez"]];
-
-  $$d{"day_name"}=
-    [["Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag",
-      "Sonntag"]];
-  $$d{"day_abb"}=
-    [["Mon","Die","Mit","Don","Fre","Sam","Son"]];
-  $$d{"day_char"}=
-    [["M","Di","Mi","Do","F","Sa","So"]];
-
-  $$d{"num_suff"}=
-    [["1.","2.","3.","4.","5.","6.","7.","8.","9.","10.",
-      "11.","12.","13.","14.","15.","16.","17.","18.","19.","20.",
-      "21.","22.","23.","24.","25.","26.","27.","28.","29.","30.",
-      "31."]];
-  $$d{"num_word"}=
-    [
-     ["erste","zweite","dritte","vierte","funfte","sechste","siebente",
-      "achte","neunte","zehnte","elfte","zwolfte","dreizehnte","vierzehnte",
-      "funfzehnte","sechzehnte","siebzehnte","achtzehnte","neunzehnte",
-      "zwanzigste","einundzwanzigste","zweiundzwanzigste","dreiundzwanzigste",
-      "vierundzwanzigste","funfundzwanzigste","sechundzwanzigste",
-      "siebundzwanzigste","achtundzwanzigste","neunundzwanzigste",
-      "dreibigste","einunddreibigste"],
-     ["erste","zweite","dritte","vierte","f${u}nfte","sechste","siebente",
-      "achte","neunte","zehnte","elfte","zw${o}lfte","dreizehnte",
-      "vierzehnte","f${u}nfzehnte","sechzehnte","siebzehnte","achtzehnte",
-      "neunzehnte","zwanzigste","einundzwanzigste","zweiundzwanzigste",
-      "dreiundzwanzigste","vierundzwanzigste","f${u}nfundzwanzigste",
-      "sechundzwanzigste","siebundzwanzigste","achtundzwanzigste",
-      "neunundzwanzigste","drei${b}igste","einunddrei${b}igste"],
-    ["erster"]];
-
-  $$d{"now"}     =["heute","jetzt"];
-  $$d{"last"}    =["letzte","letzten"];
-  $$d{"each"}    =["jeden"];
-  $$d{"of"}      =["der","im","des"];
-  $$d{"at"}      =["um"];
-  $$d{"on"}      =["am"];
-  $$d{"future"}  =["in"];
-  $$d{"past"}    =["vor"];
-  $$d{"next"}    =["nachste","n${a}chste","nachsten","n${a}chsten"];
-  $$d{"prev"}    =["vorherigen","vorherige","letzte","letzten"];
-  $$d{"later"}   =["spater","sp${a}ter"];
-
-  $$d{"exact"}   =["genau"];
-  $$d{"approx"}  =["ungefahr","ungef${a}hr"];
-  $$d{"business"}=["Arbeitstag"];
-
-  $$d{"offset"}  =["gestern","-0:0:0:1:0:0:0","morgen","+0:0:0:1:0:0:0"];
-  $$d{"times"}   =["mittag","12:00:00","mitternacht","00:00:00"];
-
-  $$d{"years"}   =["j","Jahr","Jahre"];
-  $$d{"months"}  =["Monat","Monate"];
-  $$d{"weeks"}   =["w","Woche","Wochen"];
-  $$d{"days"}    =["t","Tag","Tage"];
-  $$d{"hours"}   =["h","std","Stunde","Stunden"];
-  $$d{"minutes"} =["min","Minute","Minuten"];
-  $$d{"seconds"} =["s","sek","Sekunde","Sekunden"];
-  $$d{"replace"} =["m","Monat"];
-
-  $$d{"sephm"}   =':';
-  $$d{"sepms"}   ='[: ]';
-  $$d{"sepss"}   ='[.:]';
-
-  $$d{"am"}      = ["FM"];
-  $$d{"pm"}      = ["EM"];
-}
-
-sub Date_Init_Dutch {
-  print "DEBUG: Date_Init_Dutch\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($d)=@_;
-  my(%h)=();
-  &Char_8Bit(\%h);
-
-  $$d{"month_name"}=
-    [["januari","februari","maart","april","mei","juni","juli","augustus",
-      "september","october","november","december"],
-     ["","","","","","","","","","oktober"]];
-
-  $$d{"month_abb"}=
-    [["jan","feb","maa","apr","mei","jun","jul",
-      "aug","sep","oct","nov","dec"],
-     ["","","mrt","","","","","","","okt"]];
-  $$d{"day_name"}=
-    [["maandag","dinsdag","woensdag","donderdag","vrijdag","zaterdag",
-      "zondag"]];
-  $$d{"day_abb"}=
-    [["ma","di","wo","do","vr","zat","zon"],
-     ["","","","","","za","zo"]];
-  $$d{"day_char"}=
-    [["M","D","W","D","V","Za","Zo"]];
-
-  $$d{"num_suff"}=
-    [["1ste","2de","3de","4de","5de","6de","7de","8ste","9de","10de",
-      "11de","12de","13de","14de","15de","16de","17de","18de","19de","20ste",
-      "21ste","22ste","23ste","24ste","25ste","26ste","27ste","28ste","29ste",
-      "30ste","31ste"]];
-  $$d{"num_word"}=
-    [["eerste","tweede","derde","vierde","vijfde","zesde","zevende","achtste",
-      "negende","tiende","elfde","twaalfde",
-      map {"${_}tiende";} qw (der veer vijf zes zeven acht negen),
-      "twintigste",
-      map {"${_}entwintigste";} qw (een twee drie vier vijf zes zeven acht
-                                    negen),
-      "dertigste","eenendertigste"],
-     ["","","","","","","","","","","","","","","","","","","","",
-      map {"${_}-en-twintigste";} qw (een twee drie vier vijf zes zeven acht
-                                      negen),
-      "dertigste","een-en-dertigste"],
-     ["een","twee","drie","vier","vijf","zes","zeven","acht","negen","tien",
-      "elf","twaalf",
-      map {"${_}tien"} qw (der veer vijf zes zeven acht negen),
-      "twintig",
-      map {"${_}entwintig"} qw (een twee drie vier vijf zes zeven acht negen),
-      "dertig","eenendertig"],
-     ["","","","","","","","","","","","","","","","","","","","",
-      map {"${_}-en-twintig"} qw (een twee drie vier vijf zes zeven acht
-                                  negen),
-      "dertig","een-en-dertig"]];
-
-  $$d{"now"}     =["nu","nou","vandaag"];
-  $$d{"last"}    =["laatste"];
-  $$d{"each"}    =["elke","elk"];
-  $$d{"of"}      =["in","van"];
-  $$d{"at"}      =["om"];
-  $$d{"on"}      =["op"];
-  $$d{"future"}  =["over"];
-  $$d{"past"}    =["geleden","vroeger","eerder"];
-  $$d{"next"}    =["volgende","volgend"];
-  $$d{"prev"}    =["voorgaande","voorgaand"];
-  $$d{"later"}   =["later"];
-
-  $$d{"exact"}   =["exact","precies","nauwkeurig"];
-  $$d{"approx"}  =["ongeveer","ong",'ong\.',"circa","ca",'ca\.'];
-  $$d{"business"}=["werk","zakelijke","zakelijk"];
-
-  $$d{"offset"}  =["morgen","+0:0:0:1:0:0:0","overmorgen","+0:0:0:2:0:0:0",
-                   "gisteren","-0:0:0:1:0:0:0","eergisteren","-0::00:2:0:0:0"];
-  $$d{"times"}   =["noen","12:00:00","middernacht","00:00:00"];
-
-  $$d{"years"}   =["jaar","jaren","ja","j"];
-  $$d{"months"}  =["maand","maanden","mnd"];
-  $$d{"weeks"}   =["week","weken","w"];
-  $$d{"days"}    =["dag","dagen","d"];
-  $$d{"hours"}   =["uur","uren","u","h"];
-  $$d{"minutes"} =["minuut","minuten","min"];
-  $$d{"seconds"} =["seconde","seconden","sec","s"];
-  $$d{"replace"} =["m","minuten"];
-
-  $$d{"sephm"}   ='[:.uh]';
-  $$d{"sepms"}   ='[:.m]';
-  $$d{"sepss"}   ='[.:]';
-
-  $$d{"am"}      = ["am","a.m.","vm","v.m.","voormiddag","'s_ochtends",
-                    "ochtend","'s_nachts","nacht"];
-  $$d{"pm"}      = ["pm","p.m.","nm","n.m.","namiddag","'s_middags","middag",
-                    "'s_avonds","avond"];
-}
-
-sub Date_Init_Polish {
-  print "DEBUG: Date_Init_Polish\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($d)=@_;
-
-  $$d{"month_name"}=
-    [["stycznia","luty","marca","kwietnia","maja","czerwca",
-      "lipca","sierpnia","wrzesnia","pazdziernika","listopada","grudnia"],
-     ["stycznia","luty","marca","kwietnia","maja","czerwca","lipca",
-      "sierpnia","wrze\x9cnia","pa\x9fdziernika","listopada","grudnia"]];
-  $$d{"month_abb"}=
-    [["sty.","lut.","mar.","kwi.","maj","cze.",
-      "lip.","sie.","wrz.","paz.","lis.","gru."],
-     ["sty.","lut.","mar.","kwi.","maj","cze.",
-      "lip.","sie.","wrz.","pa\x9f.","lis.","gru."]];
-
-  $$d{"day_name"}=
-    [["poniedzialek","wtorek","sroda","czwartek","piatek","sobota",
-      "niedziela"],
-     ["poniedzia\x81\xb3ek","wtorek","\x9croda","czwartek","pi\x81\xb9tek",
-      "sobota","niedziela"]];
-  $$d{"day_abb"}=
-    [["po.","wt.","sr.","cz.","pi.","so.","ni."],
-     ["po.","wt.","\x9cr.","cz.","pi.","so.","ni."]];
-  $$d{"day_char"}=
-    [["p","w","e","c","p","s","n"],
-     ["p","w","\x9c.","c","p","s","n"]];
-
-  $$d{"num_suff"}=
-    [["1.","2.","3.","4.","5.","6.","7.","8.","9.","10.",
-      "11.","12.","13.","14.","15.","16.","17.","18.","19.","20.",
-      "21.","22.","23.","24.","25.","26.","27.","28.","29.","30.",
-      "31."]];
-  $$d{"num_word"}=
-    [["pierwszego","drugiego","trzeczego","czwartego","piatego","szostego",
-      "siodmego","osmego","dziewiatego","dziesiatego",
-      "jedenastego","dwunastego","trzynastego","czternastego","pietnastego",
-      "szestnastego","siedemnastego","osiemnastego","dziewietnastego",
-      "dwudziestego",
-      "dwudziestego pierwszego","dwudziestego drugiego",
-      "dwudziestego trzeczego","dwudziestego czwartego",
-      "dwudziestego piatego","dwudziestego szostego",
-      "dwudziestego siodmego","dwudziestego osmego",
-      "dwudziestego dziewiatego","trzydziestego","trzydziestego pierwszego"],
-     ["pierwszego","drugiego","trzeczego","czwartego","pi\x81\xb9tego",
-      "sz\x81\xf3stego","si\x81\xf3dmego","\x81\xf3smego","dziewi\x81\xb9tego",
-      "dziesi\x81\xb9tego","jedenastego","dwunastego","trzynastego",
-      "czternastego","pi\x81\xeatnastego","szestnastego","siedemnastego",
-      "osiemnastego","dziewietnastego","dwudziestego",
-      "dwudziestego pierwszego","dwudziestego drugiego",
-      "dwudziestego trzeczego","dwudziestego czwartego",
-      "dwudziestego pi\x81\xb9tego","dwudziestego sz\x81\xf3stego",
-      "dwudziestego si\x81\xf3dmego","dwudziestego \x81\xf3smego",
-      "dwudziestego dziewi\x81\xb9tego","trzydziestego",
-      "trzydziestego pierwszego"]];
-
-  $$d{"now"}     =["dzisaj","teraz"];
-  $$d{"last"}    =["ostatni","ostatna"];
-  $$d{"each"}    =["kazdy","ka\x81\xbfdy", "kazdym","ka\x81\xbfdym"];
-  $$d{"of"}      =["w","z"];
-  $$d{"at"}      =["o","u"];
-  $$d{"on"}      =["na"];
-  $$d{"future"}  =["za"];
-  $$d{"past"}    =["temu"];
-  $$d{"next"}    =["nastepny","nast\x81\xeapny","nastepnym","nast\x81\xeapnym",
-                   "przyszly","przysz\x81\xb3y","przyszlym",
-                   "przysz\x81\xb3ym"];
-  $$d{"prev"}    =["zeszly","zesz\x81\xb3y","zeszlym","zesz\x81\xb3ym"];
-  $$d{"later"}   =["later"];
-
-  $$d{"exact"}   =["doklandnie","dok\x81\xb3andnie"];
-  $$d{"approx"}  =["w przyblizeniu","w przybli\x81\xbfeniu","mniej wiecej",
-                   "mniej wi\x81\xeacej","okolo","oko\x81\xb3o"];
-  $$d{"business"}=["sluzbowy","s\x81\xb3u\x81\xbfbowy","sluzbowym",
-                   "s\x81\xb3u\x81\xbfbowym"];
-
-  $$d{"times"}   =["po\x81\xb3udnie","12:00:00",
-                   "p\x81\xf3\x81\xb3noc","00:00:00",
-                   "poludnie","12:00:00","polnoc","00:00:00"];
-  $$d{"offset"}  =["wczoraj","-0:0:1:0:0:0","jutro","+0:0:1:0:0:0"];
-
-  $$d{"years"}   =["rok","lat","lata","latach"];
-  $$d{"months"}  =["m.","miesiac","miesi\x81\xb9c","miesiecy",
-                   "miesi\x81\xeacy","miesiacu","miesi\x81\xb9cu"];
-  $$d{"weeks"}   =["ty.","tydzien","tydzie\x81\xf1","tygodniu"];
-  $$d{"days"}    =["d.","dzien","dzie\x81\xf1","dni"];
-  $$d{"hours"}   =["g.","godzina","godziny","godzinie"];
-  $$d{"minutes"} =["mn.","min.","minut","minuty"];
-  $$d{"seconds"} =["s.","sekund","sekundy"];
-  $$d{"replace"} =["m.","miesiac"];
-
-  $$d{"sephm"}   =':';
-  $$d{"sepms"}   =':';
-  $$d{"sepss"}   ='[.:]';
-
-  $$d{"am"}      = ["AM","A.M."];
-  $$d{"pm"}      = ["PM","P.M."];
-}
-
-sub Date_Init_Spanish {
-  print "DEBUG: Date_Init_Spanish\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($d)=@_;
-  my(%h)=();
-  &Char_8Bit(\%h);
-
-  $$d{"month_name"}=
-    [["Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto",
-      "Septiembre","Octubre","Noviembre","Diciembre"]];
-
-  $$d{"month_abb"}=
-    [["Ene","Feb","Mar","Abr","May","Jun","Jul","Ago","Sep","Oct",
-      "Nov","Dic"]];
-
-  $$d{"day_name"}=
-    [["Lunes","Martes","Miercoles","Jueves","Viernes","Sabado","Domingo"]];
-  $$d{"day_abb"}=
-    [["Lun","Mar","Mie","Jue","Vie","Sab","Dom"]];
-  $$d{"day_char"}=
-    [["L","Ma","Mi","J","V","S","D"]];
-
-  $$d{"num_suff"}=
-    [["1o","2o","3o","4o","5o","6o","7o","8o","9o","10o",
-      "11o","12o","13o","14o","15o","16o","17o","18o","19o","20o",
-      "21o","22o","23o","24o","25o","26o","27o","28o","29o","30o","31o"],
-     ["1a","2a","3a","4a","5a","6a","7a","8a","9a","10a",
-      "11a","12a","13a","14a","15a","16a","17a","18a","19a","20a",
-      "21a","22a","23a","24a","25a","26a","27a","28a","29a","30a","31a"]];
-  $$d{"num_word"}=
-    [["Primero","Segundo","Tercero","Cuarto","Quinto","Sexto","Septimo",
-      "Octavo","Noveno","Decimo","Decimo Primero","Decimo Segundo",
-      "Decimo Tercero","Decimo Cuarto","Decimo Quinto","Decimo Sexto",
-      "Decimo Septimo","Decimo Octavo","Decimo Noveno","Vigesimo",
-      "Vigesimo Primero","Vigesimo Segundo","Vigesimo Tercero",
-      "Vigesimo Cuarto","Vigesimo Quinto","Vigesimo Sexto",
-      "Vigesimo Septimo","Vigesimo Octavo","Vigesimo Noveno","Trigesimo",
-      "Trigesimo Primero"],
-     ["Primera","Segunda","Tercera","Cuarta","Quinta","Sexta","Septima",
-      "Octava","Novena","Decima","Decimo Primera","Decimo Segunda",
-      "Decimo Tercera","Decimo Cuarta","Decimo Quinta","Decimo Sexta",
-      "Decimo Septima","Decimo Octava","Decimo Novena","Vigesima",
-      "Vigesimo Primera","Vigesimo Segunda","Vigesimo Tercera",
-      "Vigesimo Cuarta","Vigesimo Quinta","Vigesimo Sexta",
-      "Vigesimo Septima","Vigesimo Octava","Vigesimo Novena","Trigesima",
-      "Trigesimo Primera"]];
-
-  $$d{"now"}     =["Hoy","Ahora"];
-  $$d{"last"}    =["ultimo"];
-  $$d{"each"}    =["cada"];
-  $$d{"of"}      =["en","de"];
-  $$d{"at"}      =["a"];
-  $$d{"on"}      =["el"];
-  $$d{"future"}  =["en"];
-  $$d{"past"}    =["hace"];
-  $$d{"next"}    =["siguiente"];
-  $$d{"prev"}    =["anterior"];
-  $$d{"later"}   =["later"];
-
-  $$d{"exact"}   =["exactamente"];
-  $$d{"approx"}  =["aproximadamente"];
-  $$d{"business"}=["laborales"];
-
-  $$d{"offset"}  =["ayer","-0:0:0:1:0:0:0","manana","+0:0:0:1:0:0:0"];
-  $$d{"times"}   =["mediodia","12:00:00","medianoche","00:00:00"];
-
-  $$d{"years"}   =["a","ano","ano","anos","anos"];
-  $$d{"months"}  =["m","mes","mes","meses"];
-  $$d{"weeks"}   =["sem","semana","semana","semanas"];
-  $$d{"days"}    =["d","dia","dias"];
-  $$d{"hours"}   =["hr","hrs","hora","horas"];
-  $$d{"minutes"} =["min","min","minuto","minutos"];
-  $$d{"seconds"} =["s","seg","segundo","segundos"];
-  $$d{"replace"} =["m","mes"];
-
-  $$d{"sephm"}   =':';
-  $$d{"sepms"}   =':';
-  $$d{"sepss"}   ='[.:]';
-
-  $$d{"am"}      = ["AM","A.M."];
-  $$d{"pm"}      = ["PM","P.M."];
-}
-
-sub Date_Init_Portuguese {
-  print "DEBUG: Date_Init_Portuguese\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($d)=@_;
-  my(%h)=();
-  &Char_8Bit(\%h);
-  my($o) = $h{"-o"};
-  my($c) = $h{",c"};
-  my($a) = $h{"a'"};
-  my($e) = $h{"e'"};
-  my($u) = $h{"u'"};
-  my($o2)= $h{"o'"};
-  my($a2)= $h{"a`"};
-  my($a3)= $h{"a~"};
-  my($e2)= $h{"e^"};
-
-  $$d{"month_name"}=
-    [["Janeiro","Fevereiro","Marco","Abril","Maio","Junho",
-      "Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"],
-     ["Janeiro","Fevereiro","Mar${c}o","Abril","Maio","Junho",
-      "Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"]];
-
-  $$d{"month_abb"}=
-    [["Jan","Fev","Mar","Abr","Mai","Jun",
-      "Jul","Ago","Set","Out","Nov","Dez"]];
-
-  $$d{"day_name"}=
-    [["Segunda","Terca","Quarta","Quinta","Sexta","Sabado","Domingo"],
-     ["Segunda","Ter${c}a","Quarta","Quinta","Sexta","S${a}bado","Domingo"]];
-  $$d{"day_abb"}=
-    [["Seg","Ter","Qua","Qui","Sex","Sab","Dom"],
-     ["Seg","Ter","Qua","Qui","Sex","S${a}b","Dom"]];
-  $$d{"day_char"}=
-    [["Sg","T","Qa","Qi","Sx","Sb","D"]];
-
-  $$d{"num_suff"}=
-    [["1${o}","2${o}","3${o}","4${o}","5${o}","6${o}","7${o}","8${o}",
-      "9${o}","10${o}","11${o}","12${o}","13${o}","14${o}","15${o}",
-      "16${o}","17${o}","18${o}","19${o}","20${o}","21${o}","22${o}",
-      "23${o}","24${o}","25${o}","26${o}","27${o}","28${o}","29${o}",
-      "30${o}","31${o}"]];
-  $$d{"num_word"}=
-    [["primeiro","segundo","terceiro","quarto","quinto","sexto","setimo",
-      "oitavo","nono","decimo","decimo primeiro","decimo segundo",
-      "decimo terceiro","decimo quarto","decimo quinto","decimo sexto",
-      "decimo setimo","decimo oitavo","decimo nono","vigesimo",
-      "vigesimo primeiro","vigesimo segundo","vigesimo terceiro",
-      "vigesimo quarto","vigesimo quinto","vigesimo sexto","vigesimo setimo",
-      "vigesimo oitavo","vigesimo nono","trigesimo","trigesimo primeiro"],
-     ["primeiro","segundo","terceiro","quarto","quinto","sexto","s${e}timo",
-      "oitavo","nono","d${e}cimo","d${e}cimo primeiro","d${e}cimo segundo",
-      "d${e}cimo terceiro","d${e}cimo quarto","d${e}cimo quinto",
-      "d${e}cimo sexto","d${e}cimo s${e}timo","d${e}cimo oitavo",
-      "d${e}cimo nono","vig${e}simo","vig${e}simo primeiro",
-      "vig${e}simo segundo","vig${e}simo terceiro","vig${e}simo quarto",
-      "vig${e}simo quinto","vig${e}simo sexto","vig${e}simo s${e}timo",
-      "vig${e}simo oitavo","vig${e}simo nono","trig${e}simo",
-      "trig${e}simo primeiro"]];
-
-  $$d{"now"}     =["agora","hoje"];
-  $$d{"last"}    =["${u}ltimo","ultimo"];
-  $$d{"each"}    =["cada"];
-  $$d{"of"}      =["da","do"];
-  $$d{"at"}      =["as","${a2}s"];
-  $$d{"on"}      =["na","no"];
-  $$d{"future"}  =["em"];
-  $$d{"past"}    =["a","${a2}"];
-  $$d{"next"}    =["proxima","proximo","pr${o2}xima","pr${o2}ximo"];
-  $$d{"prev"}    =["ultima","ultimo","${u}ltima","${u}ltimo"];
-  $$d{"later"}   =["passadas","passados"];
-
-  $$d{"exact"}   =["exactamente"];
-  $$d{"approx"}  =["aproximadamente"];
-  $$d{"business"}=["util","uteis"];
-
-  $$d{"offset"}  =["ontem","-0:0:0:1:0:0:0",
-                   "amanha","+0:0:0:1:0:0:0","amanh${a3}","+0:0:0:1:0:0:0"];
-  $$d{"times"}   =["meio-dia","12:00:00","meia-noite","00:00:00"];
-
-  $$d{"years"}   =["anos","ano","ans","an","a"];
-  $$d{"months"}  =["meses","m${e2}s","mes","m"];
-  $$d{"weeks"}   =["semanas","semana","sem","sems","s"];
-  $$d{"days"}    =["dias","dia","d"];
-  $$d{"hours"}   =["horas","hora","hr","hrs"];
-  $$d{"minutes"} =["minutos","minuto","min","mn"];
-  $$d{"seconds"} =["segundos","segundo","seg","sg"];
-  $$d{"replace"} =["m","mes","s","sems"];
-
-  $$d{"sephm"}   =':';
-  $$d{"sepms"}   =':';
-  $$d{"sepss"}   ='[,]';
-
-  $$d{"am"}      = ["AM","A.M."];
-  $$d{"pm"}      = ["PM","P.M."];
-}
-
-sub Date_Init_Russian {
-  print "DEBUG: Date_Init_Russian\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($d)=@_;
-  my(%h)=();
-  &Char_8Bit(\%h);
-  my($a) =$h{"a:"};
-
-  $$d{"month_name"}=
-    [
-     ["\xd1\xce\xd7\xc1\xd2\xd1","\xc6\xc5\xd7\xd2\xc1\xcc\xd1",
-      "\xcd\xc1\xd2\xd4\xc1","\xc1\xd0\xd2\xc5\xcc\xd1","\xcd\xc1\xd1",
-      "\xc9\xc0\xce\xd1",
-      "\xc9\xc0\xcc\xd1","\xc1\xd7\xc7\xd5\xd3\xd4\xc1",
-      "\xd3\xc5\xce\xd4\xd1\xc2\xd2\xd1","\xcf\xcb\xd4\xd1\xc2\xd2\xd1",
-      "\xce\xcf\xd1\xc2\xd2\xd1","\xc4\xc5\xcb\xc1\xc2\xd2\xd1"],
-     ["\xd1\xce\xd7\xc1\xd2\xd8","\xc6\xc5\xd7\xd2\xc1\xcc\xd8",
-      "\xcd\xc1\xd2\xd4","\xc1\xd0\xd2\xc5\xcc\xd8","\xcd\xc1\xca",
-      "\xc9\xc0\xce\xd8",
-      "\xc9\xc0\xcc\xd8","\xc1\xd7\xc7\xd5\xd3\xd4",
-      "\xd3\xc5\xce\xd4\xd1\xc2\xd2\xd8","\xcf\xcb\xd4\xd1\xc2\xd2\xd8",
-      "\xce\xcf\xd1\xc2\xd2\xd8","\xc4\xc5\xcb\xc1\xc2\xd2\xd8"]
-    ];
-
-  $$d{"month_abb"}=
-    [["\xd1\xce\xd7","\xc6\xc5\xd7","\xcd\xd2\xd4","\xc1\xd0\xd2",
-      "\xcd\xc1\xca","\xc9\xc0\xce",
-      "\xc9\xc0\xcc","\xc1\xd7\xc7","\xd3\xce\xd4","\xcf\xcb\xd4",
-      "\xce\xcf\xd1\xc2","\xc4\xc5\xcb"],
-     ["","\xc6\xd7\xd2","","","\xcd\xc1\xd1","",
-      "","","\xd3\xc5\xce","\xcf\xcb\xd4","\xce\xcf\xd1",""]];
-
-  $$d{"day_name"}=
-    [["\xd0\xcf\xce\xc5\xc4\xc5\xcc\xd8\xce\xc9\xcb",
-      "\xd7\xd4\xcf\xd2\xce\xc9\xcb","\xd3\xd2\xc5\xc4\xc1",
-      "\xde\xc5\xd4\xd7\xc5\xd2\xc7","\xd0\xd1\xd4\xce\xc9\xc3\xc1",
-      "\xd3\xd5\xc2\xc2\xcf\xd4\xc1",
-      "\xd7\xcf\xd3\xcb\xd2\xc5\xd3\xc5\xce\xd8\xc5"]];
-  $$d{"day_abb"}=
-    [["\xd0\xce\xc4","\xd7\xd4\xd2","\xd3\xd2\xc4","\xde\xd4\xd7",
-      "\xd0\xd4\xce","\xd3\xd5\xc2","\xd7\xd3\xcb"],
-     ["\xd0\xcf\xce","\xd7\xd4\xcf","\xd3\xd2e","\xde\xc5\xd4",
-      "\xd0\xd1\xd4","\xd3\xd5\xc2","\xd7\xcf\xd3\xcb"]];
-  $$d{"day_char"}=
-    [["\xd0\xce","\xd7\xd4","\xd3\xd2","\xde\xd4","\xd0\xd4","\xd3\xc2",
-      "\xd7\xd3"]];
-
-  $$d{"num_suff"}=
-    [["1 ","2 ","3 ","4 ","5 ","6 ","7 ","8 ","9 ","10 ",
-      "11 ","12 ","13 ","14 ","15 ","16 ","17 ","18 ","19 ","20 ",
-      "21 ","22 ","23 ","24 ","25 ","26 ","27 ","28 ","29 ","30 ",
-      "31 "]];
-  $$d{"num_word"}=
-    [["\xd0\xc5\xd2\xd7\xd9\xca","\xd7\xd4\xcf\xd2\xcf\xca",
-      "\xd4\xd2\xc5\xd4\xc9\xca","\xde\xc5\xd4\xd7\xc5\xd2\xd4\xd9\xca",
-      "\xd0\xd1\xd4\xd9\xca","\xdb\xc5\xd3\xd4\xcf\xca",
-      "\xd3\xc5\xc4\xd8\xcd\xcf\xca","\xd7\xcf\xd3\xd8\xcd\xcf\xca",
-      "\xc4\xc5\xd7\xd1\xd4\xd9\xca","\xc4\xc5\xd3\xd1\xd4\xd9\xca",
-      "\xcf\xc4\xc9\xce\xce\xc1\xc4\xc3\xc1\xd4\xd9\xca",
-      "\xc4\xd7\xc5\xce\xc1\xc4\xde\xc1\xd4\xd9\xca",
-      "\xd4\xd2\xc5\xce\xc1\xc4\xc3\xc1\xd4\xd9\xca",
-      "\xde\xc5\xd4\xd9\xd2\xce\xc1\xc4\xc3\xc1\xd4\xd9\xca",
-      "\xd0\xd1\xd4\xce\xc1\xc4\xc3\xc1\xd4\xd9\xca",
-      "\xdb\xc5\xd3\xd4\xce\xc1\xc4\xc3\xc1\xd4\xd9\xca",
-      "\xd3\xc5\xcd\xd8\xce\xc1\xc4\xc3\xc1\xd4\xd9\xca",
-      "\xd7\xcf\xd3\xc5\xcd\xd8\xce\xc1\xc4\xc3\xc1\xd4\xd9\xca",
-      "\xc4\xc5\xd7\xd1\xd4\xce\xc1\xc4\xc3\xc1\xd4\xd9\xca",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd9\xca",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd0\xc5\xd2\xd7\xd9\xca",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd7\xd4\xcf\xd2\xcf\xca",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd4\xd2\xc5\xd4\xc9\xca",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xde\xc5\xd4\xd7\xc5\xd2\xd4\xd9\xca",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd0\xd1\xd4\xd9\xca",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xdb\xc5\xd3\xd4\xcf\xca",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd3\xc5\xc4\xd8\xcd\xcf\xca",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd7\xcf\xd3\xd8\xcd\xcf\xca",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xc4\xc5\xd7\xd1\xd4\xd9\xca",
-      "\xd4\xd2\xc9\xc4\xc3\xc1\xd4\xd9\xca",
-      "\xd4\xd2\xc9\xc4\xc3\xc1\xd4\xd8 \xd0\xc5\xd2\xd7\xd9\xca"],
-
-     ["\xd0\xc5\xd2\xd7\xcf\xc5","\xd7\xd4\xcf\xd2\xcf\xc5",
-      "\xd4\xd2\xc5\xd4\xd8\xc5","\xde\xc5\xd4\xd7\xc5\xd2\xd4\xcf\xc5",
-      "\xd0\xd1\xd4\xcf\xc5","\xdb\xc5\xd3\xd4\xcf\xc5",
-      "\xd3\xc5\xc4\xd8\xcd\xcf\xc5","\xd7\xcf\xd3\xd8\xcd\xcf\xc5",
-      "\xc4\xc5\xd7\xd1\xd4\xcf\xc5","\xc4\xc5\xd3\xd1\xd4\xcf\xc5",
-      "\xcf\xc4\xc9\xce\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc5",
-      "\xc4\xd7\xc5\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc5",
-      "\xd4\xd2\xc5\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc5",
-      "\xde\xc5\xd4\xd9\xd2\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc5",
-      "\xd0\xd1\xd4\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc5",
-      "\xdb\xc5\xd3\xd4\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc5",
-      "\xd3\xc5\xcd\xd8\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc5",
-      "\xd7\xcf\xd3\xc5\xcd\xd8\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc5",
-      "\xc4\xc5\xd7\xd1\xd4\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc5",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xcf\xc5",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd0\xc5\xd2\xd7\xcf\xc5",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd7\xd4\xcf\xd2\xcf\xc5",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd4\xd2\xc5\xd4\xd8\xc5",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xde\xc5\xd4\xd7\xc5\xd2\xd4\xcf\xc5",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd0\xd1\xd4\xcf\xc5",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xdb\xc5\xd3\xd4\xcf\xc5",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd3\xc5\xc4\xd8\xcd\xcf\xc5",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd7\xcf\xd3\xd8\xcd\xcf\xc5",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xc4\xc5\xd7\xd1\xd4\xcf\xc5",
-      "\xd4\xd2\xc9\xc4\xc3\xc1\xd4\xcf\xc5",
-      "\xd4\xd2\xc9\xc4\xc3\xc1\xd4\xd8 \xd0\xc5\xd2\xd7\xcf\xc5"],
-
-     ["\xd0\xc5\xd2\xd7\xcf\xc7\xcf","\xd7\xd4\xcf\xd2\xcf\xc7\xcf",
-      "\xd4\xd2\xc5\xd4\xd8\xc5\xc7\xcf",
-      "\xde\xc5\xd4\xd7\xc5\xd2\xd4\xcf\xc7\xcf","\xd0\xd1\xd4\xcf\xc7\xcf",
-      "\xdb\xc5\xd3\xd4\xcf\xc7\xcf","\xd3\xc5\xc4\xd8\xcd\xcf\xc7\xcf",
-      "\xd7\xcf\xd3\xd8\xcd\xcf\xc7\xcf",
-      "\xc4\xc5\xd7\xd1\xd4\xcf\xc7\xcf","\xc4\xc5\xd3\xd1\xd4\xcf\xc7\xcf",
-      "\xcf\xc4\xc9\xce\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf",
-      "\xc4\xd7\xc5\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf",
-      "\xd4\xd2\xc5\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf",
-      "\xde\xc5\xd4\xd9\xd2\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf",
-      "\xd0\xd1\xd4\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf",
-      "\xdb\xc5\xd3\xd4\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf",
-      "\xd3\xc5\xcd\xd8\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf",
-      "\xd7\xcf\xd3\xc5\xcd\xd8\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf",
-      "\xc4\xc5\xd7\xd1\xd4\xce\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xcf\xc7\xcf",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd0\xc5\xd2\xd7\xcf\xc7\xcf",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd7\xd4\xcf\xd2\xcf\xc5",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd4\xd2\xc5\xd4\xd8\xc5\xc7\xcf",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xde\xc5\xd4\xd7\xc5\xd2\xd4\xcf\xc7\xcf",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd0\xd1\xd4\xcf\xc7\xcf",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xdb\xc5\xd3\xd4\xcf\xc7\xcf",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd3\xc5\xc4\xd8\xcd\xcf\xc7\xcf",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xd7\xcf\xd3\xd8\xcd\xcf\xc7\xcf",
-      "\xc4\xd7\xc1\xc4\xc3\xc1\xd4\xd8 \xc4\xc5\xd7\xd1\xd4\xcf\xc7\xcf",
-      "\xd4\xd2\xc9\xc4\xc3\xc1\xd4\xcf\xc7\xcf",
-      "\xd4\xd2\xc9\xc4\xc3\xc1\xd4\xd8 \xd0\xc5\xd2\xd7\xcf\xc7\xcf"]];
-
-  $$d{"now"}     =["\xd3\xc5\xc7\xcf\xc4\xce\xd1","\xd3\xc5\xca\xde\xc1\xd3"];
-  $$d{"last"}    =["\xd0\xcf\xd3\xcc\xc5\xc4\xce\xc9\xca"];
-  $$d{"each"}    =["\xcb\xc1\xd6\xc4\xd9\xca"];
-  $$d{"of"}      =[" "];
-  $$d{"at"}      =["\xd7"];
-  $$d{"on"}      =["\xd7"];
-  $$d{"future"}  =["\xd7\xd0\xc5\xd2\xc5\xc4 \xce\xc1"];
-  $$d{"past"}    =["\xce\xc1\xda\xc1\xc4 \xce\xc1 "];
-  $$d{"next"}    =["\xd3\xcc\xc5\xc4\xd5\xc0\xdd\xc9\xca"];
-  $$d{"prev"}    =["\xd0\xd2\xc5\xc4\xd9\xc4\xd5\xdd\xc9\xca"];
-  $$d{"later"}   =["\xd0\xcf\xda\xd6\xc5"];
-
-  $$d{"exact"}   =["\xd4\xcf\xde\xce\xcf"];
-  $$d{"approx"}  =["\xd0\xd2\xc9\xcd\xc5\xd2\xce\xcf"];
-  $$d{"business"}=["\xd2\xc1\xc2\xcf\xde\xc9\xc8"];
-
-  $$d{"offset"}  =["\xd0\xcf\xda\xc1\xd7\xde\xc5\xd2\xc1","-0:0:0:2:0:0:0",
-                   "\xd7\xde\xc5\xd2\xc1","-0:0:0:1:0:0:0",
-                   "\xda\xc1\xd7\xd4\xd2\xc1","+0:0:0:1:0:0:0",
-                   "\xd0\xcf\xd3\xcc\xc5\xda\xc1\xd7\xd4\xd2\xc1",
-                   "+0:0:0:2:0:0:0"];
-  $$d{"times"}   =["\xd0\xcf\xcc\xc4\xc5\xce\xd8","12:00:00",
-                   "\xd0\xcf\xcc\xce\xcf\xde\xd8","00:00:00"];
-
-  $$d{"years"}   =["\xc7","\xc7\xc4","\xc7\xcf\xc4","\xcc\xc5\xd4",
-                   "\xcc\xc5\xd4","\xc7\xcf\xc4\xc1"];
-  $$d{"months"}  =["\xcd\xc5\xd3","\xcd\xc5\xd3\xd1\xc3",
-                   "\xcd\xc5\xd3\xd1\xc3\xc5\xd7"];
-  $$d{"weeks"}   =["\xce\xc5\xc4\xc5\xcc\xd1","\xce\xc5\xc4\xc5\xcc\xd8",
-                   "\xce\xc5\xc4\xc5\xcc\xc9","\xce\xc5\xc4\xc5\xcc\xc0"];
-  $$d{"days"}    =["\xc4","\xc4\xc5\xce\xd8","\xc4\xce\xc5\xca",
-                   "\xc4\xce\xd1"];
-  $$d{"hours"}   =["\xde","\xde.","\xde\xd3","\xde\xd3\xd7","\xde\xc1\xd3",
-                   "\xde\xc1\xd3\xcf\xd7","\xde\xc1\xd3\xc1"];
-  $$d{"minutes"} =["\xcd\xce","\xcd\xc9\xce","\xcd\xc9\xce\xd5\xd4\xc1",
-                   "\xcd\xc9\xce\xd5\xd4"];
-  $$d{"seconds"} =["\xd3","\xd3\xc5\xcb","\xd3\xc5\xcb\xd5\xce\xc4\xc1",
-                   "\xd3\xc5\xcb\xd5\xce\xc4"];
-  $$d{"replace"} =[];
-
-  $$d{"sephm"}   ="[:\xde]";
-  $$d{"sepms"}   ="[:\xcd]";
-  $$d{"sepss"}   ="[:.\xd3]";
-
-  $$d{"am"}      = ["\xc4\xd0","${a}\xf0","${a}.\xf0.","\xce\xcf\xde\xc9",
-                    "\xd5\xd4\xd2\xc1",
-                    "\xc4\xcf \xd0\xcf\xcc\xd5\xc4\xce\xd1"];
-  $$d{"pm"}      = ["\xd0\xd0","\xf0\xf0","\xf0.\xf0.","\xc4\xce\xd1",
-                    "\xd7\xc5\xde\xc5\xd2\xc1",
-                    "\xd0\xcf\xd3\xcc\xc5 \xd0\xcf\xcc\xd5\xc4\xce\xd1",
-                    "\xd0\xcf \xd0\xcf\xcc\xd5\xc4\xce\xc0"];
-}
-
-sub Date_Init_Turkish {
-  print "DEBUG: Date_Init_Turkish\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($d)=@_;
-
-  $$d{"month_name"}=
-    [
-     ["ocak","subat","mart","nisan","mayis","haziran",
-      "temmuz","agustos","eylul","ekim","kasim","aralik"],
-     ["ocak","\xfeubat","mart","nisan","may\xfds","haziran",
-      "temmuz","a\xf0ustos","eyl\xfcl","ekim","kas\xfdm","aral\xfdk"]
-     ];
-
-  $$d{"month_abb"}=
-    [
-     ["oca","sub","mar","nis","may","haz",
-      "tem","agu","eyl","eki","kas","ara"],
-     ["oca","\xfeub","mar","nis","may","haz",
-      "tem","a\xf0u","eyl","eki","kas","ara"]
-     ];
-
-  $$d{"day_name"}=
-    [
-     ["pazartesi","sali","carsamba","persembe","cuma","cumartesi","pazar"],
-     ["pazartesi","sal\xfd","\xe7ar\xfeamba","per\xfeembe","cuma",
-      "cumartesi","pazar"],
-     ];
-
-  $$d{"day_abb"}=
-    [
-     ["pzt","sal","car","per","cum","cts","paz"],
-     ["pzt","sal","\xe7ar","per","cum","cts","paz"],
-     ];
-
-  $$d{"day_char"}=
-    [["Pt","S","Cr","Pr","C","Ct","P"],
-     ["Pt","S","\xc7","Pr","C","Ct","P"]];
-
-  $$d{"num_suff"}=
-    [[ "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", "9.", "10.",
-       "11.", "12.", "13.", "14.", "15.", "16.", "17.", "18.", "19.", "20.",
-       "21.", "22.", "23.", "24.", "25.", "26.", "27.", "28.", "29.", "30.",
-       "31."]];
-
-  $$d{"num_word"}=
-    [
-     ["birinci","ikinci","ucuncu","dorduncu",
-      "besinci","altinci","yedinci","sekizinci",
-      "dokuzuncu","onuncu","onbirinci","onikinci",
-      "onucuncu","ondordoncu",
-      "onbesinci","onaltinci","onyedinci","onsekizinci",
-      "ondokuzuncu","yirminci","yirmibirinci","yirmikinci",
-      "yirmiucuncu","yirmidorduncu",
-      "yirmibesinci","yirmialtinci","yirmiyedinci","yirmisekizinci",
-      "yirmidokuzuncu","otuzuncu","otuzbirinci"],
-     ["birinci","ikinci","\xfc\xe7\xfcnc\xfc","d\xf6rd\xfcnc\xfc",
-      "be\xfeinci","alt\xfdnc\xfd","yedinci","sekizinci",
-      "dokuzuncu","onuncu","onbirinci","onikinci",
-      "on\xfc\xe7\xfcnc\xfc","ond\xf6rd\xfcnc\xfc",
-      "onbe\xfeinci","onalt\xfdnc\xfd","onyedinci","onsekizinci",
-      "ondokuzuncu","yirminci","yirmibirinci","yirmikinci",
-      "yirmi\xfc\xe7\xfcnc\xfc","yirmid\xf6rd\xfcnc\xfc",
-      "yirmibe\xfeinci","yirmialt\xfdnc\xfd","yirmiyedinci","yirmisekizinci",
-      "yirmidokuzuncu","otuzuncu","otuzbirinci"]
-     ];
-
-  $$d{"now"}     =["\xfeimdi", "simdi", "bugun","bug\xfcn"];
-  $$d{"last"}    =["son", "sonuncu"];
-  $$d{"each"}    =["her"];
-  $$d{"of"}      =["of"];
-  $$d{"at"}      =["saat"];
-  $$d{"on"}      =["on"];
-  $$d{"future"}  =["gelecek"];
-  $$d{"past"}    =["ge\xe7mi\xfe", "gecmis","gecen", "ge\xe7en"];
-  $$d{"next"}    =["gelecek","sonraki"];
-  $$d{"prev"}    =["onceki","\xf6nceki"];
-  $$d{"later"}   =["sonra"];
-
-  $$d{"exact"}   =["tam"];
-  $$d{"approx"}  =["yakla\xfe\xfdk", "yaklasik"];
-  $$d{"business"}=["i\xfe","\xe7al\xfd\xfema","is", "calisma"];
-
-  $$d{"offset"}  =["d\xfcn","-0:0:0:1:0:0:0",
-                   "dun", "-0:0:0:1:0:0:0",
-                   "yar\xfdn","+0:0:0:1:0:0:0",
-                   "yarin","+0:0:0:1:0:0:0"];
-
-  $$d{"times"}   =["\xf6\xf0len","12:00:00",
-                   "oglen","12:00:00",
-                   "yarim","12:300:00",
-                   "yar\xfdm","12:30:00",
-                   "gece yar\xfds\xfd","00:00:00",
-                   "gece yarisi","00:00:00"];
-
-  $$d{"years"}   =["yil","y"];
-  $$d{"months"}  =["ay","a"];
-  $$d{"weeks"}   =["hafta", "h"];
-  $$d{"days"}    =["gun","g"];
-  $$d{"hours"}   =["saat"];
-  $$d{"minutes"} =["dakika","dak","d"];
-  $$d{"seconds"} =["saniye","sn",];
-  $$d{"replace"} =["s","saat"];
-
-  $$d{"sephm"}   =':';
-  $$d{"sepms"}   =':';
-  $$d{"sepss"}   ='[.:,]';
-
-  $$d{"am"}      = ["\xf6gleden \xf6nce","ogleden once"];
-  $$d{"pm"}      = ["\xf6\xf0leden sonra","ogleden sonra"];
-}
-
-sub Date_Init_Danish {
-  print "DEBUG: Date_Init_Danish\n"  if ($Curr{"Debug"} =~ /trace/);
-  my($d)=@_;
-
-  $$d{"month_name"}=
-    [["Januar","Februar","Marts","April","Maj","Juni",
-      "Juli","August","September","Oktober","November","December"]];
-  $$d{"month_abb"}=
-    [["Jan","Feb","Mar","Apr","Maj","Jun",
-      "Jul","Aug","Sep","Okt","Nov","Dec"]];
-
-  $$d{"day_name"}=
-    [["Mandag","Tirsdag","Onsdag","Torsdag","Fredag","Lordag","Sondag"],
-     ["Mandag","Tirsdag","Onsdag","Torsdag","Fredag","L\xf8rdag","S\xf8ndag"]];
-
-  $$d{"day_abb"}=
-    [["Man","Tis","Ons","Tor","Fre","Lor","Son"],
-     ["Man","Tis","Ons","Tor","Fre","L\xf8r","S\xf8n"]];
-  $$d{"day_char"}=
-    [["M","Ti","O","To","F","L","S"]];
-
-  $$d{"num_suff"}=
-    [["1:e","2:e","3:e","4:e","5:e","6:e","7:e","8:e","9:e","10:e",
-      "11:e","12:e","13:e","14:e","15:e","16:e","17:e","18:e","19:e","20:e",
-      "21:e","22:e","23:e","24:e","25:e","26:e","27:e","28:e","29:e","30:e",
-      "31:e"]];
-  $$d{"num_word"}=
-    [["forste","anden","tredie","fjerde","femte","sjette","syvende",
-      "ottende","niende","tiende","elfte","tolvte","trettende","fjortende",
-      "femtende","sekstende","syttende","attende","nittende","tyvende",
-      "enogtyvende","toogtyvende","treogtyvende","fireogtyvende","femogtyvende",
-      "seksogtyvende","syvogtyvende","otteogtyvende","niogtyvende",
-      "tredivte","enogtredivte"],
-     ["f\xf8rste","anden","tredie","fjerde","femte","sjette","syvende",
-      "ottende","niende","tiende","elfte","tolvte","trettende","fjortende",
-      "femtende","sekstende","syttende","attende","nittende","tyvende",
-      "enogtyvende","toogtyvende","treogtyvende","fireogtyvende","femogtyvende",
-      "seksogtyvende","syvogtyvende","otteogtyvende","niogtyvende",
-      "tredivte","enogtredivte"]];
-
-  $$d{"now"}     =["idag","nu"];
-  $$d{"last"}    =["forrige","sidste","nyeste"];
-  $$d{"each"}    =["hver"];
-  $$d{"of"}      =["om"];
-  $$d{"at"}      =["kl","kl.","klokken"];
-  $$d{"on"}      =["pa","p\xe5"];
-  $$d{"future"}  =["om"];
-  $$d{"past"}    =["siden"];
-  $$d{"next"}    =["nasta","n\xe6ste"];
-  $$d{"prev"}    =["forrige"];
-  $$d{"later"}   =["senere"];
-
-  $$d{"exact"}   =["pracist","pr\xe6cist"];
-  $$d{"approx"}  =["circa"];
-  $$d{"business"}=["arbejdsdag","arbejdsdage"];
-
-  $$d{"offset"}  =["ig\xe5r","-0:0:0:1:0:0:0","igar","-0:0:0:1:0:0:0",
-                   "imorgen","+0:0:0:1:0:0:0"];
-  $$d{"times"}   =["midt pa dagen","12:00:00","midt p\xe5 dagen","12:00:00",
-                   "midnat","00:00:00"];
-
-  $$d{"years"}   =["ar","\xe5r"];
-  $$d{"months"}  =["man","maned","maneder","m\xe5n","m\xe5ned","m\xe5neder"];
-  $$d{"weeks"}   =["u","uge","uger"];
-  $$d{"days"}    =["d","dag","dage"];
-  $$d{"hours"}   =["t","tim","time","timer"];
-  $$d{"minutes"} =["min","minut","minutter"];
-  $$d{"seconds"} =["s","sek","sekund","sekunder"];
-  $$d{"replace"} =["m","minut"];
-
-  $$d{"sephm"}   ='[.:]';
-  $$d{"sepms"}   =':';
-  $$d{"sepss"}   ='[.:]';
-
-  $$d{"am"}      = ["FM"];
-  $$d{"pm"}      = ["EM"];
-}
-
-########################################################################
-# FROM MY PERSONAL LIBRARIES
-########################################################################
-
-no integer;
-
-# &ModuloAddition($N,$add,\$val,\$rem);
-#   This calculates $val=$val+$add and forces $val to be in a certain range.
-#   This is useful for adding numbers for which only a certain range is
-#   allowed (for example, minutes can be between 0 and 59 or months can be
-#   between 1 and 12).  The absolute value of $N determines the range and
-#   the sign of $N determines whether the range is 0 to N-1 (if N>0) or
-#   1 to N (N<0).  The remainder (as modulo N) is added to $rem.
-#   Example:
-#     To add 2 hours together (with the excess returned in days) use:
-#       &ModuloAddition(60,$s1,\$s,\$day);
-sub ModuloAddition {
-  my($N,$add,$val,$rem)=@_;
-  return  if ($N==0);
-  $$val+=$add;
-  if ($N<0) {
-    # 1 to N
-    $N = -$N;
-    if ($$val>$N) {
-      $$rem+= int(($$val-1)/$N);
-      $$val = ($$val-1)%$N +1;
-    } elsif ($$val<1) {
-      $$rem-= int(-$$val/$N)+1;
-      $$val = $N-(-$$val % $N);
-    }
-
-  } else {
-    # 0 to N-1
-    if ($$val>($N-1)) {
-      $$rem+= int($$val/$N);
-      $$val = $$val%$N;
-    } elsif ($$val<0) {
-      $$rem-= int(-($$val+1)/$N)+1;
-      $$val = ($N-1)-(-($$val+1)%$N);
-    }
-  }
-}
-
-# $Flag=&IsInt($String [,$low, $high]);
-#    Returns 1 if $String is a valid integer, 0 otherwise.  If $low is
-#    entered, $String must be >= $low.  If $high is entered, $String must
-#    be <= $high.  It is valid to check only one of the bounds.
-sub IsInt {
-  my($N,$low,$high)=@_;
-  return 0  if (! defined $N  or
-                $N !~ /^\s*[-+]?\d+\s*$/  or
-                defined $low   &&  $N<$low  or
-                defined $high  &&  $N>$high);
-  return 1;
-}
-
-# $Pos=&SinLindex(\@List,$Str [,$offset [,$CaseInsensitive]]);
-#    Searches for an exact string in a list.
-#
-#    This is similar to RinLindex except that it searches for elements
-#    which are exactly equal to $Str (possibly case insensitive).
-sub SinLindex {
-  my($listref,$Str,$offset,$Insensitive)=@_;
-  my($i,$len,$tmp)=();
-  $len=$#$listref;
-  return -2  if ($len<0 or ! $Str);
-  return -1  if (&Index_First(\$offset,$len));
-  $Str=uc($Str)  if ($Insensitive);
-  for ($i=$offset; $i<=$len; $i++) {
-    $tmp=$$listref[$i];
-    $tmp=uc($tmp)  if ($Insensitive);
-    return $i  if ($tmp eq $Str);
-  }
-  return -1;
-}
-
-sub Index_First {
-  my($offsetref,$max)=@_;
-  $$offsetref=0  if (! $$offsetref);
-  if ($$offsetref < 0) {
-    $$offsetref += $max + 1;
-    $$offsetref=0  if ($$offsetref < 0);
-  }
-  return -1 if ($$offsetref > $max);
-  return 0;
-}
-
-# $File=&CleanFile($file);
-#   This cleans up a path to remove the following things:
-#     double slash       /a//b  -> /a/b
-#     trailing dot       /a/.   -> /a
-#     leading dot        ./a    -> a
-#     trailing slash     a/     -> a
-sub CleanFile {
-  my($file)=@_;
-  $file =~ s/\s*$//;
-  $file =~ s/^\s*//;
-  $file =~ s|//+|/|g;  # multiple slash
-  $file =~ s|/\.$|/|;  # trailing /. (leaves trailing slash)
-  $file =~ s|^\./||    # leading ./
-    if ($file ne "./");
-  $file =~ s|/$||      # trailing slash
-    if ($file ne "/");
-  return $file;
-}
-
-# $File=&ExpandTilde($file);
-#   This checks to see if a "~" appears as the first character in a path.
-#   If it does, the "~" expansion is interpreted (if possible) and the full
-#   path is returned.  If a "~" expansion is used but cannot be
-#   interpreted, an empty string is returned.
-#
-#   This is Windows/Mac friendly.
-#   This is efficient.
-sub ExpandTilde {
-  my($file)=shift;
-  my($user,$home)=();
-  # ~aaa/bbb=      ~  aaa      /bbb
-  if ($file =~ s|^~([^/]*)||) {
-    $user=$1;
-    # Single user operating systems (Mac, MSWindows) don't have the getpwnam
-    # and getpwuid routines defined.  Try to catch various different ways
-    # of knowing we are on one of these systems:
-    return ""  if ($OS eq "Windows"  or
-                   $OS eq "Mac"  or
-                   $OS eq "Netware"  or
-                   $OS eq "MPE");
-    $user=""  if (! defined $user);
-
-    if ($user) {
-      $home= (getpwnam($user))[7];
-    } else {
-      $home= (getpwuid($<))[7];
-    }
-    $home = VMS::Filespec::unixpath($home)  if ($OS eq "VMS");
-    return ""  if (! $home);
-    $file="$home/$file";
-  }
-  $file;
-}
-
-# $File=&FullFilePath($file);
-#   Returns the full or relative path to $file (expanding "~" if necessary).
-#   Returns an empty string if a "~" expansion cannot be interpreted.  The
-#   path does not need to exist.  CleanFile is called.
-sub FullFilePath {
-  my($file)=shift;
-  my($rootpat) = '^/'; #default pattern to match absolute path
-  $rootpat = '^(\\|/|([A-Za-z]:[\\/]))' if ($OS eq 'Windows');
-  $file=&ExpandTilde($file);
-  return ""  if (! $file);
-  return &CleanFile($file);
-}
-
-# $Flag=&CheckFilePath($file [,$mode]);
-#   Checks to see if $file exists, to see what type it is, and whether
-#   the script can access it.  If it exists and has the correct mode, 1
-#   is returned.
-#
-#   $mode is a string which may contain any of the valid file test operator
-#   characters except t, M, A, C.  The appropriate test is run for each
-#   character.  For example, if $mode is "re" the -r and -e tests are both
-#   run.
-#
-#   An empty string is returned if the file doesn't exist.  A 0 is returned
-#   if the file exists but any test fails.
-#
-#   All characters in $mode which do not correspond to valid tests are
-#   ignored.
-sub CheckFilePath {
-  my($file,$mode)=@_;
-  my($test)=();
-  $file=&FullFilePath($file);
-  $mode = ""  if (! defined $mode);
-
-  # Run tests
-  return 0  if (! defined $file or ! $file);
-  return 0  if ((                  ! -e $file) or
-                ($mode =~ /r/  &&  ! -r $file) or
-                ($mode =~ /w/  &&  ! -w $file) or
-                ($mode =~ /x/  &&  ! -x $file) or
-                ($mode =~ /R/  &&  ! -R $file) or
-                ($mode =~ /W/  &&  ! -W $file) or
-                ($mode =~ /X/  &&  ! -X $file) or
-                ($mode =~ /o/  &&  ! -o $file) or
-                ($mode =~ /O/  &&  ! -O $file) or
-                ($mode =~ /z/  &&  ! -z $file) or
-                ($mode =~ /s/  &&  ! -s $file) or
-                ($mode =~ /f/  &&  ! -f $file) or
-                ($mode =~ /d/  &&  ! -d $file) or
-                ($mode =~ /l/  &&  ! -l $file) or
-                ($mode =~ /s/  &&  ! -s $file) or
-                ($mode =~ /p/  &&  ! -p $file) or
-                ($mode =~ /b/  &&  ! -b $file) or
-                ($mode =~ /c/  &&  ! -c $file) or
-                ($mode =~ /u/  &&  ! -u $file) or
-                ($mode =~ /g/  &&  ! -g $file) or
-                ($mode =~ /k/  &&  ! -k $file) or
-                ($mode =~ /T/  &&  ! -T $file) or
-                ($mode =~ /B/  &&  ! -B $file));
-  return 1;
-}
-#&&
-
-# $Path=&FixPath($path [,$full] [,$mode] [,$error]);
-#   Makes sure that every directory in $path (a colon separated list of
-#   directories) appears as a full path or relative path.  All "~"
-#   expansions are removed.  All trailing slashes are removed also.  If
-#   $full is non-nil, relative paths are expanded to full paths as well.
-#
-#   If $mode is given, it may be either "e", "r", or "w".  In this case,
-#   additional checking is done to each directory.  If $mode is "e", it
-#   need ony exist to pass the check.  If $mode is "r", it must have have
-#   read and execute permission.  If $mode is "w", it must have read,
-#   write, and execute permission.
-#
-#   The value of $error determines what happens if the directory does not
-#   pass the test.  If it is non-nil, if any directory does not pass the
-#   test, the subroutine returns the empty string.  Otherwise, it is simply
-#   removed from $path.
-#
-#   The corrected path is returned.
-sub FixPath {
-  my($path,$full,$mode,$err)=@_;
-  local($_)="";
-  my(@dir)=split(/$Cnf{"PathSep"}/,$path);
-  $full=0  if (! defined $full);
-  $mode="" if (! defined $mode);
-  $err=0   if (! defined $err);
-  $path="";
-  if ($mode eq "e") {
-    $mode="de";
-  } elsif ($mode eq "r") {
-    $mode="derx";
-  } elsif ($mode eq "w") {
-    $mode="derwx";
-  }
-
-  foreach (@dir) {
-
-    # Expand path
-    if ($full) {
-      $_=&FullFilePath($_);
-    } else {
-      $_=&ExpandTilde($_);
-    }
-    if (! $_) {
-      return ""  if ($err);
-      next;
-    }
-
-    # Check mode
-    if (! $mode  or  &CheckFilePath($_,$mode)) {
-      $path .= $Cnf{"PathSep"} . $_;
-    } else {
-      return "" if ($err);
-    }
-  }
-  $path =~ s/^$Cnf{"PathSep"}//;
-  return $path;
-}
-#&&
-
-# $File=&SearchPath($file,$path [,$mode] [,@suffixes]);
-#   Searches through directories in $path for a file named $file.  The
-#   full path is returned if one is found, or an empty string otherwise.
-#   The file may exist with one of the @suffixes.  The mode is checked
-#   similar to &CheckFilePath.
-#
-#   The first full path that matches the name and mode is returned.  If none
-#   is found, an empty string is returned.
-sub SearchPath {
-  my($file,$path,$mode,@suff)=@_;
-  my($f,$s,$d,@dir,$fs)=();
-  $path=&FixPath($path,1,"r");
-  @dir=split(/$Cnf{"PathSep"}/,$path);
-  foreach $d (@dir) {
-    $f="$d/$file";
-    $f=~ s|//|/|g;
-    return $f if (&CheckFilePath($f,$mode));
-    foreach $s (@suff) {
-      $fs="$f.$s";
-      return $fs if (&CheckFilePath($fs,$mode));
-    }
-  }
-  return "";
-}
-
-# @list=&ReturnList($str);
-#    This takes a string which should be a comma separated list of integers
-#    or ranges (5-7).  It returns a sorted list of all integers referred to
-#    by the string, or () if there is an invalid element.
-#
-#    Negative integers are also handled.  "-2--1" is equivalent to "-2,-1".
-sub ReturnList {
-  my($str)=@_;
-  my(@ret,@str,$from,$to,$tmp)=();
-  @str=split(/,/,$str);
-  foreach $str (@str) {
-    if ($str =~ /^[-+]?\d+$/) {
-      push(@ret,$str);
-    } elsif ($str =~ /^([-+]?\d+)-([-+]?\d+)$/) {
-      ($from,$to)=($1,$2);
-      if ($from>$to) {
-        $tmp=$from;
-        $from=$to;
-        $to=$tmp;
-      }
-      push(@ret,$from..$to);
-    } else {
-      return ();
-    }
-  }
-  @ret;
-}
-
-1;
diff --git a/lib/Digest/HMAC.pm b/lib/Digest/HMAC.pm
deleted file mode 100644
index e2e6b60..0000000
--- a/lib/Digest/HMAC.pm
+++ /dev/null
@@ -1,111 +0,0 @@
-package Digest::HMAC;
-$VERSION = "1.01";
-
-use strict;
-
-# OO interface
-
-sub new
-{
-    my($class, $key, $hasher, $block_size) =  @_;
-    $block_size ||= 64;
-    $key = $hasher->new->add($key)->digest if length($key) > $block_size;
-
-    my $self = bless {}, $class;
-    $self->{k_ipad} = $key ^ (chr(0x36) x $block_size);
-    $self->{k_opad} = $key ^ (chr(0x5c) x $block_size);
-    $self->{hasher} = $hasher->new->add($self->{k_ipad});
-    $self;
-}
-
-sub reset
-{
-    my $self = shift;
-    $self->{hasher}->reset->add($self->{k_ipad});
-    $self;
-}
-
-sub add     { my $self = shift; $self->{hasher}->add(@_);     $self; }
-sub addfile { my $self = shift; $self->{hasher}->addfile(@_); $self; }
-
-sub _digest
-{
-    my $self = shift;
-    my $inner_digest = $self->{hasher}->digest;
-    $self->{hasher}->reset->add($self->{k_opad}, $inner_digest);
-}
-
-sub digest    { shift->_digest->digest;    }
-sub hexdigest { shift->_digest->hexdigest; }
-sub b64digest { shift->_digest->b64digest; }
-
-
-# Functional interface
-
-require Exporter;
-*import = \&Exporter::import;
-use vars qw(@EXPORT_OK);
-@EXPORT_OK = qw(hmac hmac_hex);
-
-sub hmac
-{
-    my($data, $key, $hash_func, $block_size) = @_;
-    $block_size ||= 64;
-    $key = &$hash_func($key) if length($key) > $block_size;
-
-    my $k_ipad = $key ^ (chr(0x36) x $block_size);
-    my $k_opad = $key ^ (chr(0x5c) x $block_size);
-
-    &$hash_func($k_opad, &$hash_func($k_ipad, $data));
-}
-
-sub hmac_hex { unpack("H*", &hmac); }
-
-1;
-
-__END__
-
-=head1 NAME
-
-Digest::HMAC - Keyed-Hashing for Message Authentication
-
-=head1 SYNOPSIS
-
- # Functional style
- use Digest::HMAC qw(hmac hmac_hex);
- $digest = hmac($data, $key, \&myhash);
- print hmac_hex($data, $key, \&myhash);
-
- # OO style
- use Digest::HMAC;
- $hmac = Digest::HMAC->new($key, "Digest::MyHash");
-
- $hmac->add($data);
- $hmac->addfile(*FILE);
-
- $digest = $hmac->digest;
- $digest = $hmac->hexdigest;
- $digest = $hmac->b64digest;
-
-=head1 DESCRIPTION
-
-HMAC is used for message integrity checks between two parties that
-share a secret key, and works in combination with some other Digest
-algorithm, usually MD5 or SHA-1.  The HMAC mechanism is described in
-RFC 2104.
-
-HMAC follow the common C interface, but the constructor
-takes the secret key and the name of some other simple C
-as argument.
-
-=head1 SEE ALSO
-
-L, L
-
-RFC 2104
-
-=head1 AUTHORS
-
-Graham Barr , Gisle Aas 
-
-=cut
diff --git a/lib/Digest/HMAC_MD5.pm b/lib/Digest/HMAC_MD5.pm
deleted file mode 100644
index 6efa0a1..0000000
--- a/lib/Digest/HMAC_MD5.pm
+++ /dev/null
@@ -1,71 +0,0 @@
-package Digest::HMAC_MD5;
-$VERSION="1.01";
-
-use strict;
-use Digest::MD5  qw(md5);
-use Digest::HMAC qw(hmac);
-
-# OO interface
-use vars qw(@ISA);
-@ISA=qw(Digest::HMAC);
-sub new
-{
-    my $class = shift;
-    $class->SUPER::new($_[0], "Digest::MD5", 64);
-}
-
-# Functional interface
-require Exporter;
-*import = \&Exporter::import;
-use vars qw(@EXPORT_OK);
-@EXPORT_OK=qw(hmac_md5 hmac_md5_hex);
-
-sub hmac_md5
-{
-    hmac($_[0], $_[1], \&md5, 64);
-}
-
-sub hmac_md5_hex
-{
-    unpack("H*", &hmac_md5)
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Digest::HMAC_MD5 - Keyed-Hashing for Message Authentication
-
-=head1 SYNOPSIS
-
- # Functional style
- use Digest::HMAC_MD5 qw(hmac_md5 hmac_md5_hex);
- $digest = hmac_md5($data, $key);
- print hmac_md5_hex($data, $key);
-
- # OO style
- use Digest::HMAC_MD5;
- $hmac = Digest::HMAC_MD5->new($key);
-
- $hmac->add($data);
- $hmac->addfile(*FILE);
-
- $digest = $hmac->digest;
- $digest = $hmac->hexdigest;
- $digest = $hmac->b64digest;
-
-=head1 DESCRIPTION
-
-This module provide HMAC-MD5 hashing.
-
-=head1 SEE ALSO
-
-L, L, L
-
-=head1 AUTHOR
-
-Gisle Aas 
-
-=cut
diff --git a/lib/Digest/HMAC_SHA1.pm b/lib/Digest/HMAC_SHA1.pm
deleted file mode 100644
index fadfb40..0000000
--- a/lib/Digest/HMAC_SHA1.pm
+++ /dev/null
@@ -1,71 +0,0 @@
-package Digest::HMAC_SHA1;
-$VERSION="1.01";
-
-use strict;
-use Digest::SHA1 qw(sha1);
-use Digest::HMAC qw(hmac);
-
-# OO interface
-use vars qw(@ISA);
-@ISA=qw(Digest::HMAC);
-sub new
-{
-    my $class = shift;
-    $class->SUPER::new($_[0], "Digest::SHA1", 64);
-}
-
-# Functional interface
-require Exporter;
-*import = \&Exporter::import;
-use vars qw(@EXPORT_OK);
-@EXPORT_OK=qw(hmac_sha1 hmac_sha1_hex);
-
-sub hmac_sha1
-{
-    hmac($_[0], $_[1], \&sha1, 64);
-}
-
-sub hmac_sha1_hex
-{
-    unpack("H*", &hmac_sha1)
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Digest::HMAC_SHA1 - Keyed-Hashing for Message Authentication
-
-=head1 SYNOPSIS
-
- # Functional style
- use Digest::HMAC_SHA1 qw(hmac_sha1 hmac_sha1_hex);
- $digest = hmac_sha1($data, $key);
- print hmac_sha1_hex($data, $key);
-
- # OO style
- use Digest::HMAC_SHA1;
- $hmac = Digest::HMAC_SHA1->new($key);
-
- $hmac->add($data);
- $hmac->addfile(*FILE);
-
- $digest = $hmac->digest;
- $digest = $hmac->hexdigest;
- $digest = $hmac->b64digest;
-
-=head1 DESCRIPTION
-
-This module provide HMAC-SHA-1 hashing.
-
-=head1 SEE ALSO
-
-L, L, L
-
-=head1 AUTHOR
-
-Gisle Aas 
-
-=cut
diff --git a/lib/GD/Graph/Data.pm b/lib/GD/Graph/Data.pm
deleted file mode 100644
index 23f4624..0000000
--- a/lib/GD/Graph/Data.pm
+++ /dev/null
@@ -1,725 +0,0 @@
-#==========================================================================
-#              Copyright (c) 1995-2000 Martien Verbruggen
-#--------------------------------------------------------------------------
-#
-#   Name:
-#       GD::Graph::Data.pm
-#
-# $Id: Data.pm,v 1.21 2003/06/17 03:28:11 mgjv Exp $
-#
-#==========================================================================
-
-package GD::Graph::Data;
-
-($GD::Graph::Data::VERSION) = '$Revision: 1.21 $' =~ /\s([\d.]+)/;
-
-use strict;
-use GD::Graph::Error;
-
-@GD::Graph::Data::ISA = qw( GD::Graph::Error );
-
-=head1 NAME
-
-GD::Graph::Data - Data set encapsulation for GD::Graph
-
-=head1 SYNOPSIS
-
-use GD::Graph::Data;
-
-=head1 DESCRIPTION
-
-This module encapsulates the data structure that is needed for GD::Graph
-and friends. An object of this class contains a list of X values, and a
-number of lists of corresponding Y values. This only really makes sense
-if the Y values are numerical, but you can basically store anything.
-Undefined values have a special meaning to GD::Graph, so they are
-treated with care when stored.
-
-Many of the methods of this module are intended for internal use by
-GD::Graph and the module itself, and will most likely not be useful to
-you. Many won't even I useful to you...
-
-=head1 EXAMPLES
-
-  use GD::Graph::Data;
-  use GD::Graph::bars;
-
-  my $data = GD::Graph::Data->new();
-
-  $data->read(file => '/data/sales.dat', delimiter => ',');
-  $data = $data->copy(wanted => [2, 4, 5]);
-
-  # Add the newer figures from the database
-  use DBI;
-  # do DBI things, like connecting to the database, statement
-  # preparation and execution
-
-  while (@row = $sth->fetchrow_array)
-  {
-      $data->add_point(@row);
-  }
-
-  my $chart = GD::Graph::bars->new();
-  my $gd = $chart->plot($data);
-
-or for quick changes to legacy code
-
-  # Legacy code builds array like this
-  @data = ( [qw(Jan Feb Mar)], [1, 2, 3], [5, 4, 3], [6, 3, 7] );
-
-  # And we quickly need to do some manipulations on that
-  my $data = GD::Graph::Data->new();
-  $data->copy_from(\@data);
-
-  # And now do all the new stuff that's wanted.
-  while (@foo = bar_baz())
-  {
-      $data->add_point(@foo);
-  }
-
-=head1 METHODS
-
-=head2 $data = GD::Graph::Data->new()
-
-Create a new GD::Graph::Data object.
-
-=cut
-
-# Error constants
-use constant ERR_ILL_DATASET    => 'Illegal dataset number';
-use constant ERR_ILL_POINT      => 'Illegal point number';
-use constant ERR_NO_DATASET     => 'No data sets set';
-use constant ERR_ARGS_NO_HASH   => 'Arguments must be given as a hash list';
-
-sub new
-{
-    my $proto = shift;
-    my $class = ref($proto) || $proto;
-    my $self = [];
-    bless $self => $class;
-    $self->copy_from(@_) or return $self->_move_errors if (@_);
-    return $self;
-}
-
-sub DESTROY
-{
-    my $self = shift;
-    $self->clear_errors();
-}
-
-sub _set_value
-{
-    my $self = shift;
-    my ($nd, $np, $val) = @_;
-
-    # Make sure we have empty arrays in between
-    if ($nd > $self->num_sets)
-    {
-        # XXX maybe do this with splice
-        for ($self->num_sets .. $nd - 1)
-        {
-            push @{$self}, [];
-        }
-    }
-    $self->[$nd][$np] = $val;
-
-    return $self;
-}
-
-=head2 $data->set_x($np, $value);
-
-Set the X value of point I<$np> to I<$value>. Points are numbered
-starting with 0. You probably will never need this. Returns undef on
-failure.
-
-=cut
-
-sub set_x
-{
-    my $self = shift;
-    $self->_set_value(0, @_);
-}
-
-=head2 $data->get_x($np)
-
-Get the X value of point I<$np>. See L<"set_x">.
-
-=cut
-
-sub get_x
-{
-    my $self = shift;
-    my $np   = shift;
-    return $self->_set_error(ERR_ILL_POINT)
-        unless defined $np && $np >= 0;
-
-    $self->[0][$np];
-}
-
-=head2 $data->set_y($nd, $np, $value);
-
-Set the Y value of point I<$np> in data set I<$nd> to I<$value>. Points
-are numbered starting with 0, data sets are numbered starting with 1.
-You probably will never need this. Returns undef on failure.
-
-=cut
-
-sub set_y
-{
-    my $self = shift;
-    return $self->_set_error(ERR_ILL_DATASET)
-        unless defined $_[0] && $_[0] >= 1;
-    $self->_set_value(@_);
-}
-
-=head2 $data->get_y($nd, $np)
-
-Get the Y value of point I<$np> in data set I<$nd>. See L<"set_y">. This
-will return undef on an error, but the fact that it returns undef does
-not mean there was an error (since undefined values can be stored, and
-therefore returned).
-
-=cut
-
-sub get_y
-{
-    my $self = shift;
-    my ($nd, $np) = @_;
-    return $self->_set_error(ERR_ILL_DATASET)
-        unless defined $nd && $nd >= 1 && $nd <= $self->num_sets;
-    return $self->_set_error(ERR_ILL_POINT)
-        unless defined $np && $np >= 0;
-
-    $self->[$nd][$np];
-}
-
-=head2 $data->get_y_cumulative($nd, $np)
-
-Get the cumulative value of point I<$np> in data set<$nd>. The
-cumulative value is obtained by adding all the values of the points
-I<$np> in the data sets 1 to I<$nd>.
-
-=cut
-
-sub get_y_cumulative
-{
-    my $self = shift;
-    my ($nd, $np) = @_;
-    return $self->_set_error(ERR_ILL_DATASET)
-        unless defined $nd && $nd >= 1 && $nd <= $self->num_sets;
-    return $self->_set_error(ERR_ILL_POINT)
-        unless defined $np && $np >= 0;
-    
-    my $value;
-    for (my $i = 1; $i <= $nd; $i++)
-    {
-        $value += $self->[$i][$np] || 0;
-    }
-
-    return $value;
-}
-
-sub _get_min_max
-{
-    my $self = shift;
-    my $nd   = shift;
-    my ($min, $max);
-
-    for my $val (@{$self->[$nd]})
-    {
-        next unless defined $val;
-        $min = $val if !defined $min || $val < $min;
-        $max = $val if !defined $max || $val > $max;
-    }
-
-    return $self->_set_error("No (defined) values in " . 
-        ($nd == 0 ? "X list" : "dataset $nd"))
-            unless defined $min && defined $max;
-    
-    return ($min, $max);
-}
-
-=head2 $data->get_min_max_x
-
-Returns a list of the minimum and maximum x value or the
-empty list on failure.
-
-=cut
-
-sub get_min_max_x
-{
-    my $self = shift;
-    $self->_get_min_max(0);
-}
-
-=head2 $data->get_min_max_y($nd)
-
-Returns a list of the minimum and maximum y value in data set $nd or the
-empty list on failure.
-
-=cut
-
-sub get_min_max_y
-{
-    my $self = shift;
-    my $nd   = shift;
-
-    return $self->_set_error(ERR_ILL_DATASET)
-        unless defined $nd && $nd >= 1 && $nd <= $self->num_sets;
-    
-    $self->_get_min_max($nd);
-}
-
-=head2 $data->get_min_max_y_all()
-
-Returns a list of the minimum and maximum y value in all data sets or the
-empty list on failure.
-
-=cut
-
-sub get_min_max_y_all
-{
-    my $self = shift;
-    my ($min, $max);
-
-    for (my $ds = 1; $ds <= $self->num_sets; $ds++)
-    {
-        my ($ds_min, $ds_max) = $self->get_min_max_y($ds);
-        next unless defined $ds_min;
-        $min = $ds_min if !defined $min || $ds_min < $min;
-        $max = $ds_max if !defined $max || $ds_max > $max;
-    }
-
-    return $self->_set_error('No (defined) values in any data set')
-        unless defined $min && defined $max;
-    
-    return ($min, $max);
-}
-
-# Undocumented, not part of interface right now. Might expose at later
-# point in time.
-
-sub set_point
-{
-    my $self = shift;
-    my $np = shift;
-    return $self->_set_error(ERR_ILL_POINT)
-        unless defined $np && $np >= 0;
-
-    for (my $ds = 0; $ds < @_; $ds++)
-    {
-        $self->_set_value($ds, $np, $_[$ds]);
-    }
-    return $self;
-}
-
-=head2 $data->add_point($X, $Y1, $Y2 ...)
-
-Adds a point to the data set. The base for the addition is the current
-number of X values. This means that if you have a data set with the
-contents
-
-  (X1,  X2)
-  (Y11, Y12)
-  (Y21)
-  (Y31, Y32, Y33, Y34)
-
-a $data->add_point(Xx, Y1x, Y2x, Y3x, Y4x) will result in
-
-  (X1,    X2,    Xx )
-  (Y11,   Y12,   Y1x)
-  (Y21,   undef, Y2x)
-  (Y31,   Y32,   Y3x,  Y34)
-  (undef, undef, Y4x)
-
-In other words: beware how you use this. As long as you make sure that
-all data sets are of equal length, this method is safe to use.
-
-=cut
-
-sub add_point
-{
-    my $self = shift;
-    $self->set_point(scalar $self->num_points, @_);
-}
-
-=head2 $data->num_sets()
-
-Returns the number of data sets.
-
-=cut
-
-sub num_sets
-{
-    my $self = shift;
-    @{$self} - 1;
-}
-
-=head2 $data->num_points()
-
-In list context, returns a list with its first element the number of X
-values, and the subsequent elements the number of respective Y values
-for each data set. In scalar context returns the number of points
-that have an X value set, i.e. the number of data sets that would result
-from a call to C.
-
-=cut
-
-sub num_points
-{
-    my $self = shift;
-    return (0) unless @{$self};
-
-    wantarray ?
-        map { scalar @{$_} } @{$self} :
-        scalar @{$self->[0]}
-}
-
-=head2 $data->x_values()
-
-Return a list of all the X values.
-
-=cut
-
-sub x_values
-{
-    my $self = shift;
-    return $self->_set_error(ERR_NO_DATASET)
-        unless @{$self};
-    @{$self->[0]};
-}
-
-=head2 $data->y_values($nd)
-
-Return a list of the Y values for data set I<$nd>. Data sets are
-numbered from 1. Returns the empty list if $nd is out of range, or if
-the data set at $nd is empty.
-
-=cut
-
-sub y_values
-{
-    my $self = shift;
-    my $nd   = shift;
-    return $self->_set_error(ERR_ILL_DATASET)
-        unless defined $nd && $nd >= 1 && $nd <= $self->num_sets;
-    return $self->_set_error(ERR_NO_DATASET)
-        unless @{$self};
-
-    @{$self->[$nd]};
-}
-
-=head2 $data->reset() OR GD::Graph::Data->reset()
-
-As an object method: Reset the data container, get rid of all data and
-error messages. As a class method: get rid of accumulated error messages
-and possible other crud.
-
-=cut
-
-sub reset
-{
-    my $self = shift;
-    @{$self} = () if ref($self);
-    $self->clear_errors();
-    return $self;
-}
-
-=head2 $data->make_strict()
-
-Make all data set lists the same length as the X list by truncating data
-sets that are too long, and filling data sets that are too short with
-undef values. always returns a true value.
-
-=cut
-
-sub make_strict
-{
-    my $self = shift;
-
-    for my $ds (1 .. $self->num_sets)
-    {
-        my $data_set = $self->[$ds];
-
-        my $short = $self->num_points - @{$data_set};
-        next if $short == 0;
-
-        if ($short > 0)
-        {
-            my @fill = (undef) x $short;
-            push @{$data_set}, @fill;
-        }
-        else
-        {
-            splice @{$data_set}, $short;
-        }
-    }
-    return $self;
-}
-
-=head2 $data->cumulate(preserve_undef => boolean)
-
-The B parameter will summarise the Y value sets as follows:
-the first Y value list will be unchanged, the second will contain a
-sum of the first and second, the third will contain the sum of first,
-second and third, and so on.  Returns undef on failure.
-
-if the argument I is set to a true value, then the sum
-of exclusively undefined values will be preserved as an undefined value.
-If it is not present or a false value, undef will be treated as zero.
-Note that this still will leave undefined values in the first data set
-alone.
-
-Note: Any non-numerical defined Y values will be treated as 0, but you
-really shouldn't be using this to store that sort of Y data.
-
-=cut
-
-sub cumulate
-{
-    my $self = shift;
-
-    return $self->_set_error(ERR_ARGS_NO_HASH) if (@_ && @_ % 2);
-    my %args = @_;
-
-    # For all the sets, starting at the last one, ending just 
-    # before the first
-    for (my $ds = $self->num_sets; $ds > 1; $ds--)
-    {
-        # For each point in the set
-        for my $point (0 .. $#{$self->[$ds]})
-        {
-            # Add the value for each point in lower sets to this one
-            for my $i (1 .. $ds - 1)
-            {
-                # If neither are defined, we want to preserve the
-                # undefinedness of this point. If we don't do this, then
-                # the mathematical operation will force undef to be a 0.
-                next if 
-                    $args{preserve_undef} &&
-                    ! defined $self->[$ds][$point] &&
-                    ! defined $self->[$i][$point];
-
-                $self->[$ds][$point] += $self->[$i][$point] || 0;
-            }
-        }
-    }
-    return $self;
-}
-
-=head2 $data->wanted(indexes)
-
-Removes all data sets except the ones in the argument list. It will also
-reorder the data sets in the order given. Returns undef on failure.
-
-To remove all data sets except the first, sixth and second, in that
-order:
-
-  $data->wanted(1, 6, 2) or die $data->error;
-
-=cut
-
-sub wanted
-{
-    my $self = shift;
-
-    for my $wanted (@_)
-    {
-        return $self->_set_error("Wanted index $wanted out of range 1-"
-                    . $self->num_sets)
-            if $wanted < 1 || $wanted > $self->num_sets;
-    }
-    @{$self} = @{$self}[0, @_];
-    return $self;
-}
-
-=head2 $data->reverse
-
-Reverse the order of the data sets.
-
-=cut
-
-sub reverse
-{
-    my $self = shift;
-    @{$self} = ($self->[0], reverse @{$self}[1..$#{$self}]);
-    return $self;
-}
-
-=head2 $data->copy_from($data_ref)
-
-Copy an 'old' style GD::Graph data structure or another GD::Graph::Data
-object into this object. This will remove the current data. Returns undef
-on failure.
-
-=cut
-
-sub copy_from
-{
-    my $self = shift;
-    my $data = shift;
-    return $self->_set_error('Not a valid source data structure')
-        unless defined $data && (
-                ref($data) eq 'ARRAY' || ref($data) eq __PACKAGE__);
-    
-    $self->reset;
-
-    my $i = 0;
-    for my $data_set (@{$data})
-    {
-        return $self->_set_error("Invalid data set: $i")
-            unless ref($data_set) eq 'ARRAY';
-
-        push @{$self}, [@{$data_set}];
-        $i++;
-    }
-
-    return $self;
-}
-
-=head2 $data->copy()
-
-Returns a copy of the object, or undef on failure.
-
-=cut
-
-sub copy
-{
-    my $self = shift;
-
-    my $new = $self->new();
-    $new->copy_from($self);
-    return $new;
-}
-
-=head2 $data->read(I)
-
-Read a data set from a file. This will remove the current data. returns
-undef on failure. This method uses the standard module 
-Text::ParseWords to parse lines. If you don't have this for some odd
-reason, don't use this method, or your program will die.
-
-B: The default data file format is tab separated data
-(which can be changed with the delimiter argument). Comment lines are
-any lines that start with a #. In the following example I have replaced
-literal tabs with  for clarity
-
-  # This is a comment, and will be ignored
-  Jan1224
-  Feb1337
-  # March is missing
-  Mar
-  Apr918
-
-Valid arguments are:
-
-I, mandatory. The file name of the file to read from, or a
-reference to a file handle or glob.
-
-  $data->read(file => '/data/foo.dat') or die $data->error;
-  $data->read(file => \*DATA) or die $data->error;
-  $data->read(file => $file_handle) or die $data->error;
-
-I, optional. Give this a true value if you don't want lines
-with an initial # to be skipped.
-
-  $data->read(file => '/data/foo.dat', no_comment => 1);
-
-I, optional. A regular expression that will become the
-delimiter instead of a single tab.
-
-  $data->read(file => '/data/foo.dat', delimiter => '\s+');
-  $data->read(file => '/data/foo.dat', delimiter => qr/\s+/);
-
-=cut
-
-sub read
-{
-    my $self = shift;
-
-    return $self->_set_error(ERR_ARGS_NO_HASH) if (@_ && @_ % 2);
-    my %args = @_;
-
-    return $self->_set_error('Missing required argument: file') 
-        unless $args{file};
-
-    my $delim = $args{delimiter} || "\t";
-
-    $self->reset();
-
-    # The following will die if these modules are not present, as
-    # documented.
-    require Text::ParseWords;
-
-    my $fh;
-    local *FH;
-
-    if (UNIVERSAL::isa($args{file}, "GLOB"))
-    {
-	$fh = $args{file};
-    }
-    else
-    {
-	# $fh = \do{ local *FH }; # Odd... This dumps core, sometimes in 5.005
-	$fh = \*FH; # XXX Need this for perl 5.005
-	open($fh, $args{file}) or 
-	    return $self->_set_error("open ($args{file}): $!");
-    }
-
-    while (my $line = <$fh>)
-    {
-        chomp $line;
-        next if $line =~ /^#/ && !$args{no_comment};
-        my @fields = Text::ParseWords::parse_line($delim, 1, $line);
-        next unless @fields;
-        $self->add_point(@fields);
-    }
-    return $self;
-}
-
-=head2 $data->error() OR GD::Graph::Data->error()
-
-Returns a list of all the errors that the current object has
-accumulated. In scalar context, returns the last error. If called as a
-class method it works at a class level.
-
-This method is inherited, see L for more information.
-
-=cut
-
-=head2 $data->has_error() OR GD::Graph::Data->has_error()
-
-Returns true if the object (or class) has errors pending, false if not.
-In some cases (see L<"copy">) this is the best way to check for errors.
-
-This method is inherited, see L for more information.
-
-=cut
-
-=head1 NOTES
-
-As with all Modules for Perl: Please stick to using the interface. If
-you try to fiddle too much with knowledge of the internals of this
-module, you could get burned. I may change them at any time.
-Specifically, I probably won't always keep this implemented as an array
-reference.
-
-=head1 AUTHOR
-
-Martien Verbruggen Emgjv@tradingpost.com.auE
-
-=head2 Copyright
-
-(c) Martien Verbruggen.
-
-All rights reserved. This package is free software; you can redistribute
-it and/or modify it under the same terms as Perl itself.
-
-=head1 SEE ALSO
-
-L, L
-
-=cut
-
-"Just another true value";
-
diff --git a/lib/GD/Graph/Error.pm b/lib/GD/Graph/Error.pm
deleted file mode 100644
index 0d8e50c..0000000
--- a/lib/GD/Graph/Error.pm
+++ /dev/null
@@ -1,346 +0,0 @@
-#==========================================================================
-#              Copyright (c) 1995-2000 Martien Verbruggen
-#--------------------------------------------------------------------------
-#
-#   Name:
-#       GD::Graph::Error.pm
-#
-# $Id: Error.pm,v 1.8 2003/02/10 22:12:41 mgjv Exp $
-#
-#==========================================================================
-
-package GD::Graph::Error;
-
-($GD::Graph::Error::VERSION) = '$Revision: 1.8 $' =~ /\s([\d.]+)/;
-
-use strict;
-use Carp;
-
-my %Errors;
-use vars qw( $Debug $ErrorLevel $CriticalLevel );
-
-$Debug = 0;
-
-# Warnings from 0 to 4, Errors from 5 to 9, and Critical 10 and above.
-$ErrorLevel    = 5;
-$CriticalLevel = 10;
-
-=head1 NAME
-
-GD::Graph::Error - Error handling for GD::Graph classes
-
-=head1 SYNOPSIS
-
-use GD::Graph::Error_subclass;
-
-=head1 DESCRIPTION
-
-This class is a parent for all GD::Graph classes, including
-GD::Graph::Data, and offers error and warning handling and some
-debugging control.
-
-Errors are stored in a lexical hash in this package, so the
-implementation of the subclass should be irrelevant. 
-
-=head1 PUBLIC METHODS
-
-These methods can be used by users of any of the subclasses of
-GD::Graph::Error to get at the errors of objects or classes.
-
-=head2 $object->error() OR Class->error()
-
-Returns a list of all the errors that the current object has
-accumulated. In scalar context, returns the last error. If called as a
-class method it works at a class level. This is handy when a constructor
-fails, for example:
-
-  my $data = GD::Graph::Data->new()    
-      or die GD::Graph::Data->error;
-  $data->read(file => '/foo/bar.data') 
-      or die $data->error;
-
-or if you really are only interested in the last error:
-
-  $data->read(file => '/foo/bar.data') 
-      or die scalar $data->error;
-
-This implementation does not clear the error list, so if you don't die
-on errors, you will need to make sure to never ask for anything but the
-last error (put this in scalar context) or to call C now
-and again.
-
-Errors are more verbose about where the errors originated if the
-$GD::Graph::Error::Debug variable is set to a true value, and even more
-verbose if this value is larger than 5.
-
-If $Debug is larger than 3, both of these will always return the
-full list of errors and warnings (although the meaning of C
-and C does not change).
-
-=cut
-
-sub _error
-{
-    my $self = shift;
-    my $min_level = shift || 0;
-    my $max_level = shift || 1 << 31;
-    return unless exists $Errors{$self};
-    my $error = $Errors{$self};
-
-    my @return;
-
-    @return = 
-        map { 
-            ($Debug > 3 ? "[$_->{level}] " : '') .
-            "$_->{msg}" .
-            ($Debug ? " at $_->{whence}[1] line $_->{whence}[2]" : '') .
-            ($Debug > 5 ? " => $_->{caller}[0]($_->{caller}[2])" : '') .
-            "\n"
-        } 
-        grep { $_->{level} >= $min_level && $_->{level} <= $max_level }
-        @$error;
-
-    wantarray && @return > 1 and  
-        $return[-1] =~ s/\n/\n\t/ or
-        $return[-1] =~ s/\n//;
-
-    return wantarray ? @return : $return[-1];
-}
-
-sub error
-{
-    my $self = shift;
-    $Debug > 3 and return $self->_error();
-    $self->_error($ErrorLevel);
-}
-
-sub warning
-{
-    my $self = shift;
-    $Debug > 3 and return $self->_error();
-    $self->_error(0, $ErrorLevel - 1);
-}
-
-=head2 $object->has_error() OR Class->has_error()
-
-=head2 $object->has_warning() OR Class->has_warning()
-
-Returns true if there are pending errors (warnings) for the object
-(or class). To be more precise, it returns a list of errors in list
-context, and the number of errors in scalar context.
-
-This allows you to check for errors and warnings after a large number of
-operations which each might fail:
-
-  $data->read(file => '/foo/bar.data') or die $data->error;
-  while (my @foo = $sth->fetchrow_array)
-  {
-      $data->add_point(@foo);
-  }
-  $data->set_x(12, 'Foo');
-  $data->has_warning and warn $data->warning;
-  $data->has_error   and die  $data->error;
-
-The reason to call this, instead of just calling C or
-C and looking at its return value, is that this method is
-much more efficient and fast.
-
-If you want to count anything as bad, just set $ErrorLevel to 0, after
-which you only need to call C.
-
-=cut
-
-sub has_error
-{
-    my $self = shift;
-    return unless exists $Errors{$self};
-    grep { $_->{level} >= $ErrorLevel } @{$Errors{$self}};
-}
-
-sub has_warning
-{
-    my $self = shift;
-    return unless exists $Errors{$self};
-    grep { $_->{level} < $ErrorLevel } @{$Errors{$self}};
-}
-
-=head2 $object->clear_errors() or Class->clear_errors()
-
-Clears all outstanding errors.
-
-=cut
-
-sub clear_errors
-{
-    my $self = shift;
-    delete $Errors{$self};
-}
-
-=head1 PROTECTED METHODS
-
-These methods are only to be called from within this class and its
-Subclasses.
-
-=head2 $object->_set_error(I) or Class->_set_error(I)
-
-=head2 $object->_set_warning(I) or Class->_set_warning(I)
-
-Subclasses call this to set an error. The argument can be a reference
-to an array, of which the first element should be the error level, and
-the second element the error message. Alternatively, it can just be the
-message, in which case the error level will be assumed to be
-$ErrorLevel.
-
-If the error level is >= $CriticalLevel the program will die, using
-Carp::croak to display the current message, as well as all the other
-error messages pending.
-
-In the current implementation these are almost identical when called
-with a scalar argument, except that the default ewrror level is
-different. When called with an array reference, they are identical in
-function. This may change in the future. They're mainly here for code
-clarity.
-
-=cut
-
-# Private, for construction of error hash. This should probably be an
-# object, but that's too much work right now.
-sub __error_hash
-{
-    my $caller  = shift;
-    my $default = shift;
-    my $msg     = shift;
-
-    my %error = (caller => $caller);
-
-    if (ref($msg) && ref($msg) eq 'ARRAY' && @{$msg} >= 2)
-    {
-        # Array reference
-        $error{level} = $msg->[0];
-        $error{msg}   = $msg->[1];
-    }
-    elsif (ref($_[0]) eq '')
-    {
-        # simple scalar
-        $error{level} = $default;
-        $error{msg}   = $msg;
-    }
-    else
-    {
-        # someting else, which I can't deal with
-        warn "Did you read the documentation for GD::Graph::Error?";
-        return;
-    }
-
-    my $lvl = 1;
-    while (my @c = caller($lvl))
-    {
-        $error{whence} = [@c[0..2]];
-        $lvl++;
-    }
-
-    return \%error;
-}
-
-sub _set_error
-{
-    my $self = shift;
-    return unless @_;
-
-    while (@_)
-    {
-        my $e_h = __error_hash([caller], $ErrorLevel, shift) or return;
-        push @{$Errors{$self}}, $e_h;
-        croak $self->error if $e_h->{level} >= $CriticalLevel;
-    }
-    return;
-}
-
-sub _set_warning
-{
-    my $self = shift;
-    return unless @_;
-
-    while (@_)
-    {
-        my $e_h = __error_hash([caller], $ErrorLevel, shift) or return;
-        push @{$Errors{$self}}, $e_h;
-        croak $self->error if $e_h->{level} >= $CriticalLevel;
-    }
-    return;
-}
-
-=head2 $object->_move_errors
-
-Move errors from an object into the class it belongs to.  This can be
-useful if something nasty happens in the constructor, while
-instantiating one of these objects, and you need to move these errors
-into the class space before returning. (see GD::Graph::Data::new for an
-example)
-
-=cut
-
-sub _move_errors
-{
-    my $self = shift;
-    my $class = ref($self);
-    push @{$Errors{$class}}, @{$Errors{$self}};
-    return;
-}
-
-sub _dump
-{
-    my $self = shift;
-    require Data::Dumper;
-    my $dd = Data::Dumper->new([$self], ['me']);
-    $dd->Dumpxs;
-}
-
-=head1 VARIABLES
-
-=head2 $GD::Graph::Error::Debug
-
-The higher this value, the more verbose error messages will be. At the
-moment, any true value will cause the line number and source file of the
-caller at the top of the stack to be included, a value of more than 2
-will include the error severity, and a value of more than 5 will also
-include the direct caller's (i.e. the spot where the error message was
-generated) line number and package. Default: 0.
-
-=head2 $GD::Graph::Error::ErrorLevel
-
-Errors levels below this value will be counted as warnings, and error
-levels above (and inclusive) up to $CriticalLevel will be counted as
-errors. This is also the default error level for the C<_set_error()>
-method. This value should be 0 or larger, and smaller than
-$CriticalLevel. Default: 5.
-
-=head2 $GD::Graph::Error::CriticalLevel
-
-Any errorlevel of or above this level will immediately cause the program
-to die with the specified message, using Carp::croak. Default: 10.
-
-=head1 NOTES
-
-As with all Modules for Perl: Please stick to using the interface. If
-you try to fiddle too much with knowledge of the internals of this
-module, you could get burned. I may change them at any time.
-
-=head1 AUTHOR
-
-Martien Verbruggen Emgjv@tradingpost.com.auE
-
-=head2 Copyright
-
-(c) Martien Verbruggen.
-
-All rights reserved. This package is free software; you can redistribute
-it and/or modify it under the same terms as Perl itself.
-
-=head1 SEE ALSO
-
-L, L
-
-=cut
-
-"Just another true value";
diff --git a/lib/GD/Graph/FAQ.pod b/lib/GD/Graph/FAQ.pod
deleted file mode 100644
index f6ed237..0000000
--- a/lib/GD/Graph/FAQ.pod
+++ /dev/null
@@ -1,130 +0,0 @@
-=head1 NAME
-
-GD::Graph::FAQ - Frequently asked questions
-
-=head1 DESCRIPTION
-
-=head2 I get errors like "Can't call method METHOD on an undefined value". What gives?
-
-You probably had an error somewhere, most likely in the plot() method,
-and you didn't check for it. See the section on Error Handling in the
-documentation for L to find out how to deal with this sort
-of thing, and how to get more information about what the error was.
-
-=head2 I am drawing a bar chart, and the chart area is a lot smaller than the image. What is going on?
-
-As of version 1.30, GD::Graph automatically corrects the width of the
-plotting area of a chart if it needs to draw bars (i.e. for bars and
-some mixed charts). This is necessary, because rounding errors cause
-irregular gaps between or overlaps of bars if the bar is not an exact
-integer number of pixels wide.  
-
-If you want the old behaviour back, set the correct_with attribute to a
-false value.
-
-
-=head2 I have my data in some format that doesn't look at all like the array that I am supposed to give to GD::Graph's plot method. Do I really need to mess around with array references?
-
-Not necessarily. Check out the GD::Graph::Data class. 
-
-
-=head2 How do I stop those pesky accents appearing around bars or inside area charts?
-
-You can set the C option to a large enough value
-(larger than your chart). Alternatively, you may like it better to set
-the C attribute to be the same as the dclrs one.
-
-I'll probably include an option in a future version that gives better
-control over this.
-
-
-=head2 Where is the ActiveState ppm of GD::Graph?
-
-Ask them. I have asked them, but didn't get an answer. I don't know what
-to do to get it included in their set of ppms, and I really do not have
-the time to keep asking them.
-
-I believe that GD::graph has finally made it into ActiveState's ppm
-archive. However, I am going to leave this question here in case they
-get behind again.
-
-
-=head2 Do you have some example code for me?
-
-The distribution has a large set of examples in it. If you don't have
-the original distribution, please get it from CPAN (http://www.cpan.org/
-or some local mirror). 
-
-
-=head2 Will you support X or Y?
-
-If you send me a patch that (in a decent manner) adds the functionality
-to the latest version, I may very well add it for the next release. If
-you don't send me a patch, but just a question, you will have to be
-patient.
-
-=head2 Why does export_format give me a weird string, instead of just 'png' or 'gif'?
-
-As of version 1.31, export_format in a list context returns all formats
-that GD can export. If you are only interested in the answer 'gif' or
-'png', make sure that you call it in a scalar context.
-
-  $export_format = GD::Graph->export_format;
-  $export_format = $graph->export_format;
-  print "Export format is ", scalar $graph->export_format, "\n";
-  print "Export format is " .  $graph->export_format . "\n";
-  @export_formats = $graph->export_format;
-
-
-=head2 TrueType fonts don't work when I use GD::Graph from a CGI program.
-
-When your programs run as CGI, they typically do not have the same
-environment as when you use them from the command line. The Perl FAQ,
-section 9, has some information on this. It is also not guaranteed that
-your script runs from the directory that it is in. It is probably better
-to include something like:
-
-  use GD::Text;
-  GD::Text->font_path("/path/to/my/font_dir");
-
-See the GD::Text documentation for more information about font paths.
-
-=head2 I'm trying to use GD's builtin fonts, but it's not working.
-
-Most likely, you are using the font short name, like gdGiantFont or
-gdMediumBoldFont, and you have not put a C in your program.
-This is needed, because these short names need to be exported into
-your name space by the GD library:
-
-  use GD;
-  # ...
-  $graph->set_x_axis_font(gdMediumBoldFont);
-
-If you don't want to include the GD library, you can use the
-longer alternative names (which is what I'd recommend anyway):
-
-  $graph1->set_x_axis_font(GD::Font->MediumBold);
-
-If you C then you will actually get an error message if
-you try to use the short names without including the GD module.
-
-Also see the L documentation for this information.
-
-=head2 When I have many data sets, some end up having the same colour.
-
-The default number of colours for data sets is seven, so if you use
-more than seven data sets, those colours will be re-used for the
-higher data sets.
-
-This is described in the entry for the C attribute in the
-L documentation.
-
-=head1 AUTHOR
-
-Martien Verbruggen Emgjv@tradingpost.com.auE
-
-(c) Martien Verbruggen.
-
-All rights reserved. This package is free software; you can redistribute
-it and/or modify it under the same terms as Perl itself.
-
diff --git a/lib/GD/Graph/area.pm b/lib/GD/Graph/area.pm
deleted file mode 100644
index a06f114..0000000
--- a/lib/GD/Graph/area.pm
+++ /dev/null
@@ -1,112 +0,0 @@
-#==========================================================================
-#              Copyright (c) 1995-2000 Martien Verbruggen
-#--------------------------------------------------------------------------
-#
-#   Name:
-#       GD::Graph::area.pm
-#
-# $Id: area.pm,v 1.16 2003/02/10 23:33:40 mgjv Exp $
-#
-#==========================================================================
-
-package GD::Graph::area;
- 
-($GD::Graph::area::VERSION) = '$Revision: 1.16 $' =~ /\s([\d.]+)/;
-
-use strict;
-
-use GD::Graph::axestype;
-
-@GD::Graph::area::ISA = qw( GD::Graph::axestype );
-
-# PRIVATE
-sub draw_data_set
-{
-    my $self = shift;       # object reference
-    my $ds   = shift;       # number of the data set
-
-    my @values = $self->{_data}->y_values($ds) or
-        return $self->_set_error("Impossible illegal data set: $ds",
-            $self->{_data}->error);
-
-    # Select a data colour
-    my $dsci = $self->set_clr($self->pick_data_clr($ds));
-    my $brci = $self->set_clr($self->pick_border_clr($ds));
-
-    # Create a new polygon
-    my $poly = GD::Polygon->new();
-
-    my @bottom;
-
-    # Add the data points
-    for (my $i = 0; $i < @values; $i++)
-    {
-        my $value = $values[$i];
-        next unless defined $value;
-
-        my $bottom = $self->_get_bottom($ds, $i);
-        $value = $self->{_data}->get_y_cumulative($ds, $i)
-            if ($self->{overwrite} == 2);
-
-        my ($x, $y) = $self->val_to_pixel($i + 1, $value, $ds);
-        $poly->addPt($x, $y);
-	# Need to keep track of this stuff for hotspots, and because
-	# it's the only reliable way of closing the polygon, without
-	# making odd assumptions.
-        push @bottom, [$x, $bottom];
-
-        # Hotspot stuff
-        # XXX needs fixing. Not used at the moment.
-	next unless defined $self->{_hotspots}->[$ds]->[$i];
-        if ($i == 0)
-        {
-            $self->{_hotspots}->[$ds]->[$i] = ["poly", 
-                $x, $y,
-                $x , $bottom,
-                $x - 1, $bottom,
-                $x - 1, $y,
-                $x, $y];
-        }
-        else
-        {
-            $self->{_hotspots}->[$ds]->[$i] = ["poly", 
-                $poly->getPt($i),
-                @{$bottom[$i]},
-                @{$bottom[$i-1]},
-                $poly->getPt($i-1),
-                $poly->getPt($i)];
-        }
-    }
-
-    foreach my $bottom (reverse @bottom)
-    {
-        $poly->addPt($bottom->[0], $bottom->[1]);
-    }
-
-    # Draw a filled and a line polygon
-    $self->{graph}->filledPolygon($poly, $dsci)
-        if defined $dsci;
-    $self->{graph}->polygon($poly, $brci)
-        if defined $brci;
-
-    # Draw the accent lines
-    if (defined $brci &&
-       ($self->{right} - $self->{left})/@values > $self->{accent_treshold})
-    {
-        for (my $i = 1; $i < @values - 1; $i++)
-        {
-            my $value = $values[$i];
-	    ## XXX Why don't I need this line?
-            ##next unless defined $value;
-
-            my ($x, $y) = $poly->getPt($i);
-            my $bottom = $bottom[$i]->[1];
-
-            $self->{graph}->dashedLine($x, $y, $x, $bottom, $brci);
-        }
-    }
-
-    return $ds
-}
-
-"Just another true value";
diff --git a/lib/GD/Graph/axestype3d.pm b/lib/GD/Graph/axestype3d.pm
deleted file mode 100644
index 7acb7f3..0000000
--- a/lib/GD/Graph/axestype3d.pm
+++ /dev/null
@@ -1,787 +0,0 @@
-#==========================================================================
-# Module: GD::Graph::axestype3d
-#
-# Copyright (C) 1999,2001 Wadsack-Allen. All Rights Reserved.
-#
-# Based on axestype.pm,v 1.21 2000/04/15 08:59:36 mgjv
-#          Copyright (c) 1995-1998 Martien Verbruggen
-#
-#--------------------------------------------------------------------------
-# Date		Modification				                                 Author
-# -------------------------------------------------------------------------
-# 1999SEP18 Created 3D axestype base class (this                         JW
-#           module) changes noted in comments.
-# 1999OCT15 Fixed to include all GIFgraph functions                      JW
-#           necessary for PNG support.
-# 2000JAN19 Converted to GD::Graph sublcass                              JW
-# 2000FEB21 Fixed bug in y-labels' height                                JW
-# 2000APR18 Updated for compatibility with GD::Graph 1.30                JW
-# 2000AUG21 Added 3d shading                                             JW
-# 2000SEP04 Allowed box_clr without box axis                             JW
-# 06Dec2001 Fixed bug in rendering of x tick when x_tick_number is set   JW
-#==========================================================================
-# TODO
-#		* Modify to use true 3-d extrusions at any theta and phi
-#==========================================================================
-package GD::Graph::axestype3d;
-
-use strict;
- 
-use GD::Graph;
-use GD::Graph::axestype;
-use GD::Graph::utils qw(:all);
-use GD::Graph::colour qw(:colours);
-use Carp;
-
-@GD::Graph::axestype3d::ISA = qw(GD::Graph::axestype);
-$GD::Graph::axestype3d::VERSION = '0.63';
-
-# Commented inheritance from GD::Graph::axestype unless otherwise noted.
-
-use constant PI => 4 * atan2(1,1);
-
-my %Defaults = (
-	depth_3d           => 20,
-	'3d_shading'       => 1,
-
-	# the rest are inherited
-);
-
-# Inherit _has_default 
-
-
-# Can't inherit initialise, because %Defaults is referenced file-
-# specific, not class specific.
-sub initialise
-{
-	my $self = shift;
-
-	my $rc = $self->SUPER::initialise();
-
-	while( my($key, $val) = each %Defaults ) { 
-		$self->{$key} = $val 
-	} # end while
-
-	return $rc;
-} # end initialise
-
-# PUBLIC
-# Inherit plot
-# Inherit set
-# Inherit setup_text
-# Inherit set_x_label_font
-# Inherit set_y_label_font
-# Inherit set_x_axis_font
-# Inherit set_y_axis_font
-# Inherit set_legend
-# Inherit set_legend_font
-
-
-
-# ----------------------------------------------------------
-# Sub: init_graph
-#
-# Args: (None)
-#
-# Description: 
-# Override GD::Graph::init_graph to add 3d shading colors, 
-# if requested
-#
-# [From GD::Graph]
-# Initialise the graph output canvas, setting colours (and 
-# getting back index numbers for them) setting the graph to 
-# transparent, and interlaced, putting a logo (if defined) 
-# on there.
-# ----------------------------------------------------------
-# Date      Modification                              Author
-# ----------------------------------------------------------
-# 20Aug2000 Added to support 3d graph extensions          JW
-# ----------------------------------------------------------
-sub init_graph {
-	my $self = shift;
-
-	# Sets up the canvas and color palette
-	$self->SUPER::init_graph( @_ );	
-
-	# Now create highlights and showdows for each color
-	# in the palette
-	if( $self->{'3d_shading'} ) {
-		$self->{'3d_highlights'} = [];
-		$self->{'3d_shadows'} = [];
-		$self->{'3d_highlights'}[$self->{bgci}] = $self->set_clr( $self->_brighten( _rgb($self->{bgclr}) ) );
-		$self->{'3d_shadows'}[$self->{bgci}]    = $self->set_clr( $self->_darken( _rgb($self->{bgclr}) ) );
-
-		$self->{'3d_highlights'}[$self->{fgci}] = $self->set_clr( $self->_brighten( _rgb($self->{fgclr}) ) );
-		$self->{'3d_shadows'}[$self->{fgci}]    = $self->set_clr( $self->_darken( _rgb($self->{fgclr}) ) );
-
-		$self->{'3d_highlights'}[$self->{tci}] = $self->set_clr( $self->_brighten( _rgb($self->{textclr}) ) );
-		$self->{'3d_shadows'}[$self->{tci}]    = $self->set_clr( $self->_darken( _rgb($self->{textclr}) ) );
-
-		$self->{'3d_highlights'}[$self->{lci}] = $self->set_clr( $self->_brighten( _rgb($self->{labelclr}) ) );
-		$self->{'3d_shadows'}[$self->{lci}]    = $self->set_clr( $self->_darken( _rgb($self->{labelclr}) ) );
-
-		$self->{'3d_highlights'}[$self->{alci}] = $self->set_clr( $self->_brighten( _rgb($self->{axislabelclr}) ) );
-		$self->{'3d_shadows'}[$self->{alci}]    = $self->set_clr( $self->_darken( _rgb($self->{axislabelclr}) ) );
-
-		$self->{'3d_highlights'}[$self->{acci}] = $self->set_clr( $self->_brighten( _rgb($self->{accentclr}) ) );
-		$self->{'3d_shadows'}[$self->{acci}]    = $self->set_clr( $self->_darken( _rgb($self->{accentclr}) ) );
-
-		$self->{'3d_highlights'}[$self->{valuesci}] = $self->set_clr( $self->_brighten( _rgb($self->{valuesclr}) ) );
-		$self->{'3d_shadows'}[$self->{valuesci}]    = $self->set_clr( $self->_darken( _rgb($self->{valuesclr}) ) );
-
-		$self->{'3d_highlights'}[$self->{legendci}] = $self->set_clr( $self->_brighten( _rgb($self->{legendclr}) ) );
-		$self->{'3d_shadows'}[$self->{legendci}]    = $self->set_clr( $self->_darken( _rgb($self->{legendclr}) ) );
-
-		if( $self->{boxclr} ) {
-			$self->{'3d_highlights'}[$self->{boxci}] = $self->set_clr( $self->_brighten( _rgb($self->{boxclr}) ) );
-			$self->{'3d_shadows'}[$self->{boxci}]    = $self->set_clr( $self->_darken( _rgb($self->{boxclr}) ) );
-		} # end if
-	} # end if
-
-	return $self;
-} # end init_graph
-
-
-# PRIVATE
-
-# ----------------------------------------------------------
-# Sub: _brighten
-#
-# Args: $r, $g, $b
-#	$r, $g, $b	The Red, Green, and Blue components of a color
-#
-# Description: Brightens the color by adding white
-# ----------------------------------------------------------
-# Date      Modification                              Author
-# ----------------------------------------------------------
-# 21AUG2000 Created to build 3d highlights table          JW
-# ----------------------------------------------------------
-sub _brighten {
-	my $self = shift;
-	my( $r, $g, $b ) = @_;
-	my $p = ($r + $g + $b) / 70;
-	$p = 3 if $p < 3;
-	my $f = _max( $r / $p, _max( $g / $p, $b / $p ) );
-	$r = _min( 255, int( $r + $f ) );
-	$g = _min( 255, int( $g + $f ) );
-	$b = _min( 255, int( $b + $f ) );
-	return( $r, $g, $b );
-} # end _brighten
-
-# ----------------------------------------------------------
-# Sub: _darken
-#
-# Args: $r, $g, $b
-#	$r, $g, $b	The Red, Green, and Blue components of a color
-#
-# Description: Darkens the color by adding black
-# ----------------------------------------------------------
-# Date      Modification                              Author
-# ----------------------------------------------------------
-# 21AUG2000 Created to build 3d shadows table          JW
-# ----------------------------------------------------------
-sub _darken {
-	my $self = shift;
-	my( $r, $g, $b ) = @_;
-	my $p = ($r + $g + $b) / 70;
-	$p = 3 if $p < 3;
-	my $f = _max( $r / $p, _max( $g / $p, $b / $p) );
-	$r = _max( 0, int( $r - $f ) );
-	$g = _max( 0, int( $g - $f ) );
-	$b = _max( 0, int( $b - $f ) );
-	return( $r, $g, $b );
-} # end _darken
-
-
-# inherit check_data from GD::Graph
-
-# [JAW] Setup boundaries as parent, the adjust for 3d extrusion
-sub _setup_boundaries
-{
-	my $self = shift;
-
-	$self->SUPER::_setup_boundaries();
-
-	# adjust for top of 3-d extrusion
-	$self->{top} += $self->{depth_3d};
-
-	return $self->_set_error('Vertical size too small')
-		if $self->{bottom} <= $self->{top};
-	
-	# adjust for right of 3-d extrusion
-	$self->{right} -= $self->{depth_3d};
-
-	return $self->_set_error('Horizontal size too small')	
-		if $self->{right} <= $self->{left};
-
-	return $self;
-} # end _setup_boundaries
-
-# [JAW] Determine 3d-extrusion depth, then call parent
-sub setup_coords
-{
-	my $self = shift;
-
-	# Calculate the 3d-depth of the graph
-	# Note this sets a minimum depth of ~20 pixels
-#	if (!defined $self->{x_tick_number}) {
-		my $depth = _max( $self->{bar_depth}, $self->{line_depth} );
-		if( $self->{overwrite} == 1 ) {
-			$depth *= $self->{_data}->num_sets();
-		} # end if
-	   $self->{depth_3d} = _max( $depth, $self->{depth_3d} );
-#	} # end if
-
-	$self->SUPER::setup_coords();
-
-	return $self;
-} # end setup_coords
-
-# Inherit create_y_labels
-# Inherit get_x_axis_label_height
-# Inherit create_x_labels
-# inherit open_graph from GD::Graph
-# Inherit draw_text
-
-# [JAW] Draws entire bounding cube for 3-d extrusion
-sub draw_axes
-{
-	my $s = shift;
-	my $g = $s->{graph};
-
-	my ($l, $r, $b, $t) = 
-		( $s->{left}, $s->{right}, $s->{bottom}, $s->{top} );
-	my $depth = $s->{depth_3d};
-
-	if ( $s->{box_axis} ) {
-		# -- Draw a bounding box
-		if( $s->{boxci} ) {
-			# -- Fill the box with color
-			# Back box
-			$g->filledRectangle($l+$depth+1, $t-$depth+1, $r+$depth-1, $b-$depth-1, $s->{boxci});
-
-			# Left side
-			my $poly = new GD::Polygon;
-			$poly->addPt( $l, $t );
-			$poly->addPt( $l + $depth, $t - $depth );
-			$poly->addPt( $l + $depth, $b - $depth );
-			$poly->addPt( $l, $b );
-			if( $s->{'3d_shading'} ) {
-				$g->filledPolygon( $poly, $s->{'3d_shadows'}[$s->{boxci}] );
-			} else {
-				$g->filledPolygon( $poly, $s->{boxci} );
-			} # end if
-
-			# Bottom
-			$poly = new GD::Polygon;
-			$poly->addPt( $l, $b );
-			$poly->addPt( $l + $depth, $b - $depth );
-			$poly->addPt( $r + $depth, $b - $depth );
-			$poly->addPt( $r, $b );
-			if( $s->{'3d_shading'} ) {
-				$g->filledPolygon( $poly, $s->{'3d_highlights'}[$s->{boxci}] );
-			} else {
-				$g->filledPolygon( $poly, $s->{boxci} );
-			} # end if
-		} # end if
-
-		# -- Draw the box frame
-		
-		# Back box
-		$g->rectangle($l+$depth, $t-$depth, $r+$depth, $b-$depth, $s->{fgci});
-		
-		# Connecting frame
-		$g->line($l, $t, $l + $depth, $t - $depth, $s->{fgci});
-		$g->line($r, $t, $r + $depth, $t - $depth, $s->{fgci});
-		$g->line($l, $b, $l + $depth, $b - $depth, $s->{fgci});
-		$g->line($r, $b, $r + $depth, $b - $depth, $s->{fgci});
-
-		# Front box
-		$g->rectangle($l, $t, $r, $b, $s->{fgci});
-
-	} else {
-		if( $s->{boxci} ) {
-			# -- Fill the background box with color
-			# Back box
-			$g->filledRectangle($l+$depth+1, $t-$depth+1, $r+$depth-1, $b-$depth-1, $s->{boxci});
-
-			# Left side
-			my $poly = new GD::Polygon;
-			$poly->addPt( $l, $t );
-			$poly->addPt( $l + $depth, $t - $depth );
-			$poly->addPt( $l + $depth, $b - $depth );
-			$poly->addPt( $l, $b );
-			if( $s->{'3d_shading'} ) {
-				$g->filledPolygon( $poly, $s->{'3d_shadows'}[$s->{boxci}] );
-			} else {
-				$g->filledPolygon( $poly, $s->{boxci} );
-			} # end if
-
-			# Bottom
-			$poly = new GD::Polygon;
-			$poly->addPt( $l, $b );
-			$poly->addPt( $l + $depth, $b - $depth );
-			$poly->addPt( $r + $depth, $b - $depth );
-			$poly->addPt( $r, $b );
-			if( $s->{'3d_shading'} ) {
-				$g->filledPolygon( $poly, $s->{'3d_highlights'}[$s->{boxci}] );
-			} else {
-				$g->filledPolygon( $poly, $s->{boxci} );
-			} # end if
-		} # end if
-		# -- Draw the frame only for back & sides
-		
-		# Back box
-		$g->rectangle($l + $depth, $t - $depth, $r + $depth, $b - $depth, $s->{fgci});
-
-		# Y axis
-		my $poly = new GD::Polygon;
-		$poly->addPt( $l, $t );
-		$poly->addPt( $l, $b );
-		$poly->addPt( $l + $depth, $b - $depth );
-		$poly->addPt( $l + $depth, $t - $depth );
-		$g->polygon( $poly, $s->{fgci} );
-		
-		# X axis
-		if( !$s->{zero_axis_only} ) {
-			$poly = new GD::Polygon;
-			$poly->addPt( $l, $b );
-			$poly->addPt( $r, $b );
-			$poly->addPt( $r + $depth, $b - $depth );
-			$poly->addPt( $l + $depth, $b - $depth );
-			$g->polygon( $poly, $s->{fgci} );
-		} # end if
-		
-		# Second Y axis
-		if( $s->{two_axes} ){
-			$poly = new GD::Polygon;
-			$poly->addPt( $r, $b );
-			$poly->addPt( $r, $t );
-			$poly->addPt( $r + $depth, $t - $depth );
-			$poly->addPt( $r + $depth, $b - $depth );
-			$g->polygon( $poly, $s->{fgci} );
-		} # end if
-	} # end if
-
-	# Zero axis
-	if ($s->{zero_axis} or $s->{zero_axis_only})	{
-		my ($x, $y) = $s->val_to_pixel(0, 0, 1);
-		my $poly = new GD::Polygon;
-		$poly->addPt( $l, $y );
-		$poly->addPt( $r, $y );
-		$poly->addPt( $r + $depth, $y - $depth );
-		$poly->addPt( $l + $depth, $y - $depth);
-		$g->polygon( $poly, $s->{fgci} );
-	} # end if
-	
-} # end draw_axes
-
-# [JAW] Draws ticks and values for y axes in 3d extrusion
-# Modified from MVERB source
-sub draw_y_ticks
-{
-	my $self = shift;
-
-	for my $t (0 .. $self->{y_tick_number}) 
-	{
-		for my $a (1 .. ($self->{two_axes} + 1)) 
-		{
-			my $value = $self->{y_values}[$a][$t];
-			my $label = $self->{y_labels}[$a][$t];
-			
-			my ($x, $y) = $self->val_to_pixel(0, $value, $a);
-			$x = ($a == 1) ? $self->{left} : $self->{right};
-
-			# CONTRIB Jeremy Wadsack
-			# Draw on the back of the extrusion
-			$x += $self->{depth_3d};
-			$y -= $self->{depth_3d};
-
-			if ($self->{y_long_ticks}) 
-			{
-				$self->{graph}->line( 
-					$x, $y, 
-					$x + $self->{right} - $self->{left}, $y, 
-					$self->{fgci} 
-				) unless ($a-1);
-				# CONTRIB Jeremy Wadsack
-				# Draw conector ticks
-				$self->{graph}->line( $x - $self->{depth_3d}, 
-				                      $y + $self->{depth_3d},
-				                      $x, 
-				                      $y, 
-				                      $self->{fgci} 
-				) unless ($a-1);
-			} 
-			else 
-			{
-				$self->{graph}->line( 
-					$x, $y, 
-					$x + (3 - 2 * $a) * $self->{y_tick_length}, $y, 
-					$self->{fgci} 
-				);
-				# CONTRIB Jeremy Wadsack
-				# Draw conector ticks
-				$self->{graph}->line( $x - $self->{depth_3d}, 
-				                      $y + $self->{depth_3d},
-				                      $x - $self->{depth_3d} + (3 - 2 * $a) * $self->{y_tick_length}, 
-				                      $y + $self->{depth_3d} - (3 - 2 * $a) * $self->{y_tick_length},
-				                      $self->{fgci} 
-				);
-			}
-
-			next 
-				if $t % ($self->{y_label_skip}) || ! $self->{y_plot_values};
-
-			$self->{gdta_y_axis}->set_text($label);
-			$self->{gdta_y_axis}->set_align('center', 
-				$a == 1 ? 'right' : 'left');
-			$x -= (3 - 2 * $a) * $self->{axis_space};
-			
-			# CONTRIB Jeremy Wadsack
-			# Subtract 3-d extrusion width from left axis label
-			# (it was added for ticks)
-			$x -= (2 - $a) * $self->{depth_3d};
-
-			# CONTRIB Jeremy Wadsack
-			# Add 3-d extrusion height to label
-			# (it was subtracted for ticks)
-			$y += $self->{depth_3d};
-
-			$self->{gdta_y_axis}->draw($x, $y);
-			
-		} # end foreach
-	} # end foreach
-
-	return $self;
-
-} # end draw_y_ticks
-
-# [JAW] Darws ticks and values for x axes wih 3d extrusion
-# Modified from MVERB source
-sub draw_x_ticks
-{
-	my $self = shift;
-
-	for (my $i = 0; $i < $self->{_data}->num_points; $i++) 
-	{
-		my ($x, $y) = $self->val_to_pixel($i + 1, 0, 1);
-
-		$y = $self->{bottom} unless $self->{zero_axis_only};
-
-		# CONTRIB  Damon Brodie for x_tick_offset
-		next if (!$self->{x_all_ticks} and 
-				($i - $self->{x_tick_offset}) % $self->{x_label_skip} and 
-				$i != $self->{_data}->num_points - 1 
-			);
-
-		# CONTRIB Jeremy Wadsack
-		# Draw on the back of the extrusion
-		$x += $self->{depth_3d};
-		$y -= $self->{depth_3d};
-
-		if ($self->{x_ticks})
-		{
-			if ($self->{x_long_ticks})
-			{
-				# CONTRIB Jeremy Wadsack
-				# Move up by 3d depth
-				$self->{graph}->line( $x, 
-				                      $self->{bottom} - $self->{depth_3d}, 
-				                      $x, 
-				                      $self->{top} - $self->{depth_3d},
-				                      $self->{fgci});
-				# CONTRIB Jeremy Wadsack
-				# Draw conector ticks
-				$self->{graph}->line( $x - $self->{depth_3d}, 
-				                      $y + $self->{depth_3d},
-				                      $x, 
-				                      $y, 
-				                      $self->{fgci} 
-				);
-			}
-			else
-			{
-				$self->{graph}->line( $x, $y, $x, $y - $self->{x_tick_length}, $self->{fgci} );
-				# CONTRIB Jeremy Wadsack
-				# Draw conector ticks
-				$self->{graph}->line( $x - $self->{depth_3d}, 
-				                      $y + $self->{depth_3d},
-				                      $x - $self->{depth_3d} + $self->{x_tick_length}, 
-				                      $y + $self->{depth_3d} - $self->{x_tick_length},
-				                      $self->{fgci} 
-				);
-			}
-		}
-
-		# CONTRIB Damon Brodie for x_tick_offset
-		next if 
-			($i - $self->{x_tick_offset}) % ($self->{x_label_skip}) and 
-			$i != $self->{_data}->num_points - 1;
-
-		$self->{gdta_x_axis}->set_text($self->{_data}->get_x($i));
-
-		# CONTRIB Jeremy Wadsack
-		# Subtract 3-d extrusion width from left label
-		# Add 3-d extrusion height to left label
-		# (they were changed for ticks)
-		$x -= $self->{depth_3d};
-		$y += $self->{depth_3d};
-
-		my $yt = $y + $self->{axis_space};
-
-		if ($self->{x_labels_vertical})
-		{
-			$self->{gdta_x_axis}->set_align('center', 'right');
-			$self->{gdta_x_axis}->draw($x, $yt, PI/2);
-		}
-		else
-		{
-			$self->{gdta_x_axis}->set_align('top', 'center');
-			$self->{gdta_x_axis}->draw($x, $yt);
-		}
-		
-	} # end for
-
-	return $self;
-
-} # end draw_x_ticks
-
-
-# CONTRIB Scott Prahl
-# Assume x array contains equally spaced x-values
-# and generate an appropriate axis
-#
-####
-# 'True' numerical X axis addition 
-# From: Gary Deschaines
-#
-# These modification to draw_x_ticks_number pass x-tick values to the
-# val_to_pixel subroutine instead of x-tick indices when ture[sic] numerical
-# x-axis mode is detected.  Also, x_tick_offset and x_label_skip are
-# processed differently when true numerical x-axis mode is detected to
-# allow labeled major x-tick marks and un-labeled minor x-tick marks.
-#
-# For example:
-#
-#      x_tick_number =>  14,
-#      x_ticks       =>   1,
-#      x_long_ticks  =>   1,
-#      x_tick_length =>  -4,
-#      x_min_value   => 100,
-#      x_max_value   => 800,
-#      x_tick_offset =>   2,
-#      x_label_skip  =>   2,
-#
-#
-#      ~         ~    ~    ~    ~    ~    ~    ~    ~    ~    ~    ~         ~
-#      |         |    |    |    |    |    |    |    |    |    |    |         |
-#   1 -|         |    |    |    |    |    |    |    |    |    |    |         |
-#      |         |    |    |    |    |    |    |    |    |    |    |         |
-#   0 _|_________|____|____|____|____|____|____|____|____|____|____|_________|
-#                |    |    |    |    |    |    |    |    |    |    |
-#               200       300       400       500       600       700
-####
-# [JAW] Added commented items for 3d rendering
-# Based on MVERB source
-sub draw_x_ticks_number
-{
-	my $self = shift;
-
-	for my $i (0 .. $self->{x_tick_number})
-	{
-		my ($value, $x, $y);
-
- 		if (defined($self->{x_min_value}) && defined($self->{x_max_value}))
- 		{
-			next if ($i - $self->{x_tick_offset}) < 0;
- 			next if ($i + $self->{x_tick_offset}) > $self->{x_tick_number};
- 			$value = $self->{x_values}[$i];
- 			($x, $y) = $self->val_to_pixel($value, 0, 1);
- 		}
- 		else
- 		{
-			$value = ($self->{_data}->num_points - 1)
-						* ($self->{x_values}[$i] - $self->{true_x_min})
-						/ ($self->{true_x_max} - $self->{true_x_min});
- 			($x, $y) = $self->val_to_pixel($value + 1, 0, 1);
- 		}
-
-		$y = $self->{bottom} unless $self->{zero_axis_only};
-
-		# Draw on the back of the extrusion
-		$x += $self->{depth_3d};
-		$y -= $self->{depth_3d};
-
-		if ($self->{x_ticks})
-		{
-			if ($self->{x_long_ticks})
-			{
-				# XXX This mod needs to be done everywhere ticks are
-				# drawn
-				if ( $self->{x_tick_length} >= 0 ) 
-				{
-					# Move up by 3d depth
-					$self->{graph}->line( $x,
-					                      $self->{bottom} - $self->{depth_3d}, 
-												 $x, 
-												 $self->{top} - $self->{depth_3d}, 
-												 $self->{fgci});
-				} 
-				else 
-				{
-					$self->{graph}->line(
-						$x, $self->{bottom} - $self->{x_tick_length}, 
-						$x, $self->{top}, $self->{fgci});
-				}
-				# CONTRIB Jeremy Wadsack
-				# Draw conector ticks
-				$self->{graph}->line( $x - $self->{depth_3d}, 
-				                      $y + $self->{depth_3d},
-				                      $x, 
-				                      $y, 
-				                      $self->{fgci} 
-				);
-			}
-			else
-			{
-				$self->{graph}->line($x, $y, 
-					$x, $y - $self->{x_tick_length}, $self->{fgci} );
-				# CONTRIB Jeremy Wadsack
-				# Draw conector ticks
-				$self->{graph}->line( $x - $self->{depth_3d}, 
-				                      $y + $self->{depth_3d},
-				                      $x, - $self->{depth_3d} + $self->{tick_length}, 
-				                      $y, + $self->{depth_3d} - $self->{tick_length},
-				                      $self->{fgci} 
-				);
-			} # end if -- x_long_ticks
-		} # end if -- x_ticks
-
-		# If we have to skip labels, we'll do it here.
-		# Make sure to always draw the last one.
-		next if $i % $self->{x_label_skip} && $i != $self->{x_tick_number};
-
-		$self->{gdta_x_axis}->set_text($self->{x_labels}[$i]);
-
-		# CONTRIB Jeremy Wadsack
-		# Subtract 3-d extrusion width from left label
-		# Add 3-d extrusion height to left label
-		# (they were changed for ticks)
-		$x -= $self->{depth_3d};
-		$y += $self->{depth_3d};
-
-		if ($self->{x_labels_vertical})
-		{
-			$self->{gdta_x_axis}->set_align('center', 'right');
-			my $yt = $y + $self->{text_space}/2;
-			$self->{gdta_x_axis}->draw($x, $yt, PI/2);
-		}
-		else
-		{
-			$self->{gdta_x_axis}->set_align('top', 'center');
-			my $yt = $y + $self->{text_space}/2;
-			$self->{gdta_x_axis}->draw($x, $yt);
-		} # end if
-	} # end for
-
-	return $self;
-	
-} # end draw_x_tick_number
-
-# Inherit draw_ticks
-# Inherit draw_data
-# Inherit draw_data_set
-# Inherit set_max_min
-# Inherit get_max_y
-# Inherit get_min_y
-# Inherit get_max_min_y_all
-# Inherit _get_bottom
-# Inherit val_to_pixel
-# Inherit setup_legend
-
-
-# [JW] Override draw_legend and reverse the drawing order
-# if cumulate is enabled so legend matches data on chart
-sub draw_legend
-{
-	my $self = shift;
-
-	return unless defined $self->{legend};
-
-	my $xl = $self->{lg_xs} + $self->{legend_spacing};
-	my $y  = $self->{lg_ys} + $self->{legend_spacing} - 1;
-
-	# If there's a frame, offset by the size and margin
-	$xl += $self->{legend_frame_margin} + $self->{legend_frame_size} if $self->{legend_frame_size};
-	$y += $self->{legend_frame_margin} + $self->{legend_frame_size} if $self->{legend_frame_size};
-
-	my $i = 0;
-	my $row = 1;
-	my $x = $xl;	# start position of current element
-	my @legends = @{$self->{legend}};
-	my $i_step = 1;
-	
-	# If we are working in cumulate mode, then reverse the drawing order
-	if( $self->{cumulate} ) {
-		@legends = reverse @legends;
-		$i = scalar(@legends);
-		$i = $self->{_data}->num_sets if $self->{_data}->num_sets < $i;
-		$i++;
-		$i_step = -1;
-	} # end if
-	
-	foreach my $legend (@legends)
-	{
-		$i += $i_step;
-
-		# Legend for Pie goes over first set, and all points
-		# Works in either direction
-		last if $i > $self->{_data}->num_sets;
-		last if $i < 1;
-
-		my $xe = $x;	# position within an element
-
-		next unless defined($legend) && $legend ne "";
-
-		$self->draw_legend_marker($i, $xe, $y);
-
-		$xe += $self->{legend_marker_width} + $self->{legend_spacing};
-		my $ys = int($y + $self->{lg_el_height}/2 - $self->{lgfh}/2);
-
-		$self->{gdta_legend}->set_text($legend);
-		$self->{gdta_legend}->draw($xe, $ys);
-
-		$x += $self->{lg_el_width};
-
-		if (++$row > $self->{lg_cols})
-		{
-			$row = 1;
-			$y += $self->{lg_el_height};
-			$x = $xl;
-		}
-	}
-	
-	# If there's a frame, draw it now
-	if( $self->{legend_frame_size} ) {
-		$x = $self->{lg_xs} + $self->{legend_spacing};
-		$y = $self->{lg_ys} + $self->{legend_spacing} - 1;
-		
-		for $i ( 0 .. $self->{legend_frame_size} - 1 ) {
-			$self->{graph}->rectangle(
-				$x + $i,
-				$y + $i, 
-				$x + $self->{lg_x_size} + 2 * $self->{legend_frame_margin} - $i - 1,
-				$y + $self->{lg_y_size} + 2 * $self->{legend_frame_margin} - $i - 1,
-				$self->{acci},
-			);
-		} # end for
-	} # end if
-	
-}
-
-
-
-# Inherit draw_legend_marker
-
-1;
diff --git a/lib/GD/Graph/bars.pm b/lib/GD/Graph/bars.pm
deleted file mode 100644
index 2650351..0000000
--- a/lib/GD/Graph/bars.pm
+++ /dev/null
@@ -1,372 +0,0 @@
-#==========================================================================
-#              Copyright (c) 1995-1998 Martien Verbruggen
-#--------------------------------------------------------------------------
-#
-#   Name:
-#       GD::Graph::bars.pm
-#
-# $Id: bars.pm,v 1.25 2003/06/11 00:43:49 mgjv Exp $
-#
-#==========================================================================
- 
-package GD::Graph::bars;
-
-($GD::Graph::bars::VERSION) = '$Revision: 1.25 $' =~ /\s([\d.]+)/;
-
-use strict;
-
-use GD::Graph::axestype;
-use GD::Graph::utils qw(:all);
-use GD::Graph::colour qw(:colours);
-
-@GD::Graph::bars::ISA = qw(GD::Graph::axestype);
-
-use constant PI => 4 * atan2(1,1);
-
-sub initialise
-{
-    my $self = shift;
-    $self->SUPER::initialise();
-    $self->set(correct_width => 1);
-}
-
-sub draw_data
-{
-    my $self = shift;
-
-    $self->SUPER::draw_data() or return;
-
-    unless ($self->{no_axes})
-    {
-        # redraw the 'zero' axis
-        if ($self->{rotate_chart})
-        {
-            $self->{graph}->line( 
-                $self->{zeropoint}, $self->{top},
-                $self->{zeropoint}, $self->{bottom},
-                $self->{fgci} );
-        }
-        else
-        {
-            $self->{graph}->line( 
-                $self->{left}, $self->{zeropoint}, 
-                $self->{right}, $self->{zeropoint}, 
-                $self->{fgci} );
-        }
-    }
-    
-    return $self;
-}
-
-sub _top_values
-{
-    my $self = shift;
-    my @topvalues;
-
-    if ($self->{cumulate})
-    {
-	my $data = $self->{_data};
-	for my $i (0 .. $data->num_points - 1)
-	{
-	    push @topvalues, $data->get_y_cumulative($data->num_sets, $i);
-	}
-    }
-
-    return \@topvalues;
-}
-
-#
-# Draw the shadow
-#
-sub _draw_shadow
-{
-    my $self = shift;
-    my ($ds, $i, $value, $topvalues, $l, $t, $r, $b) = @_;
-    my $bsd = $self->{shadow_depth} or return;
-    my $bsci = $self->set_clr(_rgb($self->{shadowclr}));
-
-    if ($self->{cumulate})
-    {
-	return if $ds > 1;
-	$value = $topvalues->[$i];
-	if ($self->{rotate_chart})
-	{
-	    $r = ($self->val_to_pixel($i + 1, $value, $ds))[0];
-	}
-	else
-	{
-	    $t = ($self->val_to_pixel($i + 1, $value, $ds))[1];
-	}
-    }
-
-    # XXX Clean this up
-    if ($value >= 0)
-    {
-	if ($self->{rotate_chart})
-	{
-	    $self->{graph}->filledRectangle(
-		$l, $t + $bsd, $r - $bsd, $b + $bsd, $bsci);
-	}
-	else
-	{
-            $self->{graph}->filledRectangle(
-                $l + $bsd, $t + $bsd, $r + $bsd, $b, $bsci);
-	}
-    }
-    else
-    {
-	if ($self->{rotate_chart})
-	{
-	    $self->{graph}->filledRectangle(
-		$l + $bsd, $t, $r + $bsd, $b, $bsci);
-	}
-	else
-	{
-            $self->{graph}->filledRectangle(
-                $l + $bsd, $b, $r + $bsd, $t + $bsd, $bsci);
-	}
-    }
-}
-
-sub draw_data_set_h
-{
-    my $self = shift;
-    my $ds = shift;
-
-    my $bar_s = $self->{bar_spacing}/2;
-
-    # Pick a data colour
-    my $dsci = $self->set_clr($self->pick_data_clr($ds));
-    # contrib "Bremford, Mike" 
-    my $brci = $self->set_clr($self->pick_border_clr($ds));
-
-    my @values = $self->{_data}->y_values($ds) or
-        return $self->_set_error("Impossible illegal data set: $ds",
-            $self->{_data}->error);
-
-    my $topvalues = $self->_top_values;
-
-    for my $i (0 .. $#values) 
-    {
-        my $value = $values[$i];
-        next unless defined $value;
-
-        my $l = $self->_get_bottom($ds, $i);
-        $value = $self->{_data}->get_y_cumulative($ds, $i)
-            if ($self->{cumulate});
-
-        # CONTRIB Jeremy Wadsack
-        #
-        # cycle_clrs option sets the color based on the point, 
-        # not the dataset.
-        $dsci = $self->set_clr($self->pick_data_clr($i + 1))
-            if $self->{cycle_clrs};
-        $brci = $self->set_clr($self->pick_data_clr($i + 1))
-            if $self->{cycle_clrs} > 1;
-
-        # get coordinates of right and center of bar
-        my ($r, $xp) = $self->val_to_pixel($i + 1, $value, $ds);
-
-        # calculate top and bottom of bar
-        my ($t, $b);
-
-        if (ref $self eq 'GD::Graph::mixed' || $self->{overwrite})
-        {
-            $t = $xp - $self->{x_step}/2 + $bar_s + 1;
-            $b = $xp + $self->{x_step}/2 - $bar_s;
-        }
-        else
-        {
-            $t = $xp 
-                - $self->{x_step}/2
-                + ($ds - 1) * $self->{x_step}/$self->{_data}->num_sets
-                + $bar_s + 1;
-            $b = $xp 
-                - $self->{x_step}/2
-                + $ds * $self->{x_step}/$self->{_data}->num_sets
-                - $bar_s;
-        }
-
-        # draw the bar
-	$self->_draw_shadow($ds, $i, $value, $topvalues, $l, $t, $r, $b);
-        if ($value >= 0)
-        {
-            # positive value
-            $self->{graph}->filledRectangle($l, $t, $r, $b, $dsci)
-                if defined $dsci;
-            $self->{graph}->rectangle($l, $t, $r, $b, $brci) 
-                if defined $brci && $b - $t > $self->{accent_treshold};
-
-            $self->{_hotspots}->[$ds]->[$i] = ['rect', $t, $l, $r, $b]
-        }
-        else
-        {
-            # negative value
-            $self->{graph}->filledRectangle($r, $t, $l, $b, $dsci)
-                if defined $dsci;
-            $self->{graph}->rectangle($l, $t, $r, $b, $brci) 
-                if defined $brci && $b - $t > $self->{accent_treshold};
-
-            $self->{_hotspots}->[$ds]->[$i] = ['rect', $t, $l, $b, $r]
-        }
-    }
-
-    return $ds;
-}
-
-sub draw_data_set_v
-{
-    my $self = shift;
-    my $ds = shift;
-
-    my $bar_s = $self->{bar_spacing}/2;
-
-    # Pick a data colour
-    my $dsci = $self->set_clr($self->pick_data_clr($ds));
-    # contrib "Bremford, Mike" 
-    my $brci = $self->set_clr($self->pick_border_clr($ds));
-
-    my @values = $self->{_data}->y_values($ds) or
-        return $self->_set_error("Impossible illegal data set: $ds",
-            $self->{_data}->error);
-
-    my $topvalues = $self->_top_values;
-
-    for (my $i = 0; $i < @values; $i++) 
-    {
-        my $value = $values[$i];
-        next unless defined $value;
-
-        my $bottom = $self->_get_bottom($ds, $i);
-        $value = $self->{_data}->get_y_cumulative($ds, $i)
-            if ($self->{cumulate});
-
-        # CONTRIB Jeremy Wadsack
-        #
-        # cycle_clrs option sets the color based on the point, 
-        # not the dataset.
-        $dsci = $self->set_clr($self->pick_data_clr($i + 1))
-            if $self->{cycle_clrs};
-        $brci = $self->set_clr($self->pick_data_clr($i + 1))
-            if $self->{cycle_clrs} > 1;
-
-        # get coordinates of top and center of bar
-        my ($xp, $t) = $self->val_to_pixel($i + 1, $value, $ds);
-
-        # calculate left and right of bar
-        my ($l, $r);
-
-        if (ref $self eq 'GD::Graph::mixed' || $self->{overwrite})
-        {
-            $l = $xp - $self->{x_step}/2 + $bar_s + 1;
-            $r = $xp + $self->{x_step}/2 - $bar_s;
-        }
-        else
-        {
-            $l = $xp 
-                - $self->{x_step}/2
-                + ($ds - 1) * $self->{x_step}/$self->{_data}->num_sets
-                + $bar_s + 1;
-            $r = $xp 
-                - $self->{x_step}/2
-                + $ds * $self->{x_step}/$self->{_data}->num_sets
-                - $bar_s;
-        }
-
-        # draw the bar
-	$self->_draw_shadow($ds, $i, $value, $topvalues, $l, $t, $r, $bottom);
-        if ($value >= 0)
-        {
-            # positive value
-            $self->{graph}->filledRectangle($l, $t, $r, $bottom, $dsci)
-                if defined $dsci;
-            $self->{graph}->rectangle($l, $t, $r, $bottom, $brci) 
-                if defined $brci && $r - $l > $self->{accent_treshold};
-
-            $self->{_hotspots}->[$ds]->[$i] = ['rect', $l, $t, $r, $bottom]
-        }
-        else
-        {
-            # negative value
-            $self->{graph}->filledRectangle($l, $bottom, $r, $t, $dsci)
-                if defined $dsci;
-            $self->{graph}->rectangle($l, $bottom, $r, $t, $brci) 
-                if defined $brci && $r - $l > $self->{accent_treshold};
-
-            $self->{_hotspots}->[$ds]->[$i] = ['rect', $l, $bottom, $r, $t]
-        }
-    }
-
-    return $ds;
-}
-
-sub draw_data_set
-{
-    $_[0]->{rotate_chart} ? goto &draw_data_set_h : goto &draw_data_set_v;
-}
-
-sub draw_values
-{
-    my $self = shift;
-
-    return $self unless $self->{show_values};
-    
-    my $text_angle = $self->{values_vertical} ? PI/2 : 0;
-
-    for (my $dsn = 1; $dsn <= $self->{_data}->num_sets; $dsn++)
-    {
-        my @values = $self->{_data}->y_values($dsn) or
-            return $self->_set_error("Impossible illegal data set: $dsn",
-                $self->{_data}->error);
-        my @display = $self->{show_values}->y_values($dsn) or next;
-
-        for (my $i = 0; $i < @values; $i++)
-        {
-            next unless defined $display[$i];
-
-            my $value = $display[$i];
-            if (defined $self->{values_format})
-            {
-                $value = ref $self->{values_format} eq 'CODE' ?
-                    &{$self->{values_format}}($value) :
-                    sprintf($self->{values_format}, $value);
-            }
-
-            my ($xp, $yp);
-            if (defined($self->{x_min_value}) && defined($self->{x_max_value}))
-            {
-                ($xp, $yp) = $self->val_to_pixel(
-                    $self->{_data}->get_x($i), $values[$i], $dsn);
-            }
-            else    
-            {
-                ($xp, $yp) = $self->val_to_pixel($i+1, $values[$i], $dsn);
-            }
-	    if ($self->{rotate_chart})
-	    {
-		$xp += $self->{values_space};
-		unless ($self->{overwrite})
-		{
-		    $yp -= $self->{x_step}/2 - ($dsn - 0.5) 
-			* $self->{x_step}/$self->{_data}->num_sets;
-		}
-	    }
-	    else
-	    {
-		$yp -= $self->{values_space};
-		unless ($self->{overwrite})
-		{
-		    $xp -= $self->{x_step}/2 - ($dsn - 0.5) 
-			* $self->{x_step}/$self->{_data}->num_sets;
-		}
-	    }
-
-            $self->{gdta_values}->set_text($value);
-            $self->{gdta_values}->draw($xp, $yp, $text_angle);
-        }
-    }
-
-    return $self
-}
-
-"Just another true value";
diff --git a/lib/GD/Graph/bars3d.pm b/lib/GD/Graph/bars3d.pm
deleted file mode 100644
index 5344976..0000000
--- a/lib/GD/Graph/bars3d.pm
+++ /dev/null
@@ -1,349 +0,0 @@
-#==========================================================================
-# Module: GD::Graph::bars3d
-#
-# Copyright (C) 1999,2001 Wadsack-Allen. All Rights Reserved.
-#
-# Based on GD::Graph::bars.pm,v 1.16 2000/03/18 10:58:39 mgjv
-#          Copyright (c) 1995-1998 Martien Verbruggen
-#
-#--------------------------------------------------------------------------
-# Date      Modification                                             Author
-# -------------------------------------------------------------------------
-# 1999SEP18 Created 3D bar chart class (this module)                    JAW
-# 1999SEP19 Rewrote to include a single bar-drawing                     JAW
-#           function and process all bars in series
-# 1999SEP19 Implemented support for overwrite 2 style                   JAW
-# 1999SEP19 Fixed a bug in color cycler (colors were off by 1)          JAW
-# 2000JAN19 Converted to GD::Graph class                                JAW
-# 2000MAR10 Fixed bug where bars ran off bottom of chart                JAW
-# 2000APR18 Modified to be compatible with GD::Graph 1.30               JAW
-# 2000APR24 Fixed a lot of rendering bugs and added shading             JAW
-# 2000AUG21 Added 3d shading                                            JAW
-# 2000AUG24 Fixed shading on cycle_clrs option                          JAW
-# 06Dec2002 Fixed on-bar rendering with bars.pm draw_values              JW
-#==========================================================================
-package GD::Graph::bars3d;
-
-use strict;
-
-use GD::Graph::axestype3d;
-use GD::Graph::bars;
-use GD::Graph::utils qw(:all);
-use GD::Graph::colour qw(:colours);
-
-@GD::Graph::bars3d::ISA = qw(GD::Graph::axestype3d);
-$GD::Graph::bars3d::VERSION = '0.63';
-
-use constant PI => 4 * atan2(1,1);
-
-
-my %Defaults = (
-	# Spacing between the bars
-	bar_spacing 	=> 0,
-	
-	# The 3-d extrusion depth of the bars
-	bar_depth => 10,
-);
-
-sub initialise
-{
-	my $self = shift;
-
-	my $rc = $self->SUPER::initialise();
-	$self->set(correct_width => 1);
-
-	while( my($key, $val) = each %Defaults ) { 
-		$self->{$key} = $val 
-	} # end while
-
-	return $rc;
-} # end initialise
-
-sub set
-{
-	my $s = shift;
-	my %args = @_;
-
-	$s->{_set_error} = 0;
-
-	for (keys %args) 
-	{ 
-		/^bar_depth$/ and do 
-		{
-			$s->{bar_depth} = $args{$_};
-			delete $args{$_};
-			next;
-		};
-	}
-
-	return $s->SUPER::set(%args);
-}
-
-
-# CONTRIB Jeremy Wadsack
-# This is a complete overhaul of the original GD::Graph::bars
-# design, because all versions (overwrite = 0, 1, 2) 
-# require that the bars be drawn in a loop of point over sets
-sub draw_data
-{
-	my $self = shift;
-	my $g = $self->{graph};
-
-	my $bar_s = _round($self->{bar_spacing}/2);
-
-	my $zero = $self->{zeropoint};
-
-	my $i;
-   my @iterate =  (0 .. $self->{_data}->num_points());
-   for $i ($self->{rotate_chart} ? reverse(@iterate) : @iterate) {
-		my ($xp, $t);
-		my $overwrite = 0;
-		$overwrite = $self->{overwrite} if defined $self->{overwrite};
-		
-		my $j;
-      my @iterate = (1 .. $self->{_data}->num_sets());
-      for $j (($self->{rotate_chart} && $self->{cumulate} == 0) ? reverse(@iterate) : @iterate) {
-			my $value = $self->{_data}->get_y( $j, $i );
-			next unless defined $value;
-
-			my $bottom = $self->_get_bottom($j, $i);
-         $value = $self->{_data}->get_y_cumulative($j, $i)
-				if ($self->{cumulate});
-
-			# Pick a data colour, calc shading colors too, if requested
-			# cycle_clrs option sets the color based on the point, not the dataset.
-			my @rgb;
-			if( $self->{cycle_clrs} ) {
-				@rgb = $self->pick_data_clr( $i + 1 );
-			} else {
-				@rgb = $self->pick_data_clr( $j );
-			} # end if
-			my $dsci = $self->set_clr( @rgb );
-			if( $self->{'3d_shading'} ) {
-				$self->{'3d_highlights'}[$dsci] = $self->set_clr( $self->_brighten( @rgb ) );
-				$self->{'3d_shadows'}[$dsci]    = $self->set_clr( $self->_darken( @rgb ) );
-			} # end if
-			
-			# contrib "Bremford, Mike" 
-			my $brci;
-			if( $self->{cycle_clrs} > 1 ) {
-				$brci = $self->set_clr($self->pick_data_clr($i + 1));
-			} else {
-				$brci = $self->set_clr($self->pick_border_clr($j));
-			} # end if
-
-
-			# get coordinates of top and center of bar
-			($xp, $t) = $self->val_to_pixel($i + 1, $value, $j);
-
-			# calculate offsets of this bar
-			my $x_offset = 0;
-			my $y_offset = 0;
-			if( $overwrite == 1 ) {
-				$x_offset = $self->{bar_depth} * ($self->{_data}->num_sets() - $j);
-				$y_offset = $self->{bar_depth} * ($self->{_data}->num_sets() - $j);
-			}
-			$t -= $y_offset;
-
-
-			# calculate left and right of bar
-			my ($l, $r);
-         if ($self->{rotate_chart}) {
-            $l = $bottom;
-            ($r) = $self->val_to_pixel($i + 1, $value, $j);
-         }
-
-			if( (ref $self eq 'GD::Graph::mixed') || ($overwrite >= 1) )
-			{
-            if ($self->{rotate_chart}) {
-               $bottom = $t + $self->{x_step}/2 - $bar_s + $x_offset;
-               $t = $t - $self->{x_step}/2 + $bar_s + $x_offset;
-            }
-            else 
-				{
-				   $l = $xp - $self->{x_step}/2 + $bar_s + $x_offset;
-				   $r = $xp + $self->{x_step}/2 - $bar_s + $x_offset;
-				}
-			}
-			else
-			{
-            if ($self->{rotate_chart}) {
-					warn "base is $t";
-					$bottom = $t - $self->{x_step}/2 
-					        + ($j) * $self->{x_step}/$self->{_data}->num_sets() 
-					        + $bar_s + $x_offset;
-					$t = $t - $self->{x_step}/2 
-					   + ($j-1) * $self->{x_step}/$self->{_data}->num_sets() 
-					   - $bar_s + $x_offset;
-					warn "top bottom is ($t, $bottom)";
-            }
-            else 
-				{
-					$l = $xp 
-						- $self->{x_step}/2
-						+ ($j - 1) * $self->{x_step}/$self->{_data}->num_sets()
-						+ $bar_s + $x_offset;
-					$r = $xp 
-						- $self->{x_step}/2
-						+ $j * $self->{x_step}/$self->{_data}->num_sets()
-						- $bar_s + $x_offset;
-				}
-			}
-
-			if ($value >= 0) {
-				# draw the positive bar
-				$self->draw_bar( $g, $l, $t, $r, $bottom-$y_offset, $dsci, $brci, 0 )
-			} else {
-				# draw the negative bar
-				$self->draw_bar( $g, $l, $bottom-$y_offset, $r, $t, $dsci, $brci, -1 )
-			} # end if
-
-		} # end for
-	} # end for
-
-
-	# redraw the 'zero' axis, front and right
-	if( $self->{zero_axis} ) {
-		$g->line( 
-			$self->{left}, $self->{zeropoint}, 
-			$self->{right}, $self->{zeropoint}, 
-			$self->{fgci} );
-		$g->line( 
-			$self->{right}, $self->{zeropoint}, 
-			$self->{right}+$self->{depth_3d}, $self->{zeropoint}-$self->{depth_3d}, 
-			$self->{fgci} );
-	} # end if
-
-	# redraw the box face
-	if ( $self->{box_axis} ) {
-		# Axes box
-		$g->rectangle($self->{left}, $self->{top}, $self->{right}, $self->{bottom}, $self->{fgci});
-		$g->line($self->{right}, $self->{top}, $self->{right} + $self->{depth_3d}, $self->{top} - $self->{depth_3d}, $self->{fgci});
-		$g->line($self->{right}, $self->{bottom}, $self->{right} + $self->{depth_3d}, $self->{bottom} - $self->{depth_3d}, $self->{fgci});
-	} # end if
-
-	return $self;
-	
-} # end draw_data
-
-# CONTRIB Jeremy Wadsack
-# This function draws a bar at the given 
-# coordinates. This is called in all three 
-# overwrite modes.
-sub draw_bar {
-	my $self = shift;
-	my $g = shift;
-	my( $l, $t, $r, $b, $dsci, $brci, $neg ) = @_;
-	
-	# get depth of the bar
-	my $depth = $self->{bar_depth};
-
-	# get the bar shadow depth and color
-	my $bsd = $self->{shadow_depth};
-	my $bsci = $self->set_clr(_rgb($self->{shadowclr}));
-
-	my( $xi );
-
-	# shadow
-	if( $bsd > 0 ) {
-		my $sb = $b - $depth;
-		my $st = $t - $depth + $bsd;
-		
-		if( $neg != 0 ) {
-			$st -= $bsd;
-			if( $self->{zero_axis_only} ) {
-				$sb += $bsd;
-			} else {
-				$sb = _min($b-$depth+$bsd, $self->{bottom}-$depth);
-			} # end if
-		} # end if
-
-		# ** If this isn't the back bar, then no side shadow should be 
-		#    drawn or else the top should be lowered by 
-		#    ($bsd * dataset_num), it should be drawn on the back surface, 
-		#    and a shadow should be drawn behind the front bar if the 
-		#    bar is positive and the back is negative.
-		
-		$g->filledRectangle($l+$depth+$bsd,
-		                    $st,
-		                    $r+$depth+$bsd,
-		                    $sb,
-		                    $bsci);
-
-		# Only draw bottom shadow if at the bottom and has bottom 
-		# axis. Always draw top shadow
-		if( ($neg == 0) || ($sb >= $self->{bottom}-$depth) ) {
-			my $poly = new GD::Polygon;
-			$poly->addPt( $r, $b );
-			$poly->addPt( $r+$bsd, $b );
-			$poly->addPt( $r+$depth+$bsd, $b-$depth );
-			$poly->addPt( $r+$depth, $b-$depth );
-			$g->filledPolygon( $poly, $bsci );
-		} # end if
-
-	} # end if
-
-	# side
-	my $poly = new GD::Polygon;
-	$poly->addPt( $r, $t );
-	$poly->addPt( $r+$depth, $t-$depth );
-	$poly->addPt( $r+$depth, $b-$depth );
-	$poly->addPt( $r, $b );
-	if( $self->{'3d_shading'} ) {
-		$g->filledPolygon( $poly, $self->{'3d_shadows'}[$dsci] );
-	} else {
-		$g->filledPolygon( $poly, $dsci );
-	} # end if
-	$g->polygon( $poly, $brci );
-
-	# top
-	#	-- only draw negative tops if the bar starts at zero
-	if( ($neg == 0) || ($t <= $self->{zeropoint}) ) {
-		$poly = new GD::Polygon;
-		$poly->addPt( $l, $t );
-		$poly->addPt( $l+$depth, $t-$depth );
-		$poly->addPt( $r+$depth, $t-$depth );
-		$poly->addPt( $r, $t );
-		if( $self->{'3d_shading'} ) {
-			$g->filledPolygon( $poly, $self->{'3d_highlights'}[$dsci] );
-		} else {
-			$g->filledPolygon( $poly, $dsci );
-		} # end if
-		$g->polygon( $poly, $brci );
-	} # end if
-
-	# face
-	$g->filledRectangle( $l, $t, $r, $b, $dsci );
-	$g->rectangle( $l, $t, $r, $b, $brci );
-
-} # end draw_bar
-
-# [JAW] Overrides axestype's set_max_min. 
-# Go through the parent's process then adjust the baseline to 0 for bar graphs.
-sub set_max_min {
-	my $self = shift;
-
-	$self->SUPER::set_max_min( @_ );
-	
-	# This code is taken from Martien's axestype.pm
-	for my $i (1..($self->{two_axes} ? 2 : 1)) {
-		# If at the same side of the zero axis
-		if( $self->{y_max}[$i] && $self->{y_min}[$i]/$self->{y_max}[$i] > 0 ) {
-			$self->{y_min}[$i] > 0 ? 
-			$self->{y_min}[$i] = 0 : 
-			$self->{y_max}[$i] = 0 ;
-		} # end if
-	} # end for
-
-	return $self;
-} # end set_max_min
-
-
-# [JW] Just use the one in GD::Graph::bars
-sub draw_values
-{
-	return &GD::Graph::bars::draw_values( @_ );
-}
-
-
-1;
diff --git a/lib/GD/Graph/colour.pm b/lib/GD/Graph/colour.pm
deleted file mode 100644
index 8b25059..0000000
--- a/lib/GD/Graph/colour.pm
+++ /dev/null
@@ -1,371 +0,0 @@
-#==========================================================================
-#              Copyright (c) 1995-1998 Martien Verbruggen
-#--------------------------------------------------------------------------
-#
-#   Name:
-#       GD::Graph::colour.pm
-#
-#   Description:
-#       Package of colour manipulation routines, to be used 
-#       with GD::Graph.
-#
-# $Id: colour.pm,v 1.10 2003/02/11 05:38:46 mgjv Exp $
-#
-#==========================================================================
-
- 
-package GD::Graph::colour;
-
-($GD::Graph::colour::VERSION) = '$Revision: 1.10 $' =~ /\s([\d.]+)/;
-
-=head1 NAME
-
-GD::Graph::colour - Colour manipulation routines for use with GD::Graph
-
-=head1 SYNOPSIS
-
-use GD::Graph::colour qw(:colours :lists :files :convert);
-
-=head1 DESCRIPTION
-
-The B package provides a few routines to work with
-colours. The functionality of this package is mainly defined by what is
-needed, now and historically, by the GD::Graph modules.
-
-=cut
-
-use vars qw( @EXPORT_OK %EXPORT_TAGS );
-use strict;
-require Exporter;
-use Carp;
-
-@GD::Graph::colour::ISA = qw( Exporter );
-
-@EXPORT_OK = qw( 
-    _rgb _luminance _hue add_colour
-    colour_list sorted_colour_list
-    read_rgb
-    hex2rgb rgb2hex
-);
-%EXPORT_TAGS = ( 
-    colours => [qw( add_colour _rgb _luminance _hue )],
-    lists => [qw( colour_list sorted_colour_list )],
-    files => [qw( read_rgb )],
-    convert => [qw( hex2rgb rgb2hex )],
-);
-
-my %RGB = (
-    white   => [0xFF,0xFF,0xFF], 
-    lgray   => [0xBF,0xBF,0xBF], 
-    gray    => [0x7F,0x7F,0x7F],
-    dgray   => [0x3F,0x3F,0x3F],
-    black   => [0x00,0x00,0x00],
-    lblue   => [0x00,0x00,0xFF], 
-    blue    => [0x00,0x00,0xBF],
-    dblue   => [0x00,0x00,0x7F], 
-    gold    => [0xFF,0xD7,0x00],
-    lyellow => [0xFF,0xFF,0x00], 
-    yellow  => [0xBF,0xBF,0x00], 
-    dyellow => [0x7F,0x7F,0x00],
-    lgreen  => [0x00,0xFF,0x00], 
-    green   => [0x00,0xBF,0x00], 
-    dgreen  => [0x00,0x7F,0x00],
-    lred    => [0xFF,0x00,0x00], 
-    red     => [0xBF,0x00,0x00],
-    dred    => [0x7F,0x00,0x00],
-    lpurple => [0xFF,0x00,0xFF], 
-    purple  => [0xBF,0x00,0xBF],
-    dpurple => [0x7F,0x00,0x7F],
-    lorange => [0xFF,0xB7,0x00], 
-    orange  => [0xFF,0x7F,0x00],
-    pink    => [0xFF,0xB7,0xC1], 
-    dpink   => [0xFF,0x69,0xB4],
-    marine  => [0x7F,0x7F,0xFF], 
-    cyan    => [0x00,0xFF,0xFF],
-    lbrown  => [0xD2,0xB4,0x8C], 
-    dbrown  => [0xA5,0x2A,0x2A],
-);
-
-=head1 FUNCTIONS
-
-=head2 colour_list( I )
-
-Returns a list of I colour names known to the package.
-Exported with the :lists tag.
-
-=cut
-
-sub colour_list 
-{
-    my $n = ( $_[0] ) ? $_[0] : keys %RGB;
-    return (keys %RGB)[0 .. $n-1]; 
-}
-
-=head2 sorted_colour_list( I )
-
-Returns a list of I colour names known to the package, 
-sorted by luminance or hue.
-B Right now it always sorts by luminance. Will add an option in a later
-stage to decide sorting method at run time.
-Exported with the :lists tag.
-
-=cut
-
-sub sorted_colour_list 
-{
-    my $n = $_[0] ? $_[0] : keys %RGB;
-    return (sort by_luminance keys %RGB)[0 .. $n-1];
-    # return (sort by_hue keys %rgb)[0..$n-1];
-
-    sub by_luminance { _luminance(@{$RGB{$b}}) <=> _luminance(@{$RGB{$a}}) }
-    sub by_hue       { _hue(@{$RGB{$b}}) <=> _hue(@{$RGB{$a}}) }
-}
-
-=head2 _rgb( I )
-
-Returns a list of the RGB values of I. if the colour name
-is a string of the form that is acceptable to the hex2rgb sub, then the
-colour will be added to the list dynamically.
-Exported with the :colours tag.
-
-=cut
-
-my %warned_clrs = ();
-
-# return the RGB values of the colour name
-sub _rgb 
-{ 
-    my $clr = shift or return;
-
-    # Try adding the colour if it doesn't exist yet. It may be of a
-    # parseable form
-    add_colour($clr) unless exists $RGB{$clr};
-
-    my $rgb_ref = $RGB{$clr};
-    if (!defined $rgb_ref)
-    {
-        $rgb_ref = $RGB{'black'};
-        unless ($warned_clrs{$clr})
-        {
-            $warned_clrs{$clr}++;
-            carp "Colour $clr is not defined, reverting to black"; 
-        }
-    };
-
-    @{$rgb_ref};
-}
-
-=head2 _hue( I )
-
-Returns the hue of the colour with the specified RGB values.
-Exported with the :colours tag.
-
-=head2 _luminance( I )
-
-Returns the luminance of the colour with the specified RGB values.
-Exported with the :colours tag.
-
-=cut
-
-# return the luminance of the colour (RGB)
-sub _luminance 
-{ 
-    (0.212671 * $_[0] + 0.715160 * $_[1] + 0.072169 * $_[2])/0xFF
-}
-
-# return the hue of the colour (RGB)
-sub _hue 
-{ 
-    ($_[0] + $_[1] + $_[2])/(3 * 0xFF) 
-}
-
-=head2 add_colour(colourname => [$r, $g, $b]) or
-add_colour('#7fe310')
-
-Self-explanatory.
-Exported with the :colours tag.
-
-=cut
-
-sub add_colour
-{
-    my $name = shift;
-    my $val  = shift;
-
-    if (!defined $val)
-    {
-        my @rgb = hex2rgb($name) or return;
-        $val = [@rgb];
-    }
-
-    if (ref $val && ref $val eq 'ARRAY')
-    {
-        $RGB{$name} = [@{$val}];
-        return $name;
-    }
-
-    return;
-}
-
-=head2 rgb2hex($red, $green, $blue)
-
-=head2 hex2rgb('#7fe310')
-
-These functions translate a list of RGB values into a hexadecimal
-string, as is commonly used in HTML and the Image::Magick API, and vice
-versa.
-Exported with the :convert tag.
-
-=cut
-
-# Color translation
-sub rgb2hex
-{
-    return unless @_ == 3;
-    my $color = '#';
-    foreach my $cc (@_)
-    {
-        $color .= sprintf("%02x", $cc);
-    }
-    return $color;
-}
-
-sub hex2rgb
-{
-    my $clr = shift;
-    my @rgb = $clr =~ /^#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/i;
-    return unless @rgb;
-    return map { hex $_ } @rgb;
-}
-
-=head2 read_rgb( F )
-
-Reads in colours from a rgb file as used by the X11 system.
-
-Doing something like:
-
-    use GD::Graph::bars;
-    use GD::Graph::colour;
-
-    GD::Graph::colour::read_rgb("rgb.txt") or die "cannot read colours";
-
-Will allow you to use any colours defined in rgb.txt in your graph.
-Exported with the :files tag.
-
-=cut
-
-#
-# Read a rgb.txt file (X11)
-#
-# Expected format of the file:
-#
-# R G B colour name
-#
-# Fields can be separated by any number of whitespace
-# Lines starting with an exclamation mark (!) are comment and 
-# will be ignored.
-#
-# returns number of colours read
-
-sub read_rgb($) # (filename)
-{
-    my $fn = shift;
-    my $n = 0;
-    my $line;
-
-    open(RGB, $fn) or return 0;
-
-    while (defined($line = ))
-    {
-        next if ($line =~ /\s*!/);
-        chomp($line);
-
-        # remove leading white space
-        $line =~ s/^\s+//;
-
-        # get the colours
-        my ($r, $g, $b, $name) = split(/\s+/, $line, 4);
-        
-        # Ignore bad lines
-        next unless (defined $name);
-
-        $RGB{$name} = [$r, $g, $b];
-        $n++;
-    }
-
-    close(RGB);
-
-    return $n;
-}
-
-sub version { $GD::Graph::colour::VERSION }
-
-sub dump_colours
-{
-    my $max = $_[0] ? $_[0] : keys %RGB;
-    my $n = 0;
-
-    my $clr;
-    foreach $clr (sorted_colour_list($max))
-    {
-        last if $n > $max;
-        print "colour: $clr, " . 
-            "${$RGB{$clr}}[0], ${$RGB{$clr}}[1], ${$RGB{$clr}}[2]\n"
-    }
-}
-
-
-"Just another true value";
-
-__END__
-
-=head1 PREDEFINED COLOUR NAMES
-
-white,
-lgray,
-gray,
-dgray,
-black,
-lblue,
-blue,
-dblue,
-gold,
-lyellow,
-yellow,
-dyellow,
-lgreen,
-green,
-dgreen,
-lred,
-red,
-dred,
-lpurple,
-purple,
-dpurple,
-lorange,
-orange,
-pink,
-dpink,
-marine,
-cyan,
-lbrown,
-dbrown.
-
-=head1 AUTHOR
-
-Martien Verbruggen Emgjv@tradingpost.com.auE
-
-=head2 Copyright
-
-GIFgraph: Copyright (c) 1995-1999 Martien Verbruggen.
-Chart::PNGgraph: Copyright (c) 1999 Steve Bonds.
-GD::Graph: Copyright (c) 1999 Martien Verbruggen.
-
-All rights reserved. This package is free software; you can redistribute
-it and/or modify it under the same terms as Perl itself.
-
-=head1 SEE ALSO
-
-L, 
-L
-
diff --git a/lib/GD/Graph/cylinder.pm b/lib/GD/Graph/cylinder.pm
deleted file mode 100644
index ba8ab86..0000000
--- a/lib/GD/Graph/cylinder.pm
+++ /dev/null
@@ -1,126 +0,0 @@
-# $File: //depot/RG/rg/lib/RG/lib/GD/Graph/cylinder.pm $ $Author: autrijus $
-# $Revision: #3 $ $Change: 370 $ $DateTime: 2002/07/17 20:38:38 $
-
-package GD::Graph::cylinder;
-
-use strict;
-
-use GD::Graph::axestype3d;
-use GD::Graph::utils qw(:all);
-use GD::Graph::colour qw(:colours);
-
-use base qw/GD::Graph::bars3d/;
-$GD::Graph::cylinder::VERSION = '0.63';
-
-my %Defaults = (
-	# Spacing between the bars
-	bar_spacing 	=> 0,
-
-	# The 3-d extrusion depth of the bars
-	bar_depth => 10,
-);
-
-sub initialise
-{
-	my $self = shift;
-
-	my $rc = $self->SUPER::initialise();
-	$self->set(correct_width => 1);
-
-	while( my($key, $val) = each %Defaults ) { 
-		$self->{$key} = $val 
-	} # end while
-
-	return $rc;
-} # end initialise
-
-sub draw_bar_h {
-    my $self = shift;
-    my $g = shift;
-    my( $l, $t, $r, $b, $dsci, $brci, $neg ) = @_;
-    my $fnord = $g->colorAllocate(0,0,0);
-
-    my $depth = $self->{bar_depth};
-
-    my ($lighter, $darker) = ($dsci, $dsci);
-    if ($self->{'3d_shading'}) {
-	$lighter = $self->{'3d_highlights'}[$dsci];
-	$darker = $self->{'3d_shadows'}[$dsci];
-    }
-    $g->line($l+$depth, $t+1, $r+$depth, $t+1, $dsci);
-    $g->line($l+$depth, $b, $r+$depth, $b, $dsci);
-    $g->arc($r+$depth, ($t+$b)/2, $depth*2, ($b-$t), 270, 90, $dsci);
-    $g->arc($l+$depth, ($t+$b)/2, $depth*2, ($b-$t), 90, 270, $dsci);
-    # find border
-    my $foo = $l+$depth;
-    --$foo
-	until $foo == $l || $g->getPixel($foo, $t+($b-$t)/5) == $dsci;
-    my $bar = $foo+1;
-    ++$bar
-	until $bar == $foo || $g->getPixel($bar, $t+($b-$t)/5) == $dsci;
-    $g->line($foo, $t+($b-$t)/5, $bar, $t+($b-$t)/5, $dsci);
-    $g->line($foo, $b-($b-$t)/5, $bar, $b-($b-$t)/5, $dsci);
-    $g->fillToBorder($l+$depth, ($t+$b)/2, $dsci, $dsci);
-    $g->arc($l+$depth, ($b+$t)/2, $depth*2, ($b-$t), 90, 270, $dsci);
-    if ($foo < $bar + 3) {
-	$g->fillToBorder(($l+$r)/2+$depth, $t+($b-$t)/5-1, $dsci, $lighter)
-	    unless $g->getPixel(($l+$r)/2+$depth, $t+($b-$t)/5-1) == $dsci;
-	$g->fillToBorder(($l+$r)/2+$depth, $b-($b-$t)/5+1, $dsci, $darker)
-	    unless $g->getPixel(($l+$r)/2+$depth, $b-($b-$t)/5+1) == $dsci;
-	$g->fillToBorder(($l+$r)/2, ($t+$b)/2, $dsci, $dsci);
-    }
-    $g->arc($l+$depth, ($b+$t)/2, $depth*2, ($b-$t), 90, 270, $brci);
-    $g->arc($r+$depth, ($b+$t)/2, $depth*2, ($b-$t), 0, 360, $brci);
-    $g->line($l+$depth, $t+1, $r+$depth, $t+1, $brci);
-    $g->line($l+$depth, $b, $r+$depth, $b, $brci);
-    $g->fillToBorder($r+$depth, ($b+$t)/2, $brci, $dsci);
-}
-
-sub draw_bar {
-	my $self = shift;
-	return $self->draw_bar_h(@_) if $self->{rotate_chart};
-	my $g = shift;
-	my( $l, $t, $r, $b, $dsci, $brci, $neg ) = @_;
-	my $fnord = $g->colorAllocate(0,0,0);
-
-	my $depth = $self->{bar_depth};
-
-	my ($lighter, $darker) = ($dsci, $dsci);
-	if ($self->{'3d_shading'}) {
-	    $lighter = $self->{'3d_highlights'}[$dsci];
-	    $darker = $self->{'3d_shadows'}[$dsci];
-	}
-
-	$g->line($l+1, $t-$depth, $l+1, $b-$depth, $dsci);
-	$g->line($r, $t-$depth, $r, $b-$depth, $dsci);
-
-	$g->arc(($l+$r)/2, $t-$depth, ($r-$l), $depth*2, 180, 360, $dsci);
-	$g->arc(($l+$r)/2, $b-$depth, ($r-$l), $depth*2, 0, 180, $dsci);
-	# find border
-	my $foo = $b-$depth+1;
-	++$foo
-	    until $foo == $b || $g->getPixel($l+($r-$l)/5,$foo) == $dsci;
-	my $bar = $foo-1;
-	--$bar
-	    until $bar == $foo || $g->getPixel($l+($r-$l)/5,$bar) == $dsci;
-	$g->line($l+($r-$l)/5, $bar, $l+($r-$l)/5, $foo, $dsci);
-	$g->line($r-($r-$l)/5, $bar, $r-($r-$l)/5, $foo, $dsci);
-	$g->fillToBorder(($l+$r)/2, $t-$depth, $dsci, $dsci);
-	$g->arc(($l+$r)/2, $b-$depth, ($r-$l), $depth*2, 0, 180, $dsci);
-	if ($foo > $bar + 3) {
-	    $g->fillToBorder($l+($r-$l)/5-1, ($foo+$bar)/2, $dsci, $lighter)
-		unless $g->getPixel($l+($r-$l)/5-1, ($foo+$bar)/2) == $dsci;
-	    $g->fillToBorder($r-($r-$l)/5+1, ($foo+$bar)/2, $dsci, $darker)
-		unless $g->getPixel($r-($r-$l)/5+1, ($foo+$bar)/2) == $dsci;
-	    $g->fillToBorder(($l+$r)/2, ($t+$b)/2, $dsci, $dsci);
-	}
-	$g->arc(($l+$r)/2, $b-$depth, ($r-$l), $depth*2, 0, 180, $brci);
-	$g->arc(($l+$r)/2, $t-$depth, ($r-$l), $depth*2, 0, 360, $brci);
-	$g->line($l+1, $t-$depth, $l+1, $b-$depth, $brci);
-	$g->line($r, $t-$depth, $r, $b-$depth, $brci);
-	$g->fillToBorder(($l+$r)/2, $t-$depth, $brci, $dsci);
-}
-
-1;
-
-
diff --git a/lib/GD/Graph/cylinder3d.pm b/lib/GD/Graph/cylinder3d.pm
deleted file mode 100644
index 7bc2490..0000000
--- a/lib/GD/Graph/cylinder3d.pm
+++ /dev/null
@@ -1,30 +0,0 @@
-############################################################
-#
-# Module: GD::Graph::cylinder3d
-#
-# Description: 
-# This is merely a wrapper around GD::Graph::cylinder 
-# to be used as an alias
-#
-# Created: 16 October 2002 by Jeremy Wadsack for Wadsack-Allen Digital Group
-# 	Copyright (C) 2002 Wadsack-Allen. All rights reserved.
-############################################################
-# Date      Modification                              Author
-# ----------------------------------------------------------
-#                                                          #
-############################################################
-package GD::Graph::cylinder3d;
-
-use strict;
-use GD;
-use GD::Graph;
-use GD::Graph::cylinder;
-use Carp;
-
-@GD::Graph::cylinder3d::ISA = qw( GD::Graph::cylinder );
-$GD::Graph::cylinder3d::VERSION = '0.63';
-
-# Inherit everything from GD::Graph::cylinder
-
-
-1;
diff --git a/lib/GD/Graph/hbars.pm b/lib/GD/Graph/hbars.pm
deleted file mode 100644
index e2268b5..0000000
--- a/lib/GD/Graph/hbars.pm
+++ /dev/null
@@ -1,71 +0,0 @@
-#==========================================================================
-#              Copyright (c) 1995-1998 Martien Verbruggen
-#--------------------------------------------------------------------------
-#
-#   Name:
-#       GD::Graph::hbars.pm
-#
-# $Id: hbars.pm,v 1.3 2003/02/10 22:12:41 mgjv Exp $
-#
-#==========================================================================
- 
-package GD::Graph::hbars;
-
-($GD::Graph::hbars::VERSION) = '$Revision: 1.3 $' =~ /\s([.\d]+)/;
-
-use strict;
-
-use GD::Graph::bars;
-use GD::Graph::utils qw(:all);
-use GD::Graph::colour qw(:colours);
-
-@GD::Graph::hbars::ISA = qw(GD::Graph::bars);
-
-sub initialise
-{
-    my $self = shift;
-    $self->SUPER::initialise();
-    $self->set(rotate_chart => 1);
-}
-
-"Just another true value";
-
-__END__
-
-=head1 NAME
-
-GD::Graph::hbars - make bar graphs with horizontal bars
-
-=head1 SYNOPSIS
-
-use GD::Graph::hbars;
-
-=head1 DESCRIPTION
-
-This is a wrapper module which is completely identical to creating a
-GD::Graph::bars object with the C attribute set to a true
-value.
-
-=head1 SEE ALSO
-
-L
-
-=head1 AUTHOR
-
-Martien Verbruggen Emgjv@tradingpost.com.auE
-
-=head2 Copyright
-
-(c) Martien Verbruggen
-
-=head2 Acknowledgements
-
-The original author of most of the code needed to implement this was
-brian d foy, who sent this module to me after I complained I didn't have
-the time to implement horizontal bar charts. I took the code that lived
-in here, and distributed it over axestype.pm and bars.pm, to allow for a
-better integration all around. His code, in turn, was mainly based on an
-earlier version of bars.pm and axestype.pm.
-
-=cut
-
diff --git a/lib/GD/Graph/lines.pm b/lib/GD/Graph/lines.pm
deleted file mode 100644
index 2dac4dd..0000000
--- a/lib/GD/Graph/lines.pm
+++ /dev/null
@@ -1,182 +0,0 @@
-#==========================================================================
-#              Copyright (c) 1995-1998 Martien Verbruggen
-#--------------------------------------------------------------------------
-#
-#   Name:
-#       GD::Graph::lines.pm
-#
-# $Id: lines.pm,v 1.15 2003/02/10 22:12:41 mgjv Exp $
-#
-#==========================================================================
-
-package GD::Graph::lines;
-
-($GD::Graph::lines::VERSION) = '$Revision: 1.15 $' =~ /\s([\d.]+)/;
-
-use strict;
- 
-use GD;
-use GD::Graph::axestype;
-
-@GD::Graph::lines::ISA = qw( GD::Graph::axestype );
-
-# PRIVATE
-
-sub draw_data_set
-{
-    my $self = shift;
-    my $ds = shift;
-
-    my @values = $self->{_data}->y_values($ds) or
-        return $self->_set_error("Impossible illegal data set: $ds",
-            $self->{_data}->error);
-
-    my $dsci = $self->set_clr($self->pick_data_clr($ds) );
-    my $type = $self->pick_line_type($ds);
-
-    my ($xb, $yb);
-    if (defined $values[0])
-    {
-        if (defined($self->{x_min_value}) && defined($self->{x_max_value}))
-        {
-            ($xb, $yb) =
-                $self->val_to_pixel($self->{_data}->get_x(0), $values[0], $ds);
-        }
-        else    
-        {
-            ($xb, $yb) = $self->val_to_pixel(1, $values[0], $ds);
-        }
-    }
-
-    for (my $i = 0; $i < @values; $i++)
-    {
-        if (!defined $values[$i])
-        {
-            ($xb, $yb) = () if $self->{skip_undef};
-            next;
-        }
-
-        my ($xe, $ye);
-
-        if (defined($self->{x_min_value}) && defined($self->{x_max_value}))
-        {
-            ($xe, $ye) = $self->val_to_pixel(
-                $self->{_data}->get_x($i), $values[$i], $ds);
-        }
-        else
-        {
-            ($xe, $ye) = $self->val_to_pixel($i+1, $values[$i], $ds);
-        }
-
-        if (defined $xb)
-        {
-            $self->draw_line($xb, $yb, $xe, $ye, $type, $dsci)
-                if defined $dsci;
-            $self->{_hotspots}->[$ds]->[$i] = 
-                ['line', $xb, $yb, $xe, $ye, $self->{line_width}];
-        }
-        ($xb, $yb) = ($xe, $ye);
-   }
-
-   return $ds;
-}
-
-sub pick_line_type
-{
-    my $self = shift;
-    my $num = shift;
-
-    ref $self->{line_types} ?
-        $self->{line_types}[ $num % (1 + $#{$self->{line_types}}) - 1 ] :
-        $num % 4 ? $num % 4 : 4
-}
-
-sub draw_line # ($xs, $ys, $xe, $ye, $type, $colour_index)
-{
-    my $self = shift;
-    my ($xs, $ys, $xe, $ye, $type, $clr) = @_;
-
-    my $lw = $self->{line_width};
-    my $lts = $self->{line_type_scale};
-
-    my $style = gdStyled;
-    my @pattern = ();
-
-    LINE: {
-
-        ($type == 2) && do {
-            # dashed
-
-            for (1 .. $lts) { push @pattern, $clr }
-            for (1 .. $lts) { push @pattern, gdTransparent }
-
-            $self->{graph}->setStyle(@pattern);
-
-            last LINE;
-        };
-
-        ($type == 3) && do {
-            # dotted,
-
-            for (1 .. 2) { push @pattern, $clr }
-            for (1 .. 2) { push @pattern, gdTransparent }
-
-            $self->{graph}->setStyle(@pattern);
-
-            last LINE;
-        };
-
-        ($type == 4) && do {
-            # dashed and dotted
-
-            for (1 .. $lts) { push @pattern, $clr }
-            for (1 .. 2)    { push @pattern, gdTransparent }
-            for (1 .. 2)    { push @pattern, $clr }
-            for (1 .. 2)    { push @pattern, gdTransparent }
-
-            $self->{graph}->setStyle(@pattern);
-
-            last LINE;
-        };
-
-        # default: solid
-        $style = $clr;
-    }
-
-    # Tried the line_width thing with setBrush, ugly results
-    # TODO: This loop probably should be around the datasets 
-    # for nicer results
-    my $i;
-    for $i (1..$lw)
-    {
-        my $yslw = $ys + int($lw/2) - $i;
-        my $yelw = $ye + int($lw/2) - $i;
-
-        # Need the setstyle to reset 
-        $self->{graph}->setStyle(@pattern) if (@pattern);
-        $self->{graph}->line( $xs, $yslw, $xe, $yelw, $style );
-    }
-}
-
-sub draw_legend_marker # (data_set_number, x, y)
-{
-    my $self = shift;
-    my ($n, $x, $y) = @_;
-
-    my $ci = $self->set_clr($self->pick_data_clr($n));
-    return unless defined $ci;
-    my $type = $self->pick_line_type($n);
-
-    $y += int($self->{lg_el_height}/2);
-
-    #  Joe Smith 
-    local($self->{line_width}) = 2;    # Make these show up better
-
-    $self->draw_line(
-        $x, $y, 
-        $x + $self->{legend_marker_width}, $y,
-        $type, $ci
-    );
-}
-
-"Just another true value";
diff --git a/lib/GD/Graph/lines3d.pm b/lib/GD/Graph/lines3d.pm
deleted file mode 100644
index dfd60c7..0000000
--- a/lib/GD/Graph/lines3d.pm
+++ /dev/null
@@ -1,522 +0,0 @@
-#==========================================================================
-# Module: GD::Graph::lines3d
-#
-# Copyright (C) 1999,2001 Wadsack-Allen. All Rights Reserved.
-#
-# Based on GD::Graph::lines.pm,v 1.10 2000/04/15 mgjv
-#          Copyright (c) 1995-1998 Martien Verbruggen
-#
-#--------------------------------------------------------------------------
-# Date		Modification				                                 Author
-# -------------------------------------------------------------------------
-# 1999SEP18 Created 3D line chart class (this module)                   JAW
-# 1999SEP19 Finished overwrite 1 style                                  JAW
-# 1999SEP19 Polygon'd linewidth rendering                               JAW
-# 2000SEP19 Converted to a GD::Graph class                              JAW
-# 2000APR18 Modified for compatibility with GD::Graph 1.30              JAW
-# 2000APR24 Fixed a lot of rendering bugs                               JAW
-# 2000AUG19 Changed render code so lines have consitent width           JAW
-# 2000AUG21 Added 3d shading                                            JAW
-# 2000AUG24 Fixed shading top/botttom vs. postive/negative slope        JAW
-# 2000SEP04 For single point "lines" made a short segment               JAW
-# 2000OCT09 Fixed bug in rendering of legend                            JAW
-#==========================================================================
-# TODO
-#		** The new mitred corners don't work well at data anomlies. Like
-#		   the set (0,0,1,0,0,0,1,0,1) Looks really wrong!
-#		* Write a draw_data_set that draws the line so they appear to pass 
-#		  through one another. This means drawing a border edge at each 
-#		  intersection of the data lines so the points of pass-through show.
-#		  Probably want to draw all filled polygons, then run through the data 
-#		  again finding intersections of line segments and drawing those edges.
-#==========================================================================
-package GD::Graph::lines3d;
-
-use strict;
- 
-use GD;
-use GD::Graph::axestype3d;
-use Data::Dumper;
-
-@GD::Graph::lines3d::ISA = qw( GD::Graph::axestype3d );
-$GD::Graph::lines3d::VERSION = '0.63';
-
-my $PI = 4 * atan2(1, 1);
-
-my %Defaults = (
-	# The depth of the line in their extrusion
-
-	line_depth		=> 10,
-);
-
-sub initialise()
-{
-	my $self = shift;
-
-	my $rc = $self->SUPER::initialise();
-
-	while( my($key, $val) = each %Defaults ) { 
-		$self->{$key} = $val 
-
-		# *** [JAW]
-		# Should we reset the depth_3d param based on the 
-		# line_depth, numsets and overwrite parameters, here?
-		#
-	} # end while
-
-	return $rc;
-	
-} # end initialize
-
-sub set
-{
-	my $s = shift;
-	my %args = @_;
-
-	$s->{_set_error} = 0;
-
-	for (keys %args) 
-	{ 
-		/^line_depth$/ and do 
-		{
-			$s->{line_depth} = $args{$_};
-			delete $args{$_};
-			next;
-		};
-	}
-
-	return $s->SUPER::set(%args);
-} # end set
-
-# PRIVATE
-
-# [JAW] Changed to draw_data intead of 
-# draw_data_set to allow better control 
-# of multiple set rendering
-sub draw_data
-{
-	my $self = shift;
-	my $d = $self->{_data};
-	my $g = $self->{graph};
-
-	$self->draw_data_overwrite( $g, $d );
-
-	# redraw the 'zero' axis, front and right
-	if( $self->{zero_axis} ) {
-		$g->line( 
-			$self->{left}, $self->{zeropoint}, 
-			$self->{right}, $self->{zeropoint}, 
-			$self->{fgci} );
-		$g->line( 
-			$self->{right}, $self->{zeropoint}, 
-			$self->{right} + $self->{depth_3d}, $self->{zeropoint} - $self->{depth_3d}, 
-			$self->{fgci} );
-	} # end if
-	
-	# redraw the box face
-	if ( $self->{box_axis} ) {
-		# Axes box
-		$g->rectangle($self->{left}, $self->{top}, $self->{right}, $self->{bottom}, $self->{fgci});
-		$g->line($self->{right}, $self->{top}, $self->{right} + $self->{depth_3d}, $self->{top} - $self->{depth_3d}, $self->{fgci});
-		$g->line($self->{right}, $self->{bottom}, $self->{right} + $self->{depth_3d}, $self->{bottom} - $self->{depth_3d}, $self->{fgci});
-	} # end if
-
-	return $self;
-	
-} # end draw_data
-
-# Copied from MVERB source
-sub pick_line_type
-{
-	my $self = shift;
-	my $num = shift;
-
-	ref $self->{line_types} ?
-		$self->{line_types}[ $num % (1 + $#{$self->{line_types}}) - 1 ] :
-		$num % 4 ? $num % 4 : 4
-}
-
-# ----------------------------------------------------------
-# Sub: draw_data_overwrite
-#
-# Args: $gd
-#	$gd	The GD object to draw on
-#
-# Description: Draws each line segment for each set. Runs 
-# over sets, then points so that the appearance is better.
-# ----------------------------------------------------------
-# Date      Modification                              Author
-# ----------------------------------------------------------
-# 19SEP1999 Added this for overwrite support.             JW
-# 20AUG2000 Changed structure to use points 'objects'     JW
-# ----------------------------------------------------------
-sub draw_data_overwrite {
-	my $self = shift;
-	my $g = shift;
-	my @points_cache;
-
-	my $i;
-	for $i (0 .. $self->{_data}->num_points()) 
-	{
-		my $j;
-		for $j (1 .. $self->{_data}->num_sets()) 
-		{
-			my @values = $self->{_data}->y_values($j) or
-				return $self->_set_error( "Impossible illegal data set: $j", $self->{_data}->error );
-
-			if( $self->{_data}->num_points() == 1 && $i == 1 ) {
-				# Copy the first point to the "second" 
-				$values[$i] = $values[0];
-			} # end if
-
-			next unless defined $values[$i];
-
-			# calculate offset of this line
-			# *** Should offset be the max of line_depth 
-			#     and depth_3d/numsets? [JAW]
-			#
-			my $offset = $self->{line_depth} * ($self->{_data}->num_sets() - $j);
-
-			# Get the coordinates of the previous point, if this is the first 
-			# point make a point object and start over (i.e. next;)
-			unless( $i ) {
-				my( $xb, $yb );
-				if (defined($self->{x_min_value}) && defined($self->{x_max_value})) {
-					($xb, $yb) = $self->val_to_pixel( $self->{_data}->get_x($i), $values[$i], $j );
-				} else {
-					($xb, $yb) = $self->val_to_pixel( $i + 1, $values[$i], $j );
-				} # end if
-				$xb += $offset;
-				$yb -= $offset;
-				$points_cache[$i][$j] = { coords => [$xb, $yb] };
-				next;
-			} # end unless
-
-			# Pick a data colour, calc shading colors too, if requested
-			my( @rgb ) = $self->pick_data_clr( $j );
-			my $dsci = $self->set_clr( @rgb );
-			if( $self->{'3d_shading'} ) {
-				$self->{'3d_highlights'}[$dsci] = $self->set_clr( $self->_brighten( @rgb ) );
-				$self->{'3d_shadows'}[$dsci]    = $self->set_clr( $self->_darken( @rgb ) );
-			} # end if
-
-			# Get the type
-			my $type = $self->pick_line_type($j);
-			
-			# Get the coordinates of the this point
-			unless( ref $points_cache[$i][$j] ) {
-				my( $xe, $ye );
-				if( defined($self->{x_min_value}) && defined($self->{x_max_value}) ) {
-					( $xe, $ye ) = $self->val_to_pixel( $self->{_data}->get_x($i), $values[$i], $j );
-				} else {
-					( $xe, $ye ) = $self->val_to_pixel($i + 1, $values[$i], $j);
-				} # end if
-				$xe += $offset;
-				$ye -= $offset;
-				$points_cache[$i][$j] = { coords => [$xe, $ye] };
-			} # end if
-			
-			# Find the coordinates of the next point
-			if( defined $values[$i + 1] ) {
-				my( $xe, $ye );
-				if( defined($self->{x_min_value}) && defined($self->{x_max_value}) ) {
-					( $xe, $ye ) = $self->val_to_pixel( $self->{_data}->get_x($i + 1), $values[$i + 1], $j );
-				} else {
-					( $xe, $ye ) = $self->val_to_pixel($i + 2, $values[$i + 1], $j);
-				} # end if
-				$xe += $offset;
-				$ye -= $offset;
-				$points_cache[$i + 1][$j] = { coords => [$xe, $ye] };
-			} # end if
-
-			if( $self->{_data}->num_points() == 1 && $i == 1 ) {
-				# Nudge the x coords back- and forwards
-				my $n = int(($self->{right} - $self->{left}) / 30);
-				$n = 2 if $n < 2;
-				$points_cache[$i][$j]{coords}[0] = $points_cache[$i - 1][$j]{coords}[0] + $n;
-				$points_cache[$i - 1][$j]{coords}[0] -= $n;
-			} # end if
-			
-			# Draw the line segment
-			$self->draw_line( $points_cache[$i - 1][$j], 
-			                  $points_cache[$i][$j], 
-			                  $points_cache[$i + 1][$j], 
-			                  $type, 
-			                  $dsci );
-			
-			# Draw the end cap if last segment
-			if( $i >= $self->{_data}->num_points() - 1 ) {
-				my $poly = new GD::Polygon;
-				$poly->addPt( $points_cache[$i][$j]{face}[0], $points_cache[$i][$j]{face}[1] );
-				$poly->addPt( $points_cache[$i][$j]{face}[2], $points_cache[$i][$j]{face}[3] );
-				$poly->addPt( $points_cache[$i][$j]{face}[2] + $self->{line_depth}, $points_cache[$i][$j]{face}[3] - $self->{line_depth} );
-				$poly->addPt( $points_cache[$i][$j]{face}[0] + $self->{line_depth}, $points_cache[$i][$j]{face}[1] - $self->{line_depth} );
-				if( $self->{'3d_shading'} ) {
-					$g->filledPolygon( $poly, $self->{'3d_shadows'}[$dsci] );
-				} else {
-					$g->filledPolygon( $poly, $dsci );
-				} # end if
-				$g->polygon( $poly, $self->{fgci} );
-			} # end if
-
-		} # end for -- $self->{_data}->num_sets()
-	} # end for -- $self->{_data}->num_points()
-
-} # end sub draw_data_overwrite
-
-# ----------------------------------------------------------
-# Sub: draw_line
-#
-# Args: $prev, $this, $next, $type, $clr
-#	$prev       A hash ref for the prev point's object
-#	$this       A hash ref for this point's object
-#	$next       A hash ref for the next point's object
-#	$type       A predefined line type (2..4) = (dashed, dotted, dashed & dotted)
-#	$clr        The color (colour) index to use for the fill
-#
-# Point "Object" has these properties:
-#	coords      A 2 element array of the coordinates for the line 
-#	            (this should be filled in before calling)
-#	face        An 4 element array of end points for the face 
-#	            polygon. This will be populated by this method.
-#
-# Description: Draws a line segment in 3d extrusion that 
-# connects the prev point the the this point. The next point
-# is used to calculate the mitre at the joint.
-# ----------------------------------------------------------
-# Date      Modification                              Author
-# ----------------------------------------------------------
-# 18SEP1999 Modified MVERB source to work on data 
-#           point, not data set for better rendering     JAW
-# 19SEP1999 Ploygon'd line rendering for better effect   JAW
-# 19AUG2000 Made line width perpendicular                JAW
-# 19AUG2000 Changed parameters to use %line_seg hash/obj JAW
-# 20AUG2000 Mitred joints of line segments               JAW
-# ----------------------------------------------------------
-sub draw_line
-{
-	my $self = shift;
-	my( $prev, $this, $next, $type, $clr ) = @_;
-	my $xs = $prev->{coords}[0];
-	my $ys = $prev->{coords}[1];
-	my $xe = $this->{coords}[0];
-	my $ye = $this->{coords}[1];
-
-	my $lw = $self->{line_width};
-	my $lts = $self->{line_type_scale};
-
-	my $style = gdStyled;
-	my @pattern = ();
-
-	LINE: {
-
-		($type == 2) && do {
-			# dashed
-
-			for (1 .. $lts) { push @pattern, $clr }
-			for (1 .. $lts) { push @pattern, gdTransparent }
-
-			$self->{graph}->setStyle(@pattern);
-
-			last LINE;
-		};
-
-		($type == 3) && do {
-			# dotted,
-
-			for (1 .. 2) { push @pattern, $clr }
-			for (1 .. 2) { push @pattern, gdTransparent }
-
-			$self->{graph}->setStyle(@pattern);
-
-			last LINE;
-		};
-
-		($type == 4) && do {
-			# dashed and dotted
-
-			for (1 .. $lts) { push @pattern, $clr }
-			for (1 .. 2) 	{ push @pattern, gdTransparent }
-			for (1 .. 2) 	{ push @pattern, $clr }
-			for (1 .. 2) 	{ push @pattern, gdTransparent }
-
-			$self->{graph}->setStyle(@pattern);
-
-			last LINE;
-		};
-
-		# default: solid
-		$style = $clr;
-	}
-
-	# [JAW] Removed the dataset loop for better results.
-
-	# Need the setstyle to reset 
-	$self->{graph}->setStyle(@pattern) if (@pattern);
-
-	#
-	# Find the x and y offsets for the edge of the front face 
-	# Do this by adjusting them perpendicularly from the line
-	# half the line width in front and in back. 
-	#
-	my( $lwyoff, $lwxoff );
-	if( $xe == $xs ) {
-		$lwxoff = $lw / 2;
-		$lwyoff = 0;
-	} elsif( $ye == $ys ) {
-		$lwxoff = 0;
-		$lwyoff = $lw / 2;
-	} else {
-		my $ln = sqrt( ($ys-$ye)**2 + ($xe-$xs)**2 );
-		$lwyoff = ($xe-$xs) / $ln  * $lw / 2;
-		$lwxoff = ($ys-$ye) / $ln * $lw / 2;
-	} # end if
-
-	# For first line, figure beginning point
-	unless( defined $prev->{face}[0] ) {
-		$prev->{face} = [];
-		$prev->{face}[0] = $xs - $lwxoff;
-		$prev->{face}[1] = $ys - $lwyoff;
-		$prev->{face}[2] = $xs + $lwxoff;
-		$prev->{face}[3] = $ys + $lwyoff;
-	} # end unless
-	
-	# Calc and store this point's face coords
-	unless( defined $this->{face}[0] ) {
-		$this->{face} = [];
-		$this->{face}[0] = $xe - $lwxoff;
-		$this->{face}[1] = $ye - $lwyoff;
-		$this->{face}[2] = $xe + $lwxoff;
-		$this->{face}[3] = $ye + $lwyoff;
-	} # end if
-	
-	# Now find next point and nudge these coords to mitre
-	if( ref $next->{coords} eq 'ARRAY' ) {
-		my( $lwyo2, $lwxo2 );
-		my( $x2, $y2 ) = @{$next->{coords}};
-		if( $x2 == $xe ) {
-			$lwxo2 = $lw / 2;
-			$lwyo2 = 0;
-		} elsif( $y2 == $ye ) {
-			$lwxo2 = 0;
-			$lwyo2 = $lw / 2;
-		} else {
-			my $ln2 = sqrt( ($ye-$y2)**2 + ($x2-$xe)**2 );
-			$lwyo2 = ($x2-$xe) / $ln2  * $lw / 2;
-			$lwxo2 = ($ye-$y2) / $ln2 * $lw / 2;
-		} # end if
-		$next->{face} = [];
-		$next->{face}[0] = $x2 - $lwxo2;
-		$next->{face}[1] = $y2 - $lwyo2;
-		$next->{face}[2] = $x2 + $lwxo2;
-		$next->{face}[3] = $y2 + $lwyo2;
-	
-		# Now get the intersecting coordinates
-		my $mt = ($ye - $ys)/($xe - $xs);
-		my $mn = ($y2 - $ye)/($x2 - $xe);
-		my $bt = $this->{face}[1] - $this->{face}[0] * $mt;
-		my $bn = $next->{face}[1] - $next->{face}[0] * $mn;
-		if( $mt != $mn ) {
-			$this->{face}[0] = ($bn - $bt) / ($mt - $mn);
-		} # end if
-		$this->{face}[1] = $mt * $this->{face}[0] + $bt;
-		$bt = $this->{face}[3] - $this->{face}[2] * $mt;
-		$bn = $next->{face}[3] - $next->{face}[2] * $mn;
-		if( $mt != $mn ) {
-			$this->{face}[2] = ($bn - $bt) / ($mt - $mn);
-		} # end if
-		$this->{face}[3] = $mt * $this->{face}[2] + $bt;
-	} # end if
-
-
-	# Make the top/bottom polygon
-	my $poly = new GD::Polygon;
-	if( ($ys-$ye)/($xe-$xs) > 1 ) {
-		$poly->addPt( $prev->{face}[2], $prev->{face}[3] );
-		$poly->addPt( $this->{face}[2], $this->{face}[3] );
-		$poly->addPt( $this->{face}[2] + $self->{line_depth}, $this->{face}[3] - $self->{line_depth} );
-		$poly->addPt( $prev->{face}[2] + $self->{line_depth}, $prev->{face}[3] - $self->{line_depth} );
-		if( $self->{'3d_shading'} &&  $style == $clr ) {
-			if( ($ys-$ye)/($xe-$xs) > 0 ) {
-				$self->{graph}->filledPolygon( $poly, $self->{'3d_shadows'}[$clr] );
-			} else {
-				$self->{graph}->filledPolygon( $poly, $self->{'3d_highlights'}[$clr] );
-			} # end if
-		} else {
-			$self->{graph}->filledPolygon( $poly, $style );
-		} # end if
-	} else {
-		$poly->addPt( $prev->{face}[0], $prev->{face}[1] );
-		$poly->addPt( $this->{face}[0], $this->{face}[1] );
-		$poly->addPt( $this->{face}[0] + $self->{line_depth}, $this->{face}[1] - $self->{line_depth} );
-		$poly->addPt( $prev->{face}[0] + $self->{line_depth}, $prev->{face}[1] - $self->{line_depth} );
-		if( $self->{'3d_shading'} &&  $style == $clr ) {
-			if( ($ys-$ye)/($xe-$xs) < 0 ) {
-				$self->{graph}->filledPolygon( $poly, $self->{'3d_shadows'}[$clr] );
-			} else {
-				$self->{graph}->filledPolygon( $poly, $self->{'3d_highlights'}[$clr] );
-			} # end if
-		} else {
-			$self->{graph}->filledPolygon( $poly, $style );
-		} # end if
-	} # end if
-	$self->{graph}->polygon( $poly, $self->{fgci} );
-
-	# *** This paints dashed and dotted patterns on the faces of
-	#     the polygons. They don't look very good though. Would it
-	#     be better to extrude the style as well as the lines?
-	#     Otherwise could also be improved by using gdTiled instead of 
-	#     gdStyled and making the tile a transform of the line style
-	#     for each face. [JAW]
-
-	# Make the face polygon
-	$poly = new GD::Polygon;
-	$poly->addPt( $prev->{face}[0], $prev->{face}[1] );
-	$poly->addPt( $this->{face}[0], $this->{face}[1] );
-	$poly->addPt( $this->{face}[2], $this->{face}[3] );
-	$poly->addPt( $prev->{face}[2], $prev->{face}[3] );
-
-	$self->{graph}->filledPolygon( $poly, $style );
-	$self->{graph}->polygon( $poly, $self->{fgci} );
-
-} # end draw line
-
-# ----------------------------------------------------------
-# Sub: draw_legend_marker
-#
-# Args: $dsn, $x, $y
-#	$dsn	The dataset number to draw the marker for
-#	$x  	The x position of the marker
-#	$y  	The y position of the marker
-#
-# Description: Draws the legend marker for the specified 
-# dataset number at the given coordinates
-# ----------------------------------------------------------
-# Date      Modification                              Author
-# ----------------------------------------------------------
-# 2000OCT06 Fixed rendering bugs                          JW
-# ----------------------------------------------------------
-sub draw_legend_marker
-{
-	my $self = shift;
-	my ($n, $x, $y) = @_;
-
-	my $ci = $self->set_clr($self->pick_data_clr($n));
-	my $type = $self->pick_line_type($n);
-
-	$y += int($self->{lg_el_height}/2);
-
-	#  Joe Smith 
-	local($self->{line_width}) = 2;    # Make these show up better
-
-	$self->draw_line(
-		{ coords => [$x, $y] }, 
-		{ coords => [$x + $self->{legend_marker_width}, $y] }, 
-		undef, 
-		$type,
-		$ci
-	);
-
-} # end draw_legend_marker
-
-1;
diff --git a/lib/GD/Graph/linespoints.pm b/lib/GD/Graph/linespoints.pm
deleted file mode 100644
index d913e2c..0000000
--- a/lib/GD/Graph/linespoints.pm
+++ /dev/null
@@ -1,46 +0,0 @@
-#==========================================================================
-#              Copyright (c) 1995-1998 Martien Verbruggen
-#--------------------------------------------------------------------------
-#
-#   Name:
-#       GD::Graph::linespoints.pm
-#
-# $Id: linespoints.pm,v 1.8 2003/02/10 22:12:41 mgjv Exp $
-#
-#==========================================================================
-
-package GD::Graph::linespoints;
- 
-($GD::Graph::linespoints::VERSION) = '$Revision: 1.8 $' =~ /\s([\d.]+)/;
-
-use strict;
- 
-use GD::Graph::axestype;
-use GD::Graph::lines;
-use GD::Graph::points;
- 
-# Even though multiple inheritance is not really a good idea,
-# since lines and points have the same parent class, I will do it here,
-# because I need the functionality of the markers and the line types
-
-@GD::Graph::linespoints::ISA = qw(GD::Graph::lines GD::Graph::points);
-
-# PRIVATE
-
-sub draw_data_set
-{
-    my $self = shift;
-
-    $self->GD::Graph::points::draw_data_set(@_) or return;
-    $self->GD::Graph::lines::draw_data_set(@_);
-}
-
-sub draw_legend_marker
-{
-    my $self = shift;
-
-    $self->GD::Graph::points::draw_legend_marker(@_);
-    $self->GD::Graph::lines::draw_legend_marker(@_);
-}
-
-"Just another true value";
diff --git a/lib/GD/Graph/mixed.pm b/lib/GD/Graph/mixed.pm
deleted file mode 100644
index daf192f..0000000
--- a/lib/GD/Graph/mixed.pm
+++ /dev/null
@@ -1,99 +0,0 @@
-#==========================================================================
-#              Copyright (c) 1995-1998 Martien Verbruggen
-#--------------------------------------------------------------------------
-#
-#   Name:
-#       GD::Graph::mixed.pm
-#
-# $Id: mixed.pm,v 1.12 2003/02/10 22:12:41 mgjv Exp $
-#
-#==========================================================================
-
-package GD::Graph::mixed;
- 
-($GD::Graph::mixed::VERSION) = '$Revision: 1.12 $' =~ /\s([\d.]+)/;
-
-use strict;
- 
-use GD::Graph::axestype;
-use GD::Graph::lines;
-use GD::Graph::points;
-use GD::Graph::linespoints;
-use GD::Graph::bars;
-use GD::Graph::area;
-use Carp;
- 
-# Even though multiple inheritance is not really a good idea, I will
-# do it here, because I need the functionality of the markers and the
-# line types We'll include axestype as the first one, to make sure
-# that's where we look first for methods.
-
-@GD::Graph::mixed::ISA = qw( 
-    GD::Graph::axestype 
-    GD::Graph::bars
-    GD::Graph::lines 
-    GD::Graph::points 
-);
-
-sub initialise
-{
-    my $self = shift;
-    $self->SUPER::initialise();
-}
-
-sub correct_width
-{
-    my $self = shift;
-
-    return $self->{correct_width} if defined $self->{correct_width};
-
-    for my $type ($self->{default_type}, @{$self->{types}})
-    {
-        return 1 if $type eq 'bars';
-    }
-}
-
-sub draw_data_set
-{
-    my $self = shift;
-    my $ds   = $_[0];
-
-    my $rc;
-
-    my $type = $self->{types}->[$ds-1] || $self->{default_type};
-
-    # Try to execute the draw_data_set function in the package
-    # specified by type
-    $rc = eval '$self->GD::Graph::'.$type.'::draw_data_set(@_)';
-
-    # If we fail, we try it in the package specified by the
-    # default_type, and warn the user
-    if ($@)
-    {
-        carp "Set $ds, unknown type $type, assuming $self->{default_type}";
-	#carp "Error message: $@";
-
-        $rc = eval '$self->GD::Graph::'.
-            $self->{default_type}.'::draw_data_set(@_)';
-    }
-
-    # If even that fails, we bail out
-    croak "Set $ds: unknown default type $self->{default_type}" if $@;
-
-    return $rc;
-}
-
-sub draw_legend_marker
-{
-    my $self = shift;
-    my $ds = $_[0];
-
-    my $type = $self->{types}->[$ds-1] || $self->{default_type};
-
-    eval '$self->GD::Graph::'.$type.'::draw_legend_marker(@_)';
-
-    eval '$self->GD::Graph::'.
-        $self->{default_type}.'::draw_legend_marker(@_)' if $@;
-}
-
-"Just another true value";
diff --git a/lib/GD/Graph/pie.pm b/lib/GD/Graph/pie.pm
deleted file mode 100644
index a945ba0..0000000
--- a/lib/GD/Graph/pie.pm
+++ /dev/null
@@ -1,446 +0,0 @@
-#==========================================================================
-#              Copyright (c) 1995-1998 Martien Verbruggen
-#--------------------------------------------------------------------------
-#
-#   Name:
-#       GD::Graph::pie.pm
-#
-# $Id: pie.pm,v 1.20 2003/02/10 22:12:41 mgjv Exp $
-#
-#==========================================================================
-
-package GD::Graph::pie;
-
-($GD::Graph::pie::VERSION) = '$Revision: 1.20 $' =~ /\s([\d.]+)/;
-
-use strict;
-
-use constant PI => 4 * atan2(1,1);
-
-use GD;
-use GD::Graph;
-use GD::Graph::utils qw(:all);
-use GD::Graph::colour qw(:colours :lists);
-use GD::Text::Align;
-use Carp;
-
-@GD::Graph::pie::ISA = qw( GD::Graph );
-
-my $ANGLE_OFFSET = 90;
-
-my %Defaults = (
- 
-    # Set the height of the pie.
-    # Because of the dependency of this on runtime information, this
-    # is being set in GD::Graph::pie::initialise
- 
-    #   pie_height => _round(0.1*${'width'}),
-    pie_height  => undef,
- 
-    # Do you want a 3D pie?
-    '3d'        => 1,
- 
-    # The angle at which to start the first data set
-    # 0 is at the front/bottom
-    start_angle => 0,
-
-    # Angle below which a label on a pie slice is suppressed.
-    suppress_angle => 0,    # CONTRIB idea ryan 
-
-    # and some public attributes without defaults
-    label       => undef,
-
-    # This misnamed attribute is used for pie marker colours
-    axislabelclr => 'black',
-);
-
-# PRIVATE
-sub _has_default { 
-    my $self = shift;
-    my $attr = shift || return;
-    exists $Defaults{$attr} || $self->SUPER::_has_default($attr);
-}
-
-sub initialise
-{
-    my $self = shift;
-    $self->SUPER::initialise();
-    while (my($key, $val) = each %Defaults)
-        { $self->{$key} = $val }
-    $self->set( pie_height => _round(0.1 * $self->{height}) );
-    $self->set_value_font(gdTinyFont);
-    $self->set_label_font(gdSmallFont);
-}
-
-# PUBLIC methods, documented in pod
-sub plot
-{
-    my $self = shift;
-    my $data = shift;
-
-    $self->check_data($data)        or return;
-    $self->init_graph()             or return;
-    $self->setup_text()             or return;
-    $self->setup_coords()           or return;
-    $self->draw_text()              or return;
-    $self->draw_pie()               or return;
-    $self->draw_data()              or return;
-
-    return $self->{graph};
-}
-
-sub set_label_font # (fontname)
-{
-    my $self = shift;
-    $self->_set_font('gdta_label', @_) or return;
-    $self->{gdta_label}->set_align('bottom', 'center');
-}
-
-sub set_value_font # (fontname)
-{
-    my $self = shift;
-    $self->_set_font('gdta_value', @_) or return;
-    $self->{gdta_value}->set_align('center', 'center');
-}
-
-# Inherit defaults() from GD::Graph
-
-# inherit checkdata from GD::Graph
-
-# Setup the coordinate system and colours, calculate the
-# relative axis coordinates in respect to the canvas size.
-
-sub setup_coords()
-{
-    my $self = shift;
-
-    # Make sure we're not reserving space we don't need.
-    $self->{'3d'} = 0           if     $self->{pie_height} <= 0;
-    $self->set(pie_height => 0) unless $self->{'3d'};
-
-    my $tfh = $self->{title} ? $self->{gdta_title}->get('height') : 0;
-    my $lfh = $self->{label} ? $self->{gdta_label}->get('height') : 0;
-
-    # Calculate the bounding box for the pie, and
-    # some width, height, and centre parameters
-    $self->{bottom} = 
-        $self->{height} - $self->{pie_height} - $self->{b_margin} -
-        ( $lfh ? $lfh + $self->{text_space} : 0 );
-    $self->{top} = 
-        $self->{t_margin} + ( $tfh ? $tfh + $self->{text_space} : 0 );
-
-    return $self->_set_error('Vertical size too small') 
-        if $self->{bottom} - $self->{top} <= 0;
-
-    $self->{left} = $self->{l_margin};
-    $self->{right} = $self->{width} - $self->{r_margin};
-
-    return $self->_set_error('Horizontal size too small')
-        if $self->{right} - $self->{left} <= 0;
-
-    $self->{w} = $self->{right}  - $self->{left};
-    $self->{h} = $self->{bottom} - $self->{top};
-
-    $self->{xc} = ($self->{right}  + $self->{left})/2; 
-    $self->{yc} = ($self->{bottom} + $self->{top})/2;
-
-    return $self;
-}
-
-# inherit open_graph from GD::Graph
-
-# Setup the parameters for the text elements
-sub setup_text
-{
-    my $self = shift;
-
-    if ( $self->{title} ) 
-    {
-        #print "'$s->{title}' at ($s->{xc},$s->{t_margin})\n";
-        $self->{gdta_title}->set(colour => $self->{tci});
-        $self->{gdta_title}->set_text($self->{title});
-    }
-
-    if ( $self->{label} ) 
-    {
-        $self->{gdta_label}->set(colour => $self->{lci});
-        $self->{gdta_label}->set_text($self->{label});
-    }
-
-    $self->{gdta_value}->set(colour => $self->{alci});
-
-    return $self;
-}
-
-# Put the text on the canvas.
-sub draw_text
-{
-    my $self = shift;
-
-    $self->{gdta_title}->draw($self->{xc}, $self->{t_margin}) 
-        if $self->{title}; 
-    $self->{gdta_label}->draw($self->{xc}, $self->{height} - $self->{b_margin})
-        if $self->{label};
-    
-    return $self;
-}
-
-# draw the pie, without the data slices
-sub draw_pie
-{
-    my $self = shift;
-
-    my $left = $self->{xc} - $self->{w}/2;
-
-    $self->{graph}->arc(
-        $self->{xc}, $self->{yc}, 
-        $self->{w}, $self->{h},
-        0, 360, $self->{acci}
-    );
-
-    $self->{graph}->arc(
-        $self->{xc}, $self->{yc} + $self->{pie_height}, 
-        $self->{w}, $self->{h},
-        0, 180, $self->{acci}
-    ) if ( $self->{'3d'} );
-
-    $self->{graph}->line(
-        $left, $self->{yc},
-        $left, $self->{yc} + $self->{pie_height}, 
-        $self->{acci}
-    );
-
-    $self->{graph}->line(
-        $left + $self->{w}, $self->{yc},
-        $left + $self->{w}, $self->{yc} + $self->{pie_height}, 
-        $self->{acci}
-    );
-
-    return $self;
-}
-
-# Draw the data slices
-
-sub draw_data
-{
-    my $self = shift;
-
-    my $total = 0;
-    my @values = $self->{_data}->y_values(1);   # for now, only one pie..
-    for (@values)
-    {   
-        $total += $_ 
-    }
-
-    return $self->_set_error("Pie data total is <= 0") 
-        unless $total > 0;
-
-    my $ac = $self->{acci};         # Accent colour
-    my $pb = $self->{start_angle};
-
-    for (my $i = 0; $i < @values; $i++)
-    {
-        # Set the data colour
-        my $dc = $self->set_clr_uniq($self->pick_data_clr($i + 1));
-
-        # Set the angles of the pie slice
-        # Angle 0 faces down, positive angles are clockwise 
-        # from there.
-        #         ---
-        #        /   \
-        #        |    |
-        #        \ | /
-        #         ---
-        #          0
-        # $pa/$pb include the start_angle (so if start_angle
-        # is 90, there will be no pa/pb < 90.
-        my $pa = $pb;
-        $pb += my $slice_angle = 360 * $values[$i]/$total;
-
-        # Calculate the end points of the lines at the boundaries of
-        # the pie slice
-        my ($xe, $ye) = cartesian(
-                $self->{w}/2, $pa, 
-                $self->{xc}, $self->{yc}, $self->{h}/$self->{w}
-            );
-
-        $self->{graph}->line($self->{xc}, $self->{yc}, $xe, $ye, $ac);
-
-        # Draw the lines on the front of the pie
-        $self->{graph}->line($xe, $ye, $xe, $ye + $self->{pie_height}, $ac)
-            if in_front($pa) && $self->{'3d'};
-
-        # Make an estimate of a point in the middle of the pie slice
-        # And fill it
-        ($xe, $ye) = cartesian(
-                3 * $self->{w}/8, ($pa+$pb)/2,
-                $self->{xc}, $self->{yc}, $self->{h}/$self->{w}
-            );
-
-        $self->{graph}->fillToBorder($xe, $ye, $ac, $dc);
-
-        # If it's 3d, colour the front ones as well
-        #
-        # if one slice is very large (>180 deg) then we will need to
-        # fill it twice.  sbonds.
-        #
-        # Independently noted and fixed by Jeremy Wadsack, in a slightly
-        # different way.
-        if ($self->{'3d'}) 
-        {
-            foreach my $fill ($self->_get_pie_front_coords($pa, $pb)) 
-            {
-                $self->{graph}->fillToBorder(
-                    $fill->[0], $fill->[1] + $self->{pie_height}/2, 
-                    $ac, $dc);
-            }
-        }
-    }
-
-    # CONTRIB Jeremy Wadsack
-    #
-    # Large text, sticking out over the pie edge, could cause 3D pies to
-    # fill improperly: Drawing the text for a given slice before the
-    # next slice was drawn and filled could make the slice boundary
-    # disappear, causing the fill colour to flow out.  With this
-    # implementation, all the text is on top of the pie.
-
-    $pb = $self->{start_angle};
-    for (my $i = 0; $i < @values; $i++)
-    {
-        next unless $values[$i];
-
-        my $pa = $pb;
-        $pb += my $slice_angle = 360 * $values[$i]/$total;
-
-        next if $slice_angle <= $self->{suppress_angle};
-
-        my ($xe, $ye) = 
-            cartesian(
-                3 * $self->{w}/8, ($pa+$pb)/2,
-                $self->{xc}, $self->{yc}, $self->{h}/$self->{w}
-            );
-
-        $self->put_slice_label($xe, $ye, $self->{_data}->get_x($i));
-    }
-
-    return $self;
-
-} #GD::Graph::pie::draw_data
-
-sub _get_pie_front_coords # (angle 1, angle 2)
-{
-    my $self = shift;
-    my $pa = level_angle(shift);
-    my $pb = level_angle(shift);
-    my @fills = ();
-
-    if (in_front($pa))
-    {
-        if (in_front($pb))
-        {
-            # both in front
-            # don't do anything
-            # Ah, but if this wraps all the way around the back
-            # then both pieces of the front need to be filled.
-            # sbonds.
-            if ($pa > $pb ) 
-            {
-                # This takes care of the left bit on the front
-                # Since we know exactly where we are, and in which
-                # direction this works, we can just get the coordinates
-                # for $pa.
-                my ($x, $y) = cartesian(
-                    $self->{w}/2, $pa,
-                    $self->{xc}, $self->{yc}, $self->{h}/$self->{w}
-                );
-
-                # and move one pixel to the left, but only if we don't
-                # fall out of the pie!.
-                push @fills, [$x - 1, $y]
-                    if $x - 1 > $self->{xc} - $self->{w}/2;
-
-                # Reset $pa to the right edge of the front arc, to do
-                # the right bit on the front.
-                $pa = level_angle(-$ANGLE_OFFSET);
-            }
-        }
-        else
-        {
-            # start in front, end in back
-            $pb = $ANGLE_OFFSET;
-        }
-    }
-    else
-    {
-        if (in_front($pb))
-        {
-            # start in back, end in front
-            $pa = $ANGLE_OFFSET - 180;
-        }
-        else
-        {
-            # both in back
-            return;
-        }
-    }
-
-    my ($x, $y) = cartesian(
-        $self->{w}/2, ($pa + $pb)/2,
-        $self->{xc}, $self->{yc}, $self->{h}/$self->{w}
-    );
-
-    push @fills, [$x, $y];
-
-    return @fills;
-}
-
-# return true if this angle is on the front of the pie
-# XXX UGLY! We need to leave a slight room for error because of rounding
-# problems
-sub in_front
-{
-    my $a = level_angle(shift);
-    return 
-        $a > ($ANGLE_OFFSET - 180 + 0.00000001) && 
-        $a < $ANGLE_OFFSET - 0.000000001;
-}
-
-# XXX Ugh! I need to fix this. See the GD::Text module for better ways
-# of doing this.
-# return a value for angle between -180 and 180
-sub level_angle # (angle)
-{
-    my $a = shift;
-    return level_angle($a-360) if ( $a > 180 );
-    return level_angle($a+360) if ( $a <= -180 );
-    return $a;
-}
-
-# put the slice label on the pie
-sub put_slice_label
-{
-    my $self = shift;
-    my ($x, $y, $label) = @_;
-
-    return unless defined $label;
-
-    $self->{gdta_value}->set_text($label);
-    $self->{gdta_value}->draw($x, $y);
-}
-
-# return x, y coordinates from input
-# radius, angle, center x and y and a scaling factor (height/width)
-#
-# $ANGLE_OFFSET is used to define where 0 is meant to be
-sub cartesian
-{
-    my ($r, $phi, $xi, $yi, $cr) = @_; 
-
-    return (
-        $xi + $r * cos(PI * ($phi + $ANGLE_OFFSET)/180), 
-        $yi + $cr * $r * sin(PI * ($phi + $ANGLE_OFFSET)/180)
-    )
-}
-
-"Just another true value";
diff --git a/lib/GD/Graph/pie3d.pm b/lib/GD/Graph/pie3d.pm
deleted file mode 100644
index f1b0a76..0000000
--- a/lib/GD/Graph/pie3d.pm
+++ /dev/null
@@ -1,331 +0,0 @@
-############################################################
-#
-# Module: GD::Graph::pie3d
-#
-# Description: 
-# This is merely a wrapper around GD::Graph::pie that forces 
-# the 3d option for pie charts.
-#
-# Created: 2000.Jan.19 by Jeremy Wadsack for Wadsack-Allen Digital Group
-# 	Copyright (C) 2000,2001 Wadsack-Allen. All rights reserved.
-############################################################
-# Date      Modification                               Author
-# ----------------------------------------------------------
-# 2000APR18 Modified to be compatible w/ GD::Graph 1.30   JW
-# 2000APR24 Set default slice label color to black        JW
-# 2001Feb16 Added support for a legend                    JW
-############################################################
-package GD::Graph::pie3d;
-
-use strict;
-use GD;
-use GD::Graph;
-use GD::Graph::pie;
-use GD::Graph::utils qw(:all);
-use Carp;
-
-@GD::Graph::pie3d::ISA = qw( GD::Graph::pie );
-$GD::Graph::pie3d::VERSION = '0.63';
-
-my %Defaults = (
-	'3d'         => 1,
-	axislabelclr => 'black',	# values on slices. black because default colors use dblue
-
-	# Size of the legend markers
-	legend_marker_height	=> 8,
-	legend_marker_width	=> 12,
-	legend_spacing			=> 4,
-	legend_placement		=> 'BC',		# '[BR][LCR]'
-	lg_cols					=> undef,
-	legend_frame_margin	=> 4,
-	legend_frame_size		=> undef,
-);
-
-# PRIVATE
-# Have to include because this is a different %Defaults hash
-sub _has_default { 
-	my $self = shift;
-	my $attr = shift || return;
-	exists $Defaults{$attr} || $self->SUPER::_has_default($attr);
-}
-
-sub initialise {
-	my $self = shift;
-	my $rc = $self->SUPER::initialise();
-
-	while( my($key, $val) = each %Defaults ) { 
-		$self->{$key} = $val;
-	} # end while
-
-	$self->set_legend_font(GD::gdTinyFont);
-	return $rc;
-} # end initialise
-
-# Add lengend calc and draw code
-sub plot
-{
-	my $self = shift;
-	my $data = shift;
-
-	$self->check_data($data) 		or return;
-	$self->init_graph() 			or return;
-	$self->setup_text()				or return;
-	$self->setup_legend();
-	$self->setup_coords() 			or return;
-	$self->{b_margin} += 4 if $self->{label};		# Kludge for descenders
-	$self->draw_text()				or return;
-	$self->draw_pie()				or return;
-	$self->draw_data()				or return;
-	$self->draw_legend();
-
-	return $self->{graph};
-}
-
-# Added legend stuff
-sub setup_text 
-{
-	my $self = shift;
-
-	my $rc = $self->SUPER::setup_text( @_ );
-	
-	$self->{gdta_legend}->set(colour => $self->{legendci});
-	$self->{gdta_legend}->set_align('top', 'left');
-	$self->{lgfh} = $self->{gdta_legend}->get('height');
-	
-	return $rc
-} # end setup_text
-
-# Inherit everything else from GD::Graph::pie
-
-
-# Legend Support. Added 16.Feb.2001 - JW/WADG
-
-sub set_legend # List of legend keys
-{
-	my $self = shift;
-	$self->{legend} = [@_];
-}
-
-sub set_legend_font # (font name)
-{
-	my $self = shift;
-	$self->_set_font('gdta_legend', @_);
-}
-
-
-
-#
-# Legend
-#
-sub setup_legend
-{
-	my $self = shift;
-
-	return unless defined $self->{legend};
-
-	my $maxlen = 0;
-	my $num = 0;
-
-	# Save some variables
-	$self->{r_margin_abs} = $self->{r_margin};
-	$self->{b_margin_abs} = $self->{b_margin};
-
-	foreach my $legend (@{$self->{legend}})
-	{
-		if (defined($legend) and $legend ne "")
-		{
-			$self->{gdta_legend}->set_text($legend);
-			my $len = $self->{gdta_legend}->get('width');
-			$maxlen = ($maxlen > $len) ? $maxlen : $len;
-			$num++;
-		}
-		# Legend for Pie goes over first set, and all points
-		last if $num >= $self->{_data}->num_points;
-	}
-
-	$self->{lg_num} = $num;
-
-	# calculate the height and width of each element
-	my $legend_height = _max($self->{lgfh}, $self->{legend_marker_height});
-
-	$self->{lg_el_width} = 
-		$maxlen + $self->{legend_marker_width} + 3 * $self->{legend_spacing};
-	$self->{lg_el_height} = $legend_height + 2 * $self->{legend_spacing};
-
-	my ($lg_pos, $lg_align) = split(//, $self->{legend_placement});
-
-	if ($lg_pos eq 'R')
-	{
-		# Always work in one column
-		$self->{lg_cols} = 1;
-		$self->{lg_rows} = $num;
-
-		# Just for completeness, might use this in later versions
-		$self->{lg_x_size} = $self->{lg_cols} * $self->{lg_el_width};
-		$self->{lg_y_size} = $self->{lg_rows} * $self->{lg_el_height};
-
-		# Adjust the right margin for the rest of the graph
-		$self->{r_margin} += $self->{lg_x_size};
-
-		# Adjust for frame if defined
-		if( $self->{legend_frame_size} ) {
-			$self->{r_margin} += 2 * ($self->{legend_frame_margin} + $self->{legend_frame_size});
-		} # end if;
-
-		# Set the x starting point
-		$self->{lg_xs} = $self->{width} - $self->{r_margin};
-
-		# Set the y starting point, depending on alignment
-		if ($lg_align eq 'T')
-		{
-			$self->{lg_ys} = $self->{t_margin};
-		}
-		elsif ($lg_align eq 'B')
-		{
-			$self->{lg_ys} = $self->{height} - $self->{b_margin} - 
-				$self->{lg_y_size};
-		}
-		else # default 'C'
-		{
-			my $height = $self->{height} - $self->{t_margin} - 
-				$self->{b_margin};
-
-			$self->{lg_ys} = 
-				int($self->{t_margin} + $height/2 - $self->{lg_y_size}/2) ;
-		}
-	}
-	else # 'B' is the default
-	{
-		# What width can we use
-		my $width = $self->{width} - $self->{l_margin} - $self->{r_margin};
-
-		(!defined($self->{lg_cols})) and 
-			$self->{lg_cols} = int($width/$self->{lg_el_width});
-		
-		$self->{lg_cols} = _min($self->{lg_cols}, $num);
-
-		$self->{lg_rows} = 
-			int($num / $self->{lg_cols}) + (($num % $self->{lg_cols}) ? 1 : 0);
-
-		$self->{lg_x_size} = $self->{lg_cols} * $self->{lg_el_width};
-		$self->{lg_y_size} = $self->{lg_rows} * $self->{lg_el_height};
-
-		# Adjust the bottom margin for the rest of the graph
-		$self->{b_margin} += $self->{lg_y_size};
-		# Adjust for frame if defined
-		if( $self->{legend_frame_size} ) {
-			$self->{b_margin} += 2 * ($self->{legend_frame_margin} + $self->{legend_frame_size});
-		} # end if;
-
-		# Set the y starting point
-		$self->{lg_ys} = $self->{height} - $self->{b_margin};
-
-		# Set the x starting point, depending on alignment
-		if ($lg_align eq 'R')
-		{
-			$self->{lg_xs} = $self->{width} - $self->{r_margin} - 
-				$self->{lg_x_size};
-		}
-		elsif ($lg_align eq 'L')
-		{
-			$self->{lg_xs} = $self->{l_margin};
-		}
-		else # default 'C'
-		{
-			$self->{lg_xs} =  
-				int($self->{l_margin} + $width/2 - $self->{lg_x_size}/2);
-		}
-	}
-}
-
-sub draw_legend
-{
-	my $self = shift;
-
-	return unless defined $self->{legend};
-
-	my $xl = $self->{lg_xs} + $self->{legend_spacing};
-	my $y  = $self->{lg_ys} + $self->{legend_spacing} - 1;
-
-	# If there's a frame, offset by the size and margin
-	$xl += $self->{legend_frame_margin} + $self->{legend_frame_size} if $self->{legend_frame_size};
-	$y += $self->{legend_frame_margin} + $self->{legend_frame_size} if $self->{legend_frame_size};
-
-	my $i = 0;
-	my $row = 1;
-	my $x = $xl;	# start position of current element
-
-	foreach my $legend (@{$self->{legend}})
-	{
-		$i++;
-		# Legend for Pie goes over first set, and all points
-		last if $i > $self->{_data}->num_points;
-
-		my $xe = $x;	# position within an element
-
-		next unless defined($legend) && $legend ne "";
-
-		$self->draw_legend_marker($i, $xe, $y);
-
-		$xe += $self->{legend_marker_width} + $self->{legend_spacing};
-		my $ys = int($y + $self->{lg_el_height}/2 - $self->{lgfh}/2);
-
-		$self->{gdta_legend}->set_text($legend);
-		$self->{gdta_legend}->draw($xe, $ys);
-
-		$x += $self->{lg_el_width};
-
-		if (++$row > $self->{lg_cols})
-		{
-			$row = 1;
-			$y += $self->{lg_el_height};
-			$x = $xl;
-		}
-	}
-	
-	# If there's a frame, draw it now
-	if( $self->{legend_frame_size} ) {
-		$x = $self->{lg_xs} + $self->{legend_spacing};
-		$y = $self->{lg_ys} + $self->{legend_spacing} - 1;
-		
-		for $i ( 0 .. $self->{legend_frame_size} - 1 ) {
-			$self->{graph}->rectangle(
-				$x + $i,
-				$y + $i, 
-				$x + $self->{lg_x_size} + 2 * $self->{legend_frame_margin} - $i - 1,
-				$y + $self->{lg_y_size} + 2 * $self->{legend_frame_margin} - $i - 1,
-				$self->{acci},
-			);
-		} # end for
-	} # end if
-	
-}
-
-sub draw_legend_marker # data_set_number, x, y
-{
-	my $s = shift;
-	my $n = shift;
-	my $x = shift;
-	my $y = shift;
-
-	my $g = $s->{graph};
-
-	my $ci = $s->set_clr($s->pick_data_clr($n));
-
-	$y += int($s->{lg_el_height}/2 - $s->{legend_marker_height}/2);
-
-	$g->filledRectangle(
-		$x, $y, 
-		$x + $s->{legend_marker_width}, $y + $s->{legend_marker_height},
-		$ci
-	);
-
-	$g->rectangle(
-		$x, $y, 
-		$x + $s->{legend_marker_width}, $y + $s->{legend_marker_height},
-		$s->{acci}
-	);
-}
-
-
-1;
diff --git a/lib/GD/Graph/points.pm b/lib/GD/Graph/points.pm
deleted file mode 100644
index 43b6825..0000000
--- a/lib/GD/Graph/points.pm
+++ /dev/null
@@ -1,183 +0,0 @@
-#==========================================================================
-#              Copyright (c) 1995-1998 Martien Verbruggen
-#--------------------------------------------------------------------------
-#
-#   Name:
-#       GD::Graph::points.pm
-#
-# $Id: points.pm,v 1.13 2003/02/10 22:12:41 mgjv Exp $
-#
-#==========================================================================
-
-package GD::Graph::points;
-
-($GD::Graph::points::VERSION) = '$Revision: 1.13 $' =~ /\s([\d.]+)/;
-
-use strict;
- 
-use GD::Graph::axestype;
-use GD::Graph::utils qw(:all);
-
-@GD::Graph::points::ISA = qw( GD::Graph::axestype );
-
-# PRIVATE
-sub draw_data_set
-{
-    my $self = shift;
-    my $ds = shift;
-
-    my @values = $self->{_data}->y_values($ds) or
-        return $self->_set_error("Impossible illegal data set: $ds",
-            $self->{_data}->error);
-
-    # Pick a colour
-    my $dsci = $self->set_clr($self->pick_data_clr($ds));
-    my $type = $self->pick_marker($ds);
-
-    for (my $i = 0; $i < @values; $i++)
-    {
-        next unless defined $values[$i];
-        my ($xp, $yp);
-        if (defined($self->{x_min_value}) && defined($self->{x_max_value}))
-        {
-            ($xp, $yp) = $self->val_to_pixel(
-                $self->{_data}->get_x($i), $values[$i], $ds);
-        }
-        else    
-        {
-            ($xp, $yp) = $self->val_to_pixel($i+1, $values[$i], $ds);
-        }
-        $self->marker($xp, $yp, $type, $dsci );
-        $self->{_hotspots}->[$ds]->[$i] = 
-            ['rect', $self->marker_coordinates($xp, $yp)];
-    }
-
-    return $ds;
-}
-
-# Pick a marker type
-
-sub pick_marker # number
-{
-    my $self = shift;
-    my $num = shift;
-
-    ref $self->{markers} ?
-        $self->{markers}[ $num % (1 + $#{$self->{markers}}) - 1 ] :
-        ($num % 8) || 8;
-}
-
-# Draw a marker
-
-sub marker_coordinates
-{
-    my $self = shift;
-    my ($xp, $yp) = @_;
-    return (
-        $xp - $self->{marker_size},
-        $xp + $self->{marker_size},
-        $yp + $self->{marker_size},
-        $yp - $self->{marker_size},
-    );
-}
-
-sub marker # $xp, $yp, $type, $colourindex
-{
-    my $self = shift;
-    my ($xp, $yp, $mtype, $mclr) = @_;
-    return unless defined $mclr;
-
-    my ($l, $r, $b, $t) = $self->marker_coordinates($xp, $yp);
-
-    MARKER: {
-
-        ($mtype == 1) && do 
-        { # Square, filled
-            $self->{graph}->filledRectangle($l, $t, $r, $b, $mclr);
-            last MARKER;
-        };
-        ($mtype == 2) && do 
-        { # Square, open
-            $self->{graph}->rectangle($l, $t, $r, $b, $mclr);
-            last MARKER;
-        };
-        ($mtype == 3) && do 
-        { # Cross, horizontal
-            $self->{graph}->line($l, $yp, $r, $yp, $mclr);
-            $self->{graph}->line($xp, $t, $xp, $b, $mclr);
-            last MARKER;
-        };
-        ($mtype == 4) && do 
-        { # Cross, diagonal
-            $self->{graph}->line($l, $b, $r, $t, $mclr);
-            $self->{graph}->line($l, $t, $r, $b, $mclr);
-            last MARKER;
-        };
-        ($mtype == 5) && do 
-        { # Diamond, filled
-            $self->{graph}->line($l, $yp, $xp, $t, $mclr);
-            $self->{graph}->line($xp, $t, $r, $yp, $mclr);
-            $self->{graph}->line($r, $yp, $xp, $b, $mclr);
-            $self->{graph}->line($xp, $b, $l, $yp, $mclr);
-            $self->{graph}->fillToBorder($xp, $yp, $mclr, $mclr);
-            last MARKER;
-        };
-        ($mtype == 6) && do 
-        { # Diamond, open
-            $self->{graph}->line($l, $yp, $xp, $t, $mclr);
-            $self->{graph}->line($xp, $t, $r, $yp, $mclr);
-            $self->{graph}->line($r, $yp, $xp, $b, $mclr);
-            $self->{graph}->line($xp, $b, $l, $yp, $mclr);
-            last MARKER;
-        };
-        ($mtype == 7) && do 
-        { # Circle, filled
-            $self->{graph}->arc($xp, $yp, 2 * $self->{marker_size},
-                         2 * $self->{marker_size}, 0, 360, $mclr);
-            $self->{graph}->fillToBorder($xp, $yp, $mclr, $mclr);
-            last MARKER;
-        };
-        ($mtype == 8) && do 
-        { # Circle, open
-            $self->{graph}->arc($xp, $yp, 2 * $self->{marker_size},
-                         2 * $self->{marker_size}, 0, 360, $mclr);
-            last MARKER;
-        };
-        ($mtype == 9) && do
-        { # Horizontal line
-            $self->{graph}->line($l, $yp, $r, $yp, $mclr);
-            last MARKER;
-        };
-        ($mtype == 10) && do
-        { # vertical line
-            $self->{graph}->line($xp, $t, $xp, $b, $mclr);
-            last MARKER;
-        };
-    }
-}
-
-sub draw_legend_marker
-{
-    my $self = shift;
-    my $n = shift;
-    my $x = shift;
-    my $y = shift;
-
-    my $ci = $self->set_clr($self->pick_data_clr($n));
-
-    my $old_ms = $self->{marker_size};
-    my $ms = _min($self->{legend_marker_height}, $self->{legend_marker_width});
-
-    ($self->{marker_size} > $ms/2) and $self->{marker_size} = $ms/2;
-    
-    $x += int($self->{legend_marker_width}/2);
-    $y += int($self->{lg_el_height}/2);
-
-    $n = $self->pick_marker($n);
-
-    $self->marker($x, $y, $n, $ci);
-
-    $self->{marker_size} = $old_ms;
-}
-
-"Just another true value";
diff --git a/lib/GD/Graph/utils.pm b/lib/GD/Graph/utils.pm
deleted file mode 100644
index b24fc26..0000000
--- a/lib/GD/Graph/utils.pm
+++ /dev/null
@@ -1,49 +0,0 @@
-#==========================================================================
-#              Copyright (c) 1995-1999 Martien Verbruggen
-#--------------------------------------------------------------------------
-#
-#   Name:
-#       GD::Graph::utils.pm
-#
-#   Description:
-#       Package of general utilities.
-#
-# $Id: utils.pm,v 1.7 2003/02/10 22:12:41 mgjv Exp $
-#
-#==========================================================================
- 
-package GD::Graph::utils;
-
-($GD::Graph::utils::VERSION) = '$Revision: 1.7 $' =~ /\s([\d.]+)/;
-
-use strict;
-
-use vars qw( @EXPORT_OK %EXPORT_TAGS );
-require Exporter;
-
-@GD::Graph::utils::ISA = qw( Exporter );
- 
-@EXPORT_OK = qw(_max _min _round);
-%EXPORT_TAGS = (all => [qw(_max _min _round)]);
-
-sub _max { 
-    my ($a, $b) = @_; 
-    return undef    if (!defined($a) and !defined($b));
-    return $a       if (!defined($b));
-    return $b       if (!defined($a));
-    ( $a >= $b ) ? $a : $b; 
-}
-
-sub _min { 
-    my ($a, $b) = @_; 
-    return undef    if (!defined($a) and !defined($b));
-    return $a       if (!defined($b));
-    return $b       if (!defined($a));
-    ( $a <= $b ) ? $a : $b; 
-}
-
-sub _round { sprintf "%.0f", shift }
-
-sub version { $GD::Graph::utils::VERSION }
-
-"Just another true value";
diff --git a/lib/GD/Graph3d.pm b/lib/GD/Graph3d.pm
deleted file mode 100644
index 3795689..0000000
--- a/lib/GD/Graph3d.pm
+++ /dev/null
@@ -1,157 +0,0 @@
-#==========================================================================
-# Module: GD::Graph3d
-#
-# Copyright (C) 2000 Wadsack-Allen. All Rights Reserved.
-#
-#--------------------------------------------------------------------------
-# Date      Modification                                             Author
-# -------------------------------------------------------------------------
-# 08Nov2001 Re-sourced to use standard module files and structure.
-#           The package is now GD-Graph3d which us what people expect    JW
-#==========================================================================
-package GD::Graph3d;
-$GD::Graph3d::VERSION = '0.63';
-1;
-
-=head1 NAME
-
-GD::Graph3D - Create 3D Graphs with GD and GD::Graph
-
-=head1 SYNOPSIS
-
-	use GD::Graph::moduleName;
-	my @data = ( 
-	   ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
-	   [ 1203,  3500,  3973,  2859,  3012,  3423,  1230]
-	);
-	my $graph = new GD::Graph::moduleName( 400, 300 );
-	$graph->set( 
-		x_label           => 'Day of the week',
-		y_label           => 'Number of hits',
-		title             => 'Daily Summary of Web Site',
-	);
-	my $gd = $graph->plot( \@data );
-
-Where I is one of C, C or C. 
-
-=head1 DESCRIPTION
-
-This is the GD::Graph3d extensions module. It provides 3D graphs for the 
-GD::Graph module by Martien Verbruggen, which in turn generates graph 
-using Lincoln Stein's GD.pm.
-
-You use these modules just as you would any of the GD::Graph modules, except 
-that they generate 3d-looking graphs. Each graph type is described below 
-with only the options that are unique to the 3d version. The modules are 
-based on their 2d versions (e.g. GD::Graph::bars3d works like 
-GD::Graph::bars), and support all the options in those. Make sure to read 
-the documentation on GD::Graph.
-
-=over 4
-
-=item GD::Graph::pie3d
-
-This is merely a wrapper around GD::Graph::pie for consistency. It also 
-sets 3d pie mode by default (which GD::Graph does as of version 1.22).
-All options are exactly as in GD::Graph::pie.
-
-=item GD::Graph::bars3d
-
-This works like GD::Graph::bars, but draws 3d bars. The following settings 
-are new or changed in GD::Graph::bars3d.
-
-=over 4
-
-=item bar_depth
-
-Sets the z-direction depth of the bars. This defaults to 10. If you have a 
-large number of bars or a small chart width, you may want to change this. 
-A visually good value for this is approximately 
-width_of_chart / number_of_bars.
-
-=item overwrite
-
-In GD::Graph::bars, multiple series of bars are normally drawn side-by-side. 
-You can set overwrite to 1 to tell it to draw each series behind the 
-previous one. By setting overwrite to 2 you can have them drawn on top of 
-each other, that is the series are stacked.
-
-=item shading
-
-By default this is set to '1' and will shade and highlight the bars (and axes).
-The light source is at top-left-center which scan well for most computer 
-users. You can disable the shading of bars and axes by specifying a false 
-value for this option.
-
-=back
-
-=item GD::Graph::lines3d
-
-This works like GD::Graph::lines, but draws 3d line. The following settings 
-are new or changed in GD::Graph::line3d.
-
-=over 4
-
-=item line_depth
-
-Sets the z-direction depth of the lines. This defaults to 10. If you have a 
-large number of bars or a small chart width, you may want to change this. 
-A visually good value for this is approximately 
-width_of_chart / number_of_bars.
-
-=item shading
-
-By default this is set to '1' and will shade and highlight the line (and axes).
-The light source is at top-left-center which scan well for most computer 
-users. You can disable the shading of lines and axes by specifiying a false 
-value for this option.
-
-=back
-
-=back
-
-=head1 VERSION
-
-0.63 (6 December 2002)
-
-=head1 INSTALLATION
-
-You will need to have the GD::Graph version 1.30 or later installed. You should also 
-have Perl version 5.005 or 5.6 installed.
-
-To install, just do the normal:
-
-	perl Makefile.PL
-	make
-	make install
-
-The documentation is in GD::Graph::Graph3d.pod.
-
-=head1 AUTHOR
-
-Jeremy Wadsack for Wadsack-Allen Digital Group. 
->
-
-Most of the modules are based on the GD::Graph modules by Martien Verbruggen.
-
-=head1 LATEST RELEASE
-
-The latest release is available from CPAN: http://www.cpan.org/.
-
-=head1 COPYRIGHT
-
-Copyright (c) 1999-2001 Wadsack-Allen. All rights reserved.
-
-Much of the original code is from GD::Graph:
-
-GIFgraph: Copyright (c) 1995-1999 Martien Verbruggen.
-
-Chart::PNGgraph: Copyright (c) 1999 Steve Bonds.
-
-GD::Graph: Copyright (c) 1999 Martien Verbruggen.
-
-This package is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
-
-=cut
-
diff --git a/lib/HTML/TextToHTML.pm b/lib/HTML/TextToHTML.pm
deleted file mode 100644
index 82f3dc2..0000000
--- a/lib/HTML/TextToHTML.pm
+++ /dev/null
@@ -1,5266 +0,0 @@
-package HTML::TextToHTML;
-use 5.006_001;
-use strict;
-#------------------------------------------------------------------------
-
-=head1 NAME
-
-HTML::TextToHTML - convert plain text file to HTML.
-
-=head1 VERSION
-
-This describes version B<2.42> of HTML::TextToHTML.
-
-=cut
-
-our $VERSION = '2.42';
-
-=head1 SYNOPSIS
-
-  From the command line:
-
-    txt2html I
-
-  From Scripts:
-
-    use HTML::TextToHTML;
- 
-    # create a new object
-    my $conv = new HTML::TextToHTML();
-
-    # convert a file
-    $conv->txt2html(infile=>[$text_file],
-                     outfile=>$html_file,
-		     title=>"Wonderful Things",
-		     mail=>1,
-      ]);
-
-    # reset arguments
-    $conv->args(infile=>[], mail=>0);
-
-    # convert a string
-    $newstring = $conv->process_chunk($mystring)
-
-=head1 DESCRIPTION
-
-HTML::TextToHTML converts plain text files to HTML. The txt2html script
-uses this module to do the same from the command-line.
-
-It supports headings, tables, lists, simple character markup, and
-hyperlinking, and is highly customizable. It recognizes some of the
-apparent structure of the source document (mostly whitespace and
-typographic layout), and attempts to mark that structure explicitly
-using HTML. The purpose for this tool is to provide an easier way of
-converting existing text documents to HTML format, giving something nicer
-than just whapping the text into a big PRE block.
-
-=head2 History
-
-The original txt2html script was written by Seth Golub (see
-http://www.aigeek.com/txt2html/), and converted to a perl module by
-Kathryn Andersen (see http://www.katspace.com/tools/text_to_html/) and
-made into a sourceforge project by Sun Tong (see
-http://sourceforge.net/projects/txt2html/).  Earlier versions of the
-HTML::TextToHTML module called the included script texthyper so as not
-to clash with the original txt2html script, but now the projects have
-all been merged.
-
-=head1 REQUIRES
-
-HTML::TextToHTML requires Perl 5.6.1 or later.
-
-For installation, it needs:
-
-    Module::Build
-
-The txt2html script needs:
-
-    Getopt::Long
-    Getopt::ArgvFile
-    Pod::Usage
-    File::Basename
-
-For testing, it also needs:
-
-    Test::More
-
-For debugging, it also needs:
-
-    Data::Dumper
-
-=head1 INSTALLATION
-
-Make sure you have the dependencies installed first!
-(see REQUIRES above)
-
-Some of those modules come standard with more recent versions of perl,
-but I thought I'd mention them anyway, just in case you may not have
-them.
-
-If you don't know how to install these, try using the CPAN module, an
-easy way of auto-installing modules from the Comprehensive Perl Archive
-Network, where the above modules reside.
-Do "perldoc perlmodinstall" or "perldoc CPAN" for more information.
-
-To install this module type the following:
-
-   perl Build.PL
-   ./Build
-   ./Build test
-   ./Build install
-
-Or, if you're on a platform (like DOS or Windows) that doesn't like the
-"./" notation, you can do this:
-
-   perl Build.PL
-   perl Build
-   perl Build test
-   perl Build install
-
-In order to install somewhere other than the default, such as
-in a directory under your home directory, like "/home/fred/perl"
-go
-
-   perl Build.PL --install_base /home/fred/perl
-
-as the first step instead.
-
-This will install the files underneath /home/fred/perl.
-
-You will then need to make sure that you alter the PERL5LIB variable to
-find the modules, and the PATH variable to find the script.
-
-Therefore you will need to change:
-your path, to include /home/fred/perl/script (where the script will be)
-
-	PATH=/home/fred/perl/script:${PATH}
-
-the PERL5LIB variable to add /home/fred/perl/lib
-
-	PERL5LIB=/home/fred/perl/lib:${PERL5LIB}
-
-Note that the system links dictionary will be installed as
-"/home/fred/perl/share/txt2html/txt2html.dict"
-
-If you want to install in a temporary install directory (such as
-if you are building a package) then instead of going
-
-   perl Build install
-
-go
-
-   perl Build install destdir=/my/temp/dir
-
-and it will be installed there, with a directory structure under
-/my/temp/dir the same as it would be if it were installed plain.
-Note that this is NOT the same as setting --install_base, because
-certain things are done at build-time which use the install_base info.
-
-See "perldoc perlrun" for more information on PERL5LIB, and
-see "perldoc Module::Build" for more information on
-installation options.
-
-=head1 OPTIONS
-
-All arguments can be set when the object is created, and further options
-can be set when calling the actual txt2html method. Arguments
-to methods can take either a hash of arguments, or a reference to an
-array.  Note that the reference-to-array method is depricated and is only
-retained for backwards compatibility.
-
-Note that all option-names must match exactly -- no abbreviations are
-allowed.
-
-The arguments get treated differently depending on whether they are
-given in a hash or a reference to an array.  When the arguments are
-in a hash, the argument-keys are expected to have values matching
-those required for that argument -- whether that be a boolean, a string,
-a reference to an array or a reference to a hash.  These will replace
-any value for that argument that might have been there before.
-
-When the arguments are in a reference to an array, it is treated
-somewhat as if it were a command-line: option names are expected to
-start with '--' or '-', boolean options are set to true as soon as the
-option is given (no value is expected to follow),  boolean options with
-the word "no" prepended set the option to false, string options are
-expected to have a string value following, and those options which are
-internally arrays or hashes are treated as cumulative; that is, the
-value following the --option is added to the current set for that
-option,  to add more, one just repeats the --option with the next value,
-and in order to reset that option to empty, the special value of "CLEAR"
-must be added to the list.
-
-NOTE: the reference-to-an-array usage is DEPRECATED and will be removed
-in the future.
-
-=over
-
-=item append_file
-
-    append_file=>I
-
-If you want something appended by default, put the filename here.
-The appended text will not be processed at all, so make sure it's
-plain text or decent HTML.  i.e. do not have things like:
-    Mary Andersen Ekitty@example.comE
-but instead, have:
-    Mary Andersen <kitty@example.com>
-
-(default: nothing)
-
-=item append_head
-
-    append_head=>I
-
-If you want something appended to the head by default, put the filename here.
-The appended text will not be processed at all, so make sure it's
-plain text or decent HTML.  i.e. do not have things like:
-    Mary Andersen Ekitty@example.comE
-but instead, have:
-    Mary Andersen <kitty@example.com>
-
-(default: nothing)
-
-=item body_deco
-
-    body_deco=>I
-
-Body decoration string: a string to be added to the BODY tag so that
-one can set attributes to the BODY (such as class, style, bgcolor etc)
-For example, "class='withimage'".
-
-=item bold_delimiter
-
-    bold_delimiter=>I
-
-This defines what character (or string) is taken to be the delimiter of
-text which is to be interpreted as bold (that is, to be given a STRONG
-tag).  If this is empty, then no bolding of text will be done.
-(default: #)
-
-=item bullets
-
-    bullets=>I
-
-This defines what single characters are taken to be "bullet" characters
-for unordered lists.  Note that because this is used as a character
-class, if you use '-' it must come first.
-(default:-=o*\267)
-
-=item bullets_ordered
-
-    bullets_ordered=>I
-
-This defines what single characters are taken to be "bullet" placeholder
-characters for ordered lists.  Ordered lists are normally marked by
-a number or letter followed by '.' or ')' or ']' or ':'.  If an ordered
-bullet is used, then it simply indicates that this is an ordered list,
-without giving explicit numbers.
-
-Note that because this is used as a character class, if you use '-' it
-must come first.
-(default:nothing)
-
-=item caps_tag
-
-    caps_tag=>I
-
-Tag to put around all-caps lines
-(default: STRONG)
-If an empty tag is given, then no tag will be put around all-caps lines.
-
-=item custom_heading_regexp
-
-    custom_heading_regexp=>I
-
-Add a regexp for headings.  Header levels are assigned by regexp
-in order seen When a line matches a custom header regexp, it is tagged as
-a header.  If it's the first time that particular regexp has matched,
-the next available header level is associated with it and applied to
-the line.  Any later matches of that regexp will use the same header level.
-Therefore, if you want to match numbered header lines, you could use
-something like this:
-
-    -H '^ *\d+\. \w+' -H '^ *\d+\.\d+\. \w+' -H '^ *\d+\.\d+\.\d+\. \w+'
-
-Then lines like
-
-                " 1. Examples "
-                " 1.1. Things"
-            and " 4.2.5. Cold Fusion"
-
-Would be marked as H1, H2, and H3 (assuming they were found in that
-order, and that no other header styles were encountered).
-If you prefer that the first one specified always be H1, the second
-always be H2, the third H3, etc, then use the -EH/--explicit-headings
-option.
-
-This is a multi-valued option.
-
-(default: none)
-
-=item debug
-    
-    debug=>1
-
-Enable copious script debugging output (don't bother, this is for the
-developer) (default: false)
-
-=item default_link_dict
-
-    default_link_dict=>I
-
-The name of the default "user" link dictionary.
-(default: "$ENV{'HOME'}/.txt2html.dict" -- this is the same as for
-the txt2html script.  If there is no $ENV{HOME} then it is just '.txt2html.dict')
-
-=item demoronize
-
-    demoronize=>1
-
-Convert Microsoft-generated character codes that are non-ISO codes into
-something more reasonable.
-(default:true)
-
-=item dict_debug
-
-    dict_debug=>I
-
-Debug mode for link dictionaries Bitwise-Or what you want to see:
-          1: The parsing of the dictionary
-          2: The code that will make the links
-          4: When each rule matches something
-          8: When each tag is created
-
-(default: 0)
-
-=item doctype
-
-    doctype=>I
-
-This gets put in the DOCTYPE field at the top of the document, unless it's
-empty.  (default : "-//W3C//DTD HTML 3.2 Final//EN")
-If --xhtml is true, the contents of this is ignored, unless it's
-empty, in which case no DOCTYPE declaration is output.
-
-=item eight_bit_clean
-
-    eight_bit_clean=>1
-
-disable Latin-1 character entity naming
-(default: false)
-
-=item escape_HTML_chars
-
-    escape_HTML_chars=>1
-
-turn & E E into & > <
-(default: true)
-
-=item explicit_headings
-
-    explicit_headings=>1
-
-Don't try to find any headings except the ones specified in the
---custom_heading_regexp option.
-Also, the custom headings will not be assigned levels in the order they
-are encountered in the document, but in the order they are specified on
-the command line.
-(default: false)
-
-=item extract
-
-    extract=>1
-
-Extract Mode; don't put HTML headers or footers on the result, just
-the plain HTML (thus making the result suitable for inserting into
-another document (or as part of the output of a CGI script).
-(default: false)
-
-=item hrule_min
-
-    hrule_min=>I
-
-Min number of ---s for an HRule.
-(default: 4)
-
-=item indent_width
-
-    indent_width=>I
-
-Indents this many spaces for each level of a list.
-(default: 2)
-
-=item indent_par_break
-
-    indent_par_break=>1
-
-Treat paragraphs marked solely by indents as breaks with indents.
-That is, instead of taking a three-space indent as a new paragraph,
-put in a 
and three non-breaking spaces instead. -(see also --preserve_indent) -(default: false) - -=item infile - - infile=>\@my_files - infile=>['chapter1.txt', 'chapter2.txt'] - "--infile", "chapter1.txt", "--infile", "chapter2.txt" - -The name of the input file(s). When the arguments are given as a hash, -this expects a reference to an array of filenames. When the arguments -are given as a reference to an array, then the "--infile" option must -be repeated for each new file added to the list. If you want to reset -the list to be empty, give the special value of "CLEAR". - -The special filename '-' designates STDIN. - -See also L and L. - -(default:-) - -=item inhandle - - inhandle=>\@my_handles - inhandle=>[\*MYINHANDLE, \*STDIN] - -An array of input filehandles; use this instead of -L or L to use a filehandle or filehandles -as input. - -=item instring - - instring=>\@my_strings - instring=>[$string1, $string2] - -An array of input strings; use this instead of -L or L to use a string or strings -as input. - -=item italic_delimiter - - italic_delimiter=>I - -This defines what character (or string) is taken to be the delimiter of -text which is to be interpreted as italic (that is, to be given a EM -tag). If this is empty, no italicising of text will be done. -(default: *) - -=item links_dictionaries - - links_dictionaries=>\@my_link_dicts - links_dictionaries=>['url_links.dict', 'format_links.dict'] - "--links_dictionaries", "url_links.dict", "--links_dictionaries", "format_links.dict" - -File(s) to use as a link-dictionary. There can be more than one of -these. These are in addition to the Global Link Dictionary and the User -Link Dictionary. When the arguments are given as a hash, this expects a -reference to an array of filenames. When the arguments are given as a -reference to an array, then the "--links_dictionaries" option must be -repeated for each new file added to the list. If you want to reset the -list to be empty, give the special value of "CLEAR". - -=item link_only - - link_only=>1 - -Do no escaping or marking up at all, except for processing the links -dictionary file and applying it. This is useful if you want to use -the linking feature on an HTML document. If the HTML is a -complete document (includes HTML,HEAD,BODY tags, etc) then you'll -probably want to use the --extract option also. -(default: false) - -=item lower_case_tags - - lower_case_tags=>1 - -Force all tags to be in lower-case. - -=item mailmode - - mailmode=>1 - -Deal with mail headers & quoted text. The mail header paragraph is -given the class 'mail_header', and mail-quoted text is given the class -'quote_mail'. -(default: false) - -=item make_anchors - - make_anchors=>0 - -Should we try to make anchors in headings? -(default: true) - -=item make_links - - make_links=>0 - -Should we try to build links? If this is false, then the links -dictionaries are not consulted and only structural text-to-HTML -conversion is done. (default: true) - -=item make_tables - - make_tables=>1 - -Should we try to build tables? If true, spots tables and marks them up -appropriately. See L for information on how tables -should be formatted. - -This overrides the detection of lists; if something looks like a table, -it is taken as a table, and list-checking is not done for that -paragraph. - -(default: false) - -=item min_caps_length - - min_caps_length=>I - -min sequential CAPS for an all-caps line -(default: 3) - -=item outfile - - outfile=>I - -The name of the output file. If it is "-" then the output goes -to Standard Output. -(default: - ) - -=item outhandle - -The output filehandle; if this is given then the output goes -to this filehandle instead of to the file given in L. - -=item par_indent - - par_indent=>I - -Minumum number of spaces indented in first lines of paragraphs. - Only used when there's no blank line -preceding the new paragraph. -(default: 2) - -=item preformat_trigger_lines - - preformat_trigger_lines=>I - -How many lines of preformatted-looking text are needed to switch to
-          <= 0 : Preformat entire document
-             1 : one line triggers
-          >= 2 : two lines trigger
-
-(default: 2)
-
-=item endpreformat_trigger_lines
-
-    endpreformat_trigger_lines=>I
-
-How many lines of unpreformatted-looking text are needed to switch from 
-           <= 0 : Never preformat within document
-              1 : one line triggers
-           >= 2 : two lines trigger
-(default: 2)
-
-NOTE for preformat_trigger_lines and endpreformat_trigger_lines:
-A zero takes precedence.  If one is zero, the other is ignored.
-If both are zero, entire document is preformatted.
-
-=item preformat_start_marker
-
-    preformat_start_marker=>I
-
-What flags the start of a preformatted section if --use_preformat_marker
-is true.
-
-(default: "^(:?(:?<)|<)PRE(:?(:?>)|>)\$")
-
-=item preformat_end_marker
-
-    preformat_end_marker=>I
-
-What flags the end of a preformatted section if --use_preformat_marker
-is true.
-
-(default: "^(:?(:?<)|<)/PRE(:?(:?>)|>)\$")
-
-=item preformat_whitespace_min
-
-    preformat_whitespace_min=>I
-
-Minimum number of consecutive whitespace characters to trigger
-normal preformatting. 
-NOTE: Tabs are expanded to spaces before this check is made.
-That means if B is 8 and this is 5, then one tab may be
-expanded to 8 spaces, which is enough to trigger preformatting.
-(default: 5)
-
-=item prepend_file
-
-    prepend_file=>I
-
-If you want something prepended to the processed body text, put the
-filename here.  The prepended text will not be processed at all, so make
-sure it's plain text or decent HTML.
-
-(default: nothing)
-
-=item preserve_indent
-
-    preserve_indent=>1
-
-Preserve the first-line indentation of paragraphs marked with indents
-by replacing the spaces of the first line with non-breaking spaces.
-(default: false)
-
-=item short_line_length
-
-    short_line_length=>I
-
-Lines this short (or shorter) must be intentionally broken and are kept
-that short.
-(default: 40)
-
-=item style_url
-
-    style_url=>I
-
-This gives the URL of a stylesheet; a LINK tag will be added to the
-output.
-
-=item tab_width
-
-    tab_width=>I
-
-How many spaces equal a tab?
-(default: 8)
-
-=item table_type
-    
-    table_type=>{ ALIGN=>0, PGSQL=>0, BORDER=>1, DELIM=>0 }
-
-This determines which types of tables will be recognised when "make_tables"
-is true.  The possible types are ALIGN, PGSQL, BORDER and DELIM.
-(default: all types are true)
-
-=item title
-
-    title=>I
-
-You can specify a title.  Otherwise it will use a blank one.
-(default: nothing)
-
-=item titlefirst
-
-    titlefirst=>1
-
-Use the first non-blank line as the title.
-
-=item underline_length_tolerance
-
-    underline_length_tolerance=>I<n>
-
-How much longer or shorter can underlines be and still be underlines?
-(default: 1)
-
-=item underline_offset_tolerance
-
-    underline_offset_tolerance=>I<n>
-
-How far offset can underlines be and still be underlines?
-(default: 1)
-
-=item unhyphenation
-
-    unhyphenation=>0
-
-Enables unhyphenation of text.
-(default: true)
-
-=item use_mosaic_header
-
-    use_mosaic_header=>1
-
-Use this option if you want to force the heading styles to match what Mosaic
-outputs.  (Underlined with "***"s is H1,
-with "==="s is H2, with "+++" is H3, with "---" is H4, with "~~~" is H5
-and with "..." is H6)
-This was the behavior of txt2html up to version 1.10.
-(default: false)
-
-=item use_preformat_marker
-
-    use_preformat_marker=>1
-
-Turn on preformatting when encountering "<PRE>" on a line by itself, and turn
-it off when there's a line containing only "</PRE>".
-When such preformatted text is detected, the PRE tag will be given the
-class 'quote_explicit'.
-(default: off)
-
-=item xhtml
-
-    xhtml=>1
-
-Try to make the output conform to the XHTML standard, including
-closing all open tags and marking empty tags correctly.  This
-turns on --lower_case_tags and overrides the --doctype option.
-Note that if you add a header or a footer file, it is up to you
-to make it conform; the header/footer isn't touched by this.
-Likewise, if you make link-dictionary entries that break XHTML,
-then this won't fix them, except to the degree of putting all tags
-into lower-case.
-
-=back
-
-=head1 METHODS
-
-=cut
-
-#------------------------------------------------------------------------
-
-require Exporter;
-use Data::Dumper;
-
-our $PROG = 'HTML::TextToHTML';
-
-#------------------------------------------------------------------------
-use constant TEXT_TO_HTML => "TEXT_TO_HTML";
-
-########################################
-# Definitions  (Don't change these)
-#
-
-# These are just constants I use for making bit vectors to keep track
-# of what modes I'm in and what actions I've taken on the current and
-# previous lines.
-
-our $NONE         = 0;
-our $LIST         = 1;
-our $HRULE        = 2;
-our $PAR          = 4;
-our $PRE          = 8;
-our $END          = 16;
-our $BREAK        = 32;
-our $HEADER       = 64;
-our $MAILHEADER   = 128;
-our $MAILQUOTE    = 256;
-our $CAPS         = 512;
-our $LINK         = 1024;
-our $PRE_EXPLICIT = 2048;
-our $TABLE        = 4096;
-our $IND_BREAK    = 8192;
-our $LIST_START   = 16384;
-our $LIST_ITEM    = 32768;
-
-# Constants for Link-processing
-# bit-vectors for what to do with a particular link-dictionary entry
-our $LINK_NOCASE    = 1;
-our $LINK_EVAL      = 2;
-our $LINK_HTML      = 4;
-our $LINK_ONCE      = 8;
-our $LINK_SECT_ONCE = 16;
-
-# Constants for Ordered Lists and Unordered Lists.
-# And Definition Lists.
-# I use this in the list stack to keep track of what's what.
-
-our $OL = 1;
-our $UL = 2;
-our $DL = 3;
-
-# Constants for table types
-our $TAB_ALIGN  = 1;
-our $TAB_PGSQL  = 2;
-our $TAB_BORDER = 3;
-our $TAB_DELIM  = 4;
-
-# Character entity names
-# characters to replace with entities
-our %char_entities = (
-    "\241", "¡",  "\242", "¢",   "\243", "£",
-    "\244", "¤", "\245", "¥",    "\246", "¦",
-    "\247", "§",   "\250", "¨",    "\251", "©",
-    "\252", "ª",   "\253", "«",  "\254", "¬",
-    "\255", "­",    "\256", "®",    "\257", "&hibar;",
-    "\260", "°",    "\261", "±", "\262", "²",
-    "\263", "³",   "\264", "´",  "\265", "µ",
-    "\266", "¶",   "\270", "¸",  "\271", "¹",
-    "\272", "º",   "\273", "»",  "\274", "¼",
-    "\275", "½", "\276", "¾", "\277", "¿",
-    "\300", "À", "\301", "Á", "\302", "Â",
-    "\303", "Ã", "\304", "Ä",   "\305", "Å",
-    "\306", "Æ",  "\307", "Ç", "\310", "È",
-    "\311", "É", "\312", "Ê",  "\313", "Ë",
-    "\314", "Ì", "\315", "Í", "\316", "Î",
-    "\317", "Ï",   "\320", "Ð",    "\321", "Ñ",
-    "\322", "Ò", "\323", "Ó", "\324", "Ô",
-    "\325", "Õ", "\326", "Ö",   "\327", "×",
-    "\330", "Ø", "\331", "Ù", "\332", "Ú",
-    "\333", "Û",  "\334", "Ü",   "\335", "Ý",
-    "\336", "Þ",  "\337", "ß",  "\340", "à",
-    "\341", "á", "\342", "â",  "\343", "ã",
-    "\344", "ä",   "\345", "å",  "\346", "æ",
-    "\347", "ç", "\350", "è", "\351", "é",
-    "\352", "ê",  "\353", "ë",   "\354", "ì",
-    "\355", "í", "\356", "î",  "\357", "ï",
-    "\360", "ð",    "\361", "ñ", "\362", "ò",
-    "\363", "ó", "\364", "ô",  "\365", "õ",
-    "\366", "ö",   "\367", "÷", "\370", "ø",
-    "\371", "ù", "\372", "ú", "\373", "û",
-    "\374", "ü",   "\375", "ý", "\376", "þ",
-    "\377", "ÿ",   "\267", "·",
-);
-
-# alignments for tables
-our @alignments    = ('', '', ' ALIGN="RIGHT"', ' ALIGN="CENTER"');
-our @lc_alignments = ('', '', ' align="right"', ' align="center"');
-our @xhtml_alignments =
-  ('', '', ' style="text-align: right;"', ' style="text-align: center;"');
-
-#---------------------------------------------------------------#
-# Object interface
-#---------------------------------------------------------------#
-
-=head2 new
-
-    $conv = new HTML::TextToHTML()
-
-    $conv = new HTML::TextToHTML(titlefirst=>1,
-	...
-    );
-
-Create a new object with new.  If one argument is given, it is assumed
-to be a reference to an array of arguments.  If more than one argument
-is given, it is assumed to be a hash of arguments.  These arguments will
-be used in invocations of other methods.
-
-See L</OPTIONS> for the possible values of the arguments.
-
-=cut
-
-sub new
-{
-    my $invocant = shift;
-    my $self     = {};
-
-    my $class = ref($invocant) || $invocant;    # Object or class name
-    init_our_data($self);
-
-    # bless self
-    bless($self, $class);
-
-    $self->args(@_);
-
-    return $self;
-}    # new
-
-=head2 args
-
-    $conv->args(short_line_length=>60,
-	titlefirst=>1,
-	....
-    );
-
-Updates the current arguments/options of the HTML::TextToHTML object.
-Takes either a hash, or a reference to an array of arguments, which will
-be used in invocations of other methods.
-See L</OPTIONS> for the possible values of the arguments.
-
-NOTE: the reference-to-an-array usage is DEPRECATED and will be removed
-in the future.
-
-=cut
-
-sub args
-{
-    my $self      = shift;
-    my %args      = ();
-    my @arg_array = ();
-    if (   @_
-        && @_ == 1
-        && ref $_[0] eq 'ARRAY')
-    {
-        # this is a reference to an array -- use the old style args
-        my $aref = shift;
-        @arg_array = @{$aref};
-    }
-    elsif (@_)
-    {
-        %args = @_;
-    }
-
-    if (%args)
-    {
-        if ($self->{debug})
-        {
-            print STDERR "========args(hash)========\n";
-            print STDERR Dumper(%args);
-        }
-        foreach my $arg (keys %args)
-        {
-            if (defined $args{$arg})
-            {
-                if ($arg =~ /^-/)
-                {
-                    $arg =~ s/^-//;    # get rid of first dash
-                    $arg =~ s/^-//;    # get rid of possible second dash
-                }
-                if ($self->{debug})
-                {
-                    print STDERR "--", $arg;
-                }
-                $self->{$arg} = $args{$arg};
-                if ($self->{debug})
-                {
-                    print STDERR " ", $args{$arg}, "\n";
-                }
-            }
-        }
-    }
-    elsif (@arg_array)
-    {
-        if ($self->{debug})
-        {
-            print STDERR "========args(array)========\n";
-            print STDERR Dumper(@arg_array);
-        }
-        # the arg array may have filenames at the end of it,
-        # so don't consume them
-        my $look_at_args = 1;
-        while (@arg_array && $look_at_args)
-        {
-            my $arg = shift @arg_array;
-            # check for arguments which are bools,
-            # and thus have no companion value
-            if ($arg =~ /^-/)
-            {
-                $arg =~ s/^-//;    # get rid of first dash
-                $arg =~ s/^-//;    # get rid of possible second dash
-                if ($self->{debug})
-                {
-                    print STDERR "--", $arg;
-                }
-                if (   $arg eq 'debug'
-                    || $arg eq 'demoronize'
-                    || $arg eq 'eight_bit_clean'
-                    || $arg eq 'escape_HTML_chars'
-                    || $arg eq 'explicit_headings'
-                    || $arg eq 'extract'
-                    || $arg eq 'link_only'
-                    || $arg eq 'lower_case_tags'
-                    || $arg eq 'mailmode'
-                    || $arg eq 'make_anchors'
-                    || $arg eq 'make_links'
-                    || $arg eq 'make_tables'
-                    || $arg eq 'preserve_indent'
-                    || $arg eq 'titlefirst'
-                    || $arg eq 'unhyphenation'
-                    || $arg eq 'use_mosaic_header'
-                    || $arg eq 'use_preformat_marker'
-                    || $arg eq 'verbose'
-                    || $arg eq 'xhtml')
-                {
-                    $self->{$arg} = 1;
-                    if ($self->{debug})
-                    {
-                        print STDERR "=true\n";
-                    }
-                }
-                elsif ($arg eq 'nodebug'
-                    || $arg eq 'nodemoronize'
-                    || $arg eq 'noeight_bit_clean'
-                    || $arg eq 'noescape_HTML_chars'
-                    || $arg eq 'noexplicit_headings'
-                    || $arg eq 'noextract'
-                    || $arg eq 'nolink_only'
-                    || $arg eq 'nolower_case_tags'
-                    || $arg eq 'nomailmode'
-                    || $arg eq 'nomake_anchors'
-                    || $arg eq 'nomake_links'
-                    || $arg eq 'nomake_tables'
-                    || $arg eq 'nopreserve_indent'
-                    || $arg eq 'notitlefirst'
-                    || $arg eq 'nounhyphenation'
-                    || $arg eq 'nouse_mosaic_header'
-                    || $arg eq 'nouse_preformat_marker'
-                    || $arg eq 'noverbose'
-                    || $arg eq 'noxhtml')
-                {
-                    $arg =~ s/^no//;
-                    $self->{$arg} = 0;
-                    if ($self->{debug})
-                    {
-                        print STDERR " $arg=false\n";
-                    }
-                }
-                else
-                {
-                    my $val = shift @arg_array;
-                    if ($self->{debug})
-                    {
-                        print STDERR "=", $val, "\n";
-                    }
-                    # check the types
-                    if (defined $arg && defined $val)
-                    {
-                        if (   $arg eq 'infile'
-                            || $arg eq 'custom_heading_regexp'
-                            || $arg eq 'links_dictionaries')
-                        {    # arrays
-                            if ($val eq 'CLEAR')
-                            {
-                                $self->{$arg} = [];
-                            }
-                            else
-                            {
-                                push @{$self->{$arg}}, $val;
-                            }
-                        }
-                        elsif ($arg eq 'file')
-                        {    # alternate for 'infile'
-                            if ($val eq 'CLEAR')
-                            {
-                                $self->{infile} = [];
-                            }
-                            else
-                            {
-                                push @{$self->{infile}}, $val;
-                            }
-                        }
-                        elsif ($arg eq 'table_type')
-                        {
-                            # hash
-                            if ($val eq 'CLEAR')
-                            {
-                                $self->{$arg} = {};
-                            }
-                            else
-                            {
-                                my ($f1, $v1) = split(/=/, $val, 2);
-                                $self->{$arg}->{$f1} = $v1;
-                            }
-                        }
-                        else
-                        {
-                            $self->{$arg} = $val;
-                        }
-                    }
-                }
-            }
-            else
-            {
-                # if an option don't start with - then we've
-                # come to the end of the options
-                $look_at_args = 0;
-            }
-        }
-    }
-    if ($self->{debug})
-    {
-        print STDERR Dumper($self);
-    }
-
-    return 1;
-}    # args
-
-=head2 process_chunk
-
-$newstring = $conv->process_chunk($mystring);
-
-Convert a string to a HTML fragment.  This assumes that this string is
-at the least, a single paragraph, but it can contain more than that.
-This returns the processed string.  If you want to pass arguments to
-alter the behaviour of this conversion, you need to do that earlier,
-either when you create the object, or with the L</args> method.
-
-    $newstring = $conv->process_chunk($mystring,
-			    close_tags=>0);
-
-If there are open tags (such as lists) in the input string,
-process_chunk will now automatically close them, unless you specify not
-to, with the close_tags option.
-
-    $newstring = $conv->process_chunk($mystring,
-			    is_fragment=>1);
-
-If you want this string to be treated as a fragment, and not assumed to
-be a paragraph, set is_fragment to true.  If there is more than one
-paragraph in the string (ie it contains blank lines) then this option
-will be ignored.
-
-=cut
-
-sub process_chunk ($$;%)
-{
-    my $self  = shift;
-    my $chunk = shift;
-    my %args  = (
-        close_tags  => 1,
-        is_fragment => 0,
-        @_
-    );
-
-    my $ret_str = '';
-    my @paras   = split(/\r?\n\r?\n/, $chunk);
-    my $ind     = 0;
-    if (@paras == 1)    # just one paragraph
-    {
-        $ret_str .= $self->process_para(
-            $chunk,
-            close_tags  => $args{close_tags},
-            is_fragment => $args{is_fragment}
-        );
-    }
-    else
-    {
-        my $ind = 0;
-        foreach my $para (@paras)
-        {
-            # if the paragraph doesn't end with a newline, add one
-            $para .= "\n" if ($para !~ /\n$/);
-            if ($ind == @paras - 1)    # last one
-            {
-                $ret_str .= $self->process_para(
-                    $para,
-                    close_tags  => $args{close_tags},
-                    is_fragment => 0
-                );
-            }
-            else
-            {
-                $ret_str .= $self->process_para(
-                    $para,
-                    close_tags  => 0,
-                    is_fragment => 0
-                );
-            }
-            $ind++;
-        }
-    }
-    $ret_str;
-}    # process_chunk
-
-=head2 process_para
-
-$newstring = $conv->process_para($mystring);
-
-Convert a string to a HTML fragment.  This assumes that this string is
-at the most a single paragraph, with no blank lines in it.  If you don't
-know whether your string will contain blank lines or not, use the
-L</process_chunk> method instead.
-
-This returns the processed string.  If you want to pass arguments to
-alter the behaviour of this conversion, you need to do that earlier,
-either when you create the object, or with the L</args> method.
-
-    $newstring = $conv->process_para($mystring,
-			    close_tags=>0);
-
-If there are open tags (such as lists) in the input string, process_para
-will now automatically close them, unless you specify not to, with the
-close_tags option.
-
-    $newstring = $conv->process_para($mystring,
-			    is_fragment=>1);
-
-If you want this string to be treated as a fragment, and not assumed to be
-a paragraph, set is_fragment to true.
-
-=cut
-
-sub process_para ($$;%)
-{
-    my $self = shift;
-    my $para = shift;
-    my %args = (
-        close_tags  => 1,
-        is_fragment => 0,
-        @_
-    );
-
-    # if this is an external call, do certain initializations
-    $self->do_init_call();
-
-    my $para_action = $NONE;
-
-    # tables and mailheaders don't carry over from one para to the next
-    if ($self->{__mode} & $TABLE)
-    {
-        $self->{__mode} ^= $TABLE;
-    }
-    if ($self->{__mode} & $MAILHEADER)
-    {
-        $self->{__mode} ^= $MAILHEADER;
-    }
-
-    # convert Microsoft character codes into sensible characters
-    if ($self->{demoronize})
-    {
-        demoronize_char($para);
-    }
-
-    # if we are not just linking, we are discerning structure
-    if (!$self->{link_only})
-    {
-
-        # Chop trailing whitespace and DOS CRs
-        $para =~ s/[ \011]*\015$//;
-        # Chop leading whitespace and DOS CRs
-        $para =~ s/^[ \011]*\015//;
-        $para =~ s/\r//g;             # remove any stray carriage returns
-
-        my @done_lines = ();          # lines which have been processed
-
-        # The PRE_EXPLICIT structure can carry over from one
-        # paragraph to the next, but it is ended with the
-        # explicit end-tag designated for it.
-        # Therefore we can shortcut for this by checking
-        # for the end of the PRE_EXPLICIT and chomping off
-        # the preformatted string part of this para before
-        # we have to split it into lines.
-        # Note that after this check, we could *still* be
-        # in PRE_EXPLICIT mode.
-        if ($self->{__mode} & $PRE_EXPLICIT)
-        {
-            my $pre_str =
-              $self->split_end_explicit_preformat(para_ref => \$para);
-            if ($pre_str)
-            {
-                push @done_lines, $pre_str;
-            }
-        }
-
-        if (defined $para && $para ne "")
-        {
-            #
-            # Now we split the paragraph into lines
-            #
-            my $para_len         = length($para);
-            my @para_lines       = split(/^/, $para);
-            my @para_line_len    = ();
-            my @para_line_indent = ();
-            my @para_line_action = ();
-            my $i                = 0;
-            foreach my $line (@para_lines)
-            {
-                # Change all tabs to spaces
-                while ($line =~ /\011/)
-                {
-                    my $tw = $self->{tab_width};
-                    $line =~ s/\011/" " x ($tw - (length($`) % $tw))/e;
-                }
-                push @para_line_len, length($line);
-                if ($line =~ /^\s*$/)
-                {
-                    # if the line is blank, use the previous indent
-                    # if there is one
-                    push @para_line_indent,
-                      ($i == 0 ? 0 : $para_line_indent[$i - 1]);
-                }
-                else
-                {
-                    # count the number of leading spaces
-                    my ($ws) = $line =~ /^( *)[^ ]/;
-                    push @para_line_indent, length($ws);
-                }
-                push @para_line_action, $NONE;
-                $i++;
-            }
-
-            # There are two more structures which carry over from one
-            # paragraph to the next: LIST, PRE
-            # There are also certain things which will immediately end
-            # multi-paragraph LIST and PRE, if found at the start
-            # of a paragraph:
-            # A list will be ended by
-            # TABLE, MAILHEADER, HEADER, custom-header
-            # A PRE will be ended by
-            # TABLE, MAILHEADER and non-pre text
-
-            my $is_table         = 0;
-            my $table_type       = 0;
-            my $is_mailheader    = 0;
-            my $is_header        = 0;
-            my $is_custom_header = 0;
-            if (@{$self->{custom_heading_regexp}})
-            {
-                $is_custom_header =
-                  $self->is_custom_heading(line => $para_lines[0]);
-            }
-            if (   $self->{make_tables}
-                && @para_lines > 1)
-            {
-                $table_type = $self->get_table_type(
-                    rows_ref => \@para_lines,
-                    para_len => $para_len
-                );
-                $is_table = ($table_type != 0);
-            }
-            if (   !$self->{explicit_headings}
-                && @para_lines > 1
-                && !$is_table)
-            {
-                $is_header = $self->is_heading(
-                    line_ref => \$para_lines[0],
-                    next_ref => \$para_lines[1]
-                );
-            }
-            # Note that it is concievable that someone has
-            # partially disabled mailmode by making a custom header
-            # which matches the start of mail.
-            # This is stupid, but allowable, so we check.
-            if (   $self->{mailmode}
-                && !$is_table
-                && !$is_custom_header)
-            {
-                $is_mailheader = $self->is_mailheader(rows_ref => \@para_lines);
-            }
-
-            # end the list if we can end it
-            if (
-                ($self->{__mode} & $LIST)
-                && (   $is_table
-                    || $is_mailheader
-                    || $is_header
-                    || $is_custom_header)
-              )
-            {
-                my $list_end = '';
-                my $action   = 0;
-                $self->endlist(
-                    num_lists       => $self->{__listnum},
-                    prev_ref        => \$list_end,
-                    line_action_ref => \$action
-                );
-                push @done_lines, $list_end;
-                $self->{__prev_para_action} |= $END;
-            }
-
-            # end the PRE if we can end it
-            if (
-                   ($self->{__mode} & $PRE)
-                && !($self->{__mode} & $PRE_EXPLICIT)
-                && (   $is_table
-                    || $is_mailheader
-                    || !$self->is_preformatted($para_lines[0]))
-                && ($self->{preformat_trigger_lines} != 0)
-              )
-            {
-                my $pre_end = '';
-                my $tag     = $self->close_tag('PRE');
-                $pre_end = "${tag}\n";
-                $self->{__mode} ^= ($PRE & $self->{__mode});
-                push @done_lines, $pre_end;
-                $self->{__prev_para_action} |= $END;
-            }
-
-            # The PRE and PRE_EXPLICIT structure can carry over
-            # from one paragraph to the next, but because we don't
-            # want trailing newlines, such newlines would have been
-            # gotten rid of in the previous call.  However, with
-            # a preformatted text, we do want the blank lines in it
-            # to be preserved, so let's add a blank line in here.
-            if ($self->{__mode} & $PRE)
-            {
-                push @done_lines, "\n";
-            }
-
-            # Now, we do certain things which are only found at the
-            # start of a paragraph:
-            # HEADER, custom-header, TABLE and MAILHEADER
-            # These could concievably eat the rest of the paragraph.
-
-            if ($is_custom_header)
-            {
-                # custom header eats the first line
-                my $header = shift @para_lines;
-                shift @para_line_len;
-                shift @para_line_indent;
-                shift @para_line_action;
-                $self->custom_heading(line_ref => \$header);
-                push @done_lines, $header;
-                $self->{__prev_para_action} |= $HEADER;
-            }
-            elsif ($is_header)
-            {
-                # normal header eats the first two lines
-                my $header = shift @para_lines;
-                shift @para_line_len;
-                shift @para_line_indent;
-                shift @para_line_action;
-                my $underline = shift @para_lines;
-                shift @para_line_len;
-                shift @para_line_indent;
-                shift @para_line_action;
-                $self->heading(
-                    line_ref => \$header,
-                    next_ref => \$underline
-                );
-                push @done_lines, $header;
-                $self->{__prev_para_action} |= $HEADER;
-            }
-
-            # do the table stuff on the array of lines
-            if ($self->{make_tables} && $is_table)
-            {
-                if (
-                    $self->tablestuff(
-                        table_type => $table_type,
-                        rows_ref   => \@para_lines,
-                        para_len   => $para_len
-                    )
-                  )
-                {
-                    # this has used up all the lines
-                    push @done_lines, @para_lines;
-                    @para_lines = ();
-                }
-            }
-
-            # check of this para is a mail-header
-            if (   $is_mailheader
-                && !($self->{__mode} & $TABLE)
-                && @para_lines)
-            {
-                $self->mailheader(rows_ref => \@para_lines);
-                # this has used up all the lines
-                push @done_lines, @para_lines;
-                @para_lines = ();
-            }
-
-            #
-            # Now go through the paragraph lines one at a time
-            # Note that we won't have TABLE, MAILHEADER, HEADER modes
-            # because they would have eaten the lines
-            #
-            my $prev        = '';
-            my $prev_action = $self->{__prev_para_action};
-            for (my $i = 0; $i < @para_lines; $i++)
-            {
-                my $prev_ref;
-                my $prev_action_ref;
-                my $prev_line_indent;
-                my $prev_line_len;
-                if ($i == 0)
-                {
-                    $prev_ref         = \$prev;
-                    $prev_action_ref  = \$prev_action;
-                    $prev_line_indent = 0;
-                    $prev_line_len    = 0;
-                }
-                else
-                {
-                    $prev_ref         = \$para_lines[$i - 1];
-                    $prev_action_ref  = \$para_line_action[$i - 1];
-                    $prev_line_indent = $para_line_indent[$i - 1];
-                    $prev_line_len    = $para_line_len[$i - 1];
-                }
-                my $next_ref;
-                if ($i == $#para_lines)
-                {
-                    $next_ref = undef;
-                }
-                else
-                {
-                    $next_ref = \$para_lines[$i + 1];
-                }
-
-                $para_lines[$i] = escape($para_lines[$i])
-                  if ($self->{escape_HTML_chars});
-
-                if ($self->{mailmode}
-                    && !($self->{__mode} & ($PRE_EXPLICIT)))
-                {
-                    $self->mailquote(
-                        line_ref        => \$para_lines[$i],
-                        line_action_ref => \$para_line_action[$i],
-                        prev_ref        => $prev_ref,
-                        prev_action_ref => $prev_action_ref,
-                        next_ref        => $next_ref
-                    );
-                }
-
-                if (   ($self->{__mode} & $PRE)
-                    && ($self->{preformat_trigger_lines} != 0))
-                {
-                    $self->endpreformat(
-                        para_lines_ref  => \@para_lines,
-                        para_action_ref => \@para_line_action,
-                        ind             => $i,
-                        prev_ref        => $prev_ref
-                    );
-                }
-
-                if (!($self->{__mode} & $PRE))
-                {
-                    $self->hrule(
-                        para_lines_ref  => \@para_lines,
-                        para_action_ref => \@para_line_action,
-                        ind             => $i
-                    );
-                }
-                if (!($self->{__mode} & ($PRE))
-                    && ($para_lines[$i] !~ /^\s*$/))
-                {
-                    $self->liststuff(
-                        para_lines_ref       => \@para_lines,
-                        para_action_ref      => \@para_line_action,
-                        para_line_indent_ref => \@para_line_indent,
-                        ind                  => $i,
-                        prev_ref             => $prev_ref
-                    );
-                }
-                if (   !($para_line_action[$i] & ($HEADER | $LIST))
-                    && !($self->{__mode} & ($LIST | $PRE))
-                    && $self->{__preformat_enabled})
-                {
-                    $self->preformat(
-                        mode_ref        => \$self->{__mode},
-                        line_ref        => \$para_lines[$i],
-                        line_action_ref => \$para_line_action[$i],
-                        prev_ref        => $prev_ref,
-                        next_ref        => $next_ref,
-                        prev_action_ref => $prev_action_ref
-                    );
-                }
-                if (!($self->{__mode} & ($PRE)))
-                {
-                    $self->paragraph(
-                        line_ref        => \$para_lines[$i],
-                        line_action_ref => \$para_line_action[$i],
-                        prev_ref        => $prev_ref,
-                        prev_action_ref => $prev_action_ref,
-                        line_indent     => $para_line_indent[$i],
-                        prev_indent     => $prev_line_indent,
-                        is_fragment     => $args{is_fragment},
-                        ind             => $i,
-                    );
-                }
-                if (!($self->{__mode} & ($PRE | $LIST)))
-                {
-                    $self->shortline(
-                        line_ref        => \$para_lines[$i],
-                        line_action_ref => \$para_line_action[$i],
-                        prev_ref        => $prev_ref,
-                        prev_action_ref => $prev_action_ref,
-                        prev_line_len   => $prev_line_len
-                    );
-                }
-                if (!($self->{__mode} & ($PRE)))
-                {
-                    $self->caps(
-                        line_ref        => \$para_lines[$i],
-                        line_action_ref => \$para_line_action[$i]
-                    );
-                }
-
-                # put the "prev" line in front of the first line
-                $para_lines[$i] = $prev . $para_lines[$i]
-                  if ($i == 0 && ($prev !~ /^\s*$/));
-            }
-
-            # para action is the action of the last line of the para
-            $para_action = $para_line_action[$#para_line_action];
-            $para_action = $NONE if (!defined $para_action);
-
-            # push them on the done lines
-            push @done_lines, @para_lines;
-            @para_lines = ();
-
-        }
-        # now put the para back together as one string
-        $para = join('', @done_lines);
-
-        # if this is a paragraph, and we are in XHTML mode,
-        # close an open paragraph.
-        if ($self->{xhtml})
-        {
-            my $open_tag = @{$self->{__tags}}[$#{$self->{__tags}}];
-            if (defined $open_tag && $open_tag eq 'P')
-            {
-                $para .= $self->close_tag('P');
-            }
-        }
-
-        if (
-            $self->{unhyphenation}
-
-            # ends in hyphen & next line starts w/letters
-            && ($para =~ /[^\W\d_]\-\n\s*[^\W\d_]/s) && !(
-                $self->{__mode} &
-                ($PRE | $HEADER | $MAILHEADER | $TABLE | $BREAK)
-            )
-          )
-        {
-            $self->unhyphenate_para(\$para);
-        }
-        # chop trailing newlines for continuing lists and PRE
-        if (   $self->{__mode} & $LIST
-            || $self->{__mode} & $PRE)
-        {
-            $para =~ s/\n$//g;
-        }
-    }
-
-    # apply links and bold/italic formatting
-    if ($para !~ /^\s*$/)
-    {
-        $self->apply_links(
-            para_ref        => \$para,
-            para_action_ref => \$para_action
-        );
-    }
-
-    # close any open lists if required to
-    if (   $args{close_tags}
-        && $self->{__mode} & $LIST)    # End all lists
-    {
-        $self->endlist(
-            num_lists       => $self->{__listnum},
-            prev_ref        => \$para,
-            line_action_ref => \$para_action
-        );
-    }
-    # close any open tags
-    if ($args{close_tags} && $self->{xhtml})
-    {
-        while (@{$self->{__tags}})
-        {
-            $para .= $self->close_tag('');
-        }
-    }
-
-    # convert remaining Microsoft character codes into sensible HTML
-    if ($self->{demoronize})
-    {
-        $para = demoronize_code($para);
-    }
-    # All the matching and formatting is done.  Now we can
-    # replace non-ASCII characters with character entities.
-    if (!$self->{eight_bit_clean})
-    {
-        my @chars = split(//, $para);
-        foreach $_ (@chars)
-        {
-            $_ = $char_entities{$_} if defined($char_entities{$_});
-        }
-        $para = join('', @chars);
-    }
-
-    $self->{__prev_para_action} = $para_action;
-
-    return $para;
-}    # process_para
-
-=head2 txt2html
-
-    $conv->txt2html(%args);
-
-Convert a text file to HTML.  Takes a hash of arguments, or a reference
-to an array of arguments to customize the conversion; (this includes
-saying what file to convert!) See L</OPTIONS> for the possible values of
-the arguments.  Arguments which have already been set with B<new> or
-B<args> will remain as they are, unless they are overridden.
-
-=cut
-
-sub txt2html ($;$)
-{
-    my $self = shift;
-
-    if (@_)
-    {
-        $self->args(@_);
-    }
-
-    $self->do_init_call();
-
-    my $outhandle;
-    my $outhandle_needs_closing;
-
-    # set up the output
-    if ($self->{outhandle})
-    {
-        $outhandle               = $self->{outhandle};
-        $outhandle_needs_closing = 1;
-    }
-    elsif ($self->{outfile} eq "-")
-    {
-        $outhandle               = *STDOUT;
-        $outhandle_needs_closing = 0;
-    }
-    else
-    {
-        open($outhandle, "> " . $self->{outfile})
-          || die "Error: unable to open ", $self->{outfile}, ": $!\n";
-        $outhandle_needs_closing = 1;
-    }
-
-    # slurp up a paragraph at a time, a file at a time
-    local $/ = "";
-    my $para        = '';
-    my $count       = 0;
-    my $print_count = 0;
-    my @sources     = ();
-    my $source_type;
-    if ($self->{infile} and @{$self->{infile}})
-    {
-        @sources     = @{$self->{infile}};
-        $source_type = 'file';
-    }
-    elsif ($self->{inhandle} and @{$self->{inhandle}})
-    {
-        @sources     = @{$self->{inhandle}};
-        $source_type = 'filehandle';
-    }
-    elsif ($self->{instring} and @{$self->{instring}})
-    {
-        @sources     = @{$self->{instring}};
-        $source_type = 'string';
-    }
-    my $inhandle;
-    my $inhandle_needs_closing = 0;
-    foreach my $source (@sources)
-    {
-        $inhandle = undef;
-        if ($source_type eq 'file')
-        {
-            if (!$source or $source eq '-')
-            {
-                $inhandle               = *STDIN;
-                $inhandle_needs_closing = 0;
-            }
-            else
-            {
-                if (-f $source && open($inhandle, $source))
-                {
-                    $inhandle_needs_closing = 1;
-                }
-                else    # error
-                {
-                    warn "Could not open $source\n";
-                    next;
-                }
-            }
-        }
-        elsif ($source_type eq 'filehandle')
-        {
-            $inhandle               = $source;
-            $inhandle_needs_closing = 1;
-        }
-        if ($source_type eq 'string')
-        {
-            # process the string
-            $para = $_;
-            $para =~ s/\n$//;    # trim the endline
-            if ($count == 0)
-            {
-                $self->do_file_start($outhandle, $para);
-            }
-            $self->{__done_with_sect_link} = [];
-            $para = $self->process_chunk($para, close_tags => 0);
-            print $outhandle $para, "\n";
-            $print_count++;
-            $count++;
-        }
-        else                     # file or filehandle
-        {
-            while (<$inhandle>)
-            {
-                $para = $_;
-                $para =~ s/\n$//;    # trim the endline
-                if ($count == 0)
-                {
-                    $self->do_file_start($outhandle, $para);
-                }
-                $self->{__done_with_sect_link} = [];
-                $para = $self->process_chunk($para, close_tags => 0);
-                print $outhandle $para, "\n";
-                $print_count++;
-                $count++;
-            }
-            if ($inhandle_needs_closing)
-            {
-                close($inhandle);
-            }
-        }
-    }    # for each file
-
-    $self->{__prev} = "";
-    if ($self->{__mode} & $LIST)    # End all lists
-    {
-        $self->endlist(
-            num_lists       => $self->{__listnum},
-            prev_ref        => \$self->{__prev},
-            line_action_ref => \$self->{__line_action}
-        );
-    }
-    print $outhandle $self->{__prev};
-
-    # end open preformats
-    if ($self->{__mode} & $PRE)
-    {
-        my $tag = $self->close_tag('PRE');
-        print $outhandle $tag;
-    }
-
-    # close all open tags
-    if (   $self->{xhtml}
-        && !$self->{extract}
-        && @{$self->{__tags}})
-    {
-        if ($self->{dict_debug} & 8)
-        {
-            print STDERR "closing all tags at end\n";
-        }
-        # close any open tags (until we get to the body)
-        my $open_tag = @{$self->{__tags}}[$#{$self->{__tags}}];
-        while (@{$self->{__tags}}
-            && $open_tag ne 'BODY'
-            && $open_tag ne 'HTML')
-        {
-            print $outhandle $self->close_tag('');
-            $open_tag = @{$self->{__tags}}[$#{$self->{__tags}}];
-        }
-        print $outhandle "\n";
-    }
-
-    if ($self->{append_file})
-    {
-        if (-r $self->{append_file})
-        {
-            open(APPEND, $self->{append_file});
-            while (<APPEND>)
-            {
-                print $outhandle $_;
-                $print_count++;
-            }
-            close(APPEND);
-        }
-        else
-        {
-            print STDERR "Can't find or read file ", $self->{append_file},
-              " to append.\n";
-        }
-    }
-
-    # print the closing tags (if we have printed stuff at all)
-    if ($print_count && !$self->{extract})
-    {
-        print $outhandle $self->close_tag('BODY'), "\n";
-        print $outhandle $self->close_tag('HTML'), "\n";
-    }
-    if ($outhandle_needs_closing)
-    {
-        close($outhandle);
-    }
-    return 1;
-}
-
-#---------------------------------------------------------------#
-# Init-related subroutines
-
-#--------------------------------#
-# Name: init_our_data
-# Args:
-#   $self
-sub init_our_data ($)
-{
-    my $self = shift;
-
-    $self->{debug} = 0;
-
-    #
-    # All the options, in alphabetical order
-    #
-    $self->{append_file}           = '';
-    $self->{append_head}           = '';
-    $self->{body_deco}             = '';
-    $self->{bullets}               = '-=o*\267';
-    $self->{bullets_ordered}       = '';
-    $self->{bold_delimiter}        = '#';
-    $self->{caps_tag}              = 'STRONG';
-    $self->{custom_heading_regexp} = [];
-    $self->{default_link_dict}     =
-      ($ENV{HOME} ? "$ENV{HOME}/.txt2html.dict" : '.txt2html.dict');
-    $self->{dict_debug}                 = 0;
-    $self->{doctype}                    = "-//W3C//DTD HTML 3.2 Final//EN";
-    $self->{demoronize}                 = 1;
-    $self->{eight_bit_clean}            = 0;
-    $self->{escape_HTML_chars}          = 1;
-    $self->{explicit_headings}          = 0;
-    $self->{extract}                    = 0;
-    $self->{hrule_min}                  = 4;
-    $self->{indent_width}               = 2;
-    $self->{indent_par_break}           = 0;
-    $self->{infile}                     = [];
-    $self->{inhandle}                   = [];
-    $self->{instring}                   = [];
-    $self->{italic_delimiter}           = '*';
-    $self->{links_dictionaries}         = [];
-    $self->{link_only}                  = 0;
-    $self->{lower_case_tags}            = 0;
-    $self->{mailmode}                   = 0;
-    $self->{make_anchors}               = 1;
-    $self->{make_links}                 = 1;
-    $self->{make_tables}                = 0;
-    $self->{min_caps_length}            = 3;
-    $self->{outfile}                    = '-';
-    $self->{par_indent}                 = 2;
-    $self->{preformat_trigger_lines}    = 2;
-    $self->{endpreformat_trigger_lines} = 2;
-    $self->{preformat_start_marker}     = "^(:?(:?<)|<)PRE(:?(:?>)|>)\$";
-    $self->{preformat_end_marker}       = "^(:?(:?<)|<)/PRE(:?(:?>)|>)\$";
-    $self->{preformat_whitespace_min}   = 5;
-    $self->{prepend_file}               = '';
-    $self->{preserve_indent}            = 0;
-    $self->{short_line_length}          = 40;
-    $self->{style_url}                  = '';
-    $self->{tab_width}                  = 8;
-    $self->{table_type}                 = {
-        ALIGN  => 1,
-        PGSQL  => 1,
-        BORDER => 1,
-        DELIM  => 1,
-    };
-    $self->{title}                      = '';
-    $self->{titlefirst}                 = 0;
-    $self->{underline_length_tolerance} = 1;
-    $self->{underline_offset_tolerance} = 1;
-    $self->{unhyphenation}              = 1;
-    $self->{use_mosaic_header}          = 0;
-    $self->{use_preformat_marker}       = 0;
-    $self->{xhtml}                      = 0;
-
-    # accumulation variables
-    $self->{__file}               = "";    # Current file being processed
-    $self->{__heading_styles}     = {};
-    $self->{__num_heading_styles} = 0;
-    $self->{__links_table}        = {};
-    $self->{__links_table_order}  = [];
-    $self->{__search_patterns}    = [];
-    $self->{__repl_code}          = [];
-    $self->{__prev_para_action}   = 0;
-    $self->{__non_header_anchor}  = 0;
-    $self->{__mode}               = 0;
-    $self->{__listnum}            = 0;
-    $self->{__list_nice_indent}   = "";
-    $self->{__list_indent}        = [];
-
-    $self->{__call_init_done} = 0;
-
-    #
-    # The global links data
-    #
-    # This is stored in the DATA handle, after the __DATA__ at
-    # the end of this file; but because the test scripts (and possibly
-    # other scripts) don't just create one instance of this object,
-    # we have to remember the position of the DATA handle
-    # and reset it after we've read from it, just in case
-    # we have to read from it again.
-    # This also means that we don't close it, either.  Hope that doesn't
-    # cause a problem...
-    #
-    my $curpos = tell(DATA);    # remember the __DATA__ position
-    my @lines  = ();
-    while (<DATA>)
-    {
-        # skip lines that start with '#'
-        next if /^\#/;
-        # skip lines that end with unescaped ':'
-        next if /^.*[^\\]:\s*$/;
-        push @lines, $_;
-    }
-    # reset the data handle to the start, just in case
-    seek(DATA, $curpos, 0);
-    $self->{__global_links_data} = join('', @lines);
-}    # init_our_data
-
-#---------------------------------------------------------------#
-# txt2html-related subroutines
-
-#--------------------------------#
-# Name: deal_with_options
-#   do extra processing related to particular options
-# Args:
-#   $self
-sub deal_with_options ($)
-{
-    my $self = shift;
-
-    if ($self->{links_dictionaries})
-    {
-        # only put into the links dictionaries files which are readable
-        my @dict_files = @{$self->{links_dictionaries}};
-        $self->args(links_dictionaries => []);
-
-        foreach my $ld (@dict_files)
-        {
-            if (-r $ld)
-            {
-                $self->{'make_links'} = 1;
-                $self->args(['--links_dictionaries', $ld]);
-            }
-            else
-            {
-                print STDERR "Can't find or read link-file $ld\n";
-            }
-        }
-    }
-    if (!$self->{make_links})
-    {
-        $self->{'links_dictionaries'} = 0;
-    }
-    if ($self->{append_file})
-    {
-        if (!-r $self->{append_file})
-        {
-            print STDERR "Can't find or read ", $self->{append_file}, "\n";
-            $self->{append_file} = '';
-        }
-    }
-    if ($self->{prepend_file})
-    {
-        if (!-r $self->{prepend_file})
-        {
-            print STDERR "Can't find or read ", $self->{prepend_file}, "\n";
-            $self->{'prepend_file'} = '';
-        }
-    }
-    if ($self->{append_head})
-    {
-        if (!-r $self->{append_head})
-        {
-            print STDERR "Can't find or read ", $self->{append_head}, "\n";
-            $self->{'append_head'} = '';
-        }
-    }
-
-    if (!$self->{outfile})
-    {
-        $self->{'outfile'} = "-";
-    }
-
-    $self->{'preformat_trigger_lines'} = 0
-      if ($self->{preformat_trigger_lines} < 0);
-    $self->{'preformat_trigger_lines'} = 2
-      if ($self->{preformat_trigger_lines} > 2);
-
-    $self->{'endpreformat_trigger_lines'} = 1
-      if ($self->{preformat_trigger_lines} == 0);
-    $self->{'endpreformat_trigger_lines'} = 0
-      if ($self->{endpreformat_trigger_lines} < 0);
-    $self->{'endpreformat_trigger_lines'} = 2
-      if ($self->{endpreformat_trigger_lines} > 2);
-
-    $self->{__preformat_enabled} =
-      (($self->{endpreformat_trigger_lines} != 0)
-          || $self->{use_preformat_marker});
-
-    if ($self->{use_mosaic_header})
-    {
-        my $num_heading_styles = 0;
-        my %heading_styles     = ();
-        $heading_styles{"*"}          = ++$num_heading_styles;
-        $heading_styles{"="}          = ++$num_heading_styles;
-        $heading_styles{"+"}          = ++$num_heading_styles;
-        $heading_styles{"-"}          = ++$num_heading_styles;
-        $heading_styles{"~"}          = ++$num_heading_styles;
-        $heading_styles{"."}          = ++$num_heading_styles;
-        $self->{__heading_styles}     = \%heading_styles;
-        $self->{__num_heading_styles} = $num_heading_styles;
-    }
-    # XHTML implies lower case
-    $self->{'lower_case_tags'} = 1 if ($self->{xhtml});
-}
-
-sub escape ($)
-{
-    my ($text) = @_;
-    $text =~ s/&/&/g;
-    $text =~ s/>/>/g;
-    $text =~ s/</</g;
-    return $text;
-}
-
-#     Added by Alan Jackson, alan at ajackson dot org, and based
-#     on the demoronize script by John Walker, http://www.fourmilab.ch/
-# Convert Microsoft character entities into characters.
-sub demoronize_char($)
-{
-    my $s = shift;
-    #   Map strategically incompatible non-ISO characters in the
-    #   range 0x82 -- 0x9F into plausible substitutes where
-    #   possible.
-
-    $s =~ s/\x82/,/g;
-    $s =~ s/\x84/,,/g;
-    $s =~ s/\x85/.../g;
-
-    $s =~ s/\x88/^/g;
-
-    $s =~ s/\x8B/</g;
-    $s =~ s/\x8C/Oe/g;
-
-    $s =~ s/\x91/`/g;
-    $s =~ s/\x92/'/g;
-    $s =~ s/\x93/"/g;
-    $s =~ s/\x94/"/g;
-    $s =~ s/\x95/*/g;
-    $s =~ s/\x96/-/g;
-    $s =~ s/\x97/--/g;
-
-    $s =~ s/\x9B/>/g;
-    $s =~ s/\x9C/oe/g;
-
-    return $s;
-}
-
-# convert Microsoft character entities into HTML code
-sub demoronize_code($)
-{
-    my $s = shift;
-    #   Map strategically incompatible non-ISO characters in the
-    #   range 0x82 -- 0x9F into plausible substitutes where
-    #   possible.
-
-    $s =~ s-\x83-<em>f</em>-g;
-
-    $s =~ s-\x98-<sup>~</sup>-g;
-    $s =~ s-\x99-<sup>TM</sup>-g;
-
-    return $s;
-}
-
-# output the tag wanted (add the <> and the / if necessary)
-# - output in lower or upper case
-# - do tag-related processing
-# options:
-#   tag_type=>'start' | tag_type=>'end' | tag_type=>'empty'
-#   (default start)
-#   inside_tag=>string (default empty)
-sub get_tag ($$;%)
-{
-    my $self   = shift;
-    my $in_tag = shift;
-    my %args   = (
-        tag_type   => 'start',
-        inside_tag => '',
-        @_
-    );
-    my $inside_tag = $args{inside_tag};
-
-    my $open_tag = @{$self->{__tags}}[$#{$self->{__tags}}];
-    if (!defined $open_tag)
-    {
-        $open_tag = '';
-    }
-    # close any open tags that need closing
-    # Note that we only have to check for the structural tags we make,
-    # not every possible HTML tag
-    my $tag_prefix = '';
-    if ($self->{xhtml})
-    {
-        if (    $open_tag eq 'P'
-            and $in_tag eq 'P'
-            and $args{tag_type} ne 'end')
-        {
-            $tag_prefix = $self->close_tag('P');
-        }
-        elsif ( $open_tag eq 'P'
-            and $in_tag =~ /^(HR|UL|OL|DL|PRE|TABLE|H)/)
-        {
-            $tag_prefix = $self->close_tag('P');
-        }
-        elsif ( $open_tag eq 'LI'
-            and $in_tag eq 'LI'
-            and $args{tag_type} ne 'end')
-        {
-            # close a LI before the next LI
-            $tag_prefix = $self->close_tag('LI');
-        }
-        elsif ( $open_tag eq 'LI'
-            and $in_tag =~ /^(UL|OL)$/
-            and $args{tag_type} eq 'end')
-        {
-            # close the LI before the list closes
-            $tag_prefix = $self->close_tag('LI');
-        }
-        elsif ( $open_tag eq 'DT'
-            and $in_tag eq 'DD'
-            and $args{tag_type} ne 'end')
-        {
-            # close a DT before the next DD
-            $tag_prefix = $self->close_tag('DT');
-        }
-        elsif ( $open_tag eq 'DD'
-            and $in_tag eq 'DT'
-            and $args{tag_type} ne 'end')
-        {
-            # close a DD before the next DT
-            $tag_prefix = $self->close_tag('DD');
-        }
-        elsif ( $open_tag eq 'DD'
-            and $in_tag         eq 'DL'
-            and $args{tag_type} eq 'end')
-        {
-            # close the DD before the list closes
-            $tag_prefix = $self->close_tag('DD');
-        }
-    }
-
-    my $out_tag = $in_tag;
-    if ($args{tag_type} eq 'end')
-    {
-        $out_tag = $self->close_tag($in_tag);
-    }
-    else
-    {
-        if ($self->{lower_case_tags})
-        {
-            $out_tag =~ tr/A-Z/a-z/;
-        }
-        else    # upper case
-        {
-            $out_tag =~ tr/a-z/A-Z/;
-        }
-        if ($args{tag_type} eq 'empty')
-        {
-            if ($self->{xhtml})
-            {
-                $out_tag = "<${out_tag}${inside_tag}/>";
-            }
-            else
-            {
-                $out_tag = "<${out_tag}${inside_tag}>";
-            }
-        }
-        else
-        {
-            push @{$self->{__tags}}, $in_tag;
-            $out_tag = "<${out_tag}${inside_tag}>";
-        }
-    }
-    $out_tag = $tag_prefix . $out_tag if $tag_prefix;
-    if ($self->{dict_debug} & 8)
-    {
-        print STDERR
-          "open_tag = '${open_tag}', in_tag = '${in_tag}', tag_type = ",
-          $args{tag_type},
-          ", inside_tag = '${inside_tag}', out_tag = '$out_tag'\n";
-    }
-
-    return $out_tag;
-}    # get_tag
-
-# close the open tag
-sub close_tag ($$)
-{
-    my $self   = shift;
-    my $in_tag = shift;
-
-    my $open_tag = pop @{$self->{__tags}};
-    $in_tag ||= $open_tag;
-    # put the open tag back on the stack if the in-tag is not the same
-    if (defined $open_tag && $open_tag ne $in_tag)
-    {
-        push @{$self->{__tags}}, $open_tag;
-    }
-    my $out_tag = $in_tag;
-    if ($self->{lower_case_tags})
-    {
-        $out_tag =~ tr/A-Z/a-z/;
-    }
-    else    # upper case
-    {
-        $out_tag =~ tr/a-z/A-Z/;
-    }
-    $out_tag = "<\/${out_tag}>";
-    if ($self->{dict_debug} & 8)
-    {
-        print STDERR
-"close_tag: open_tag = '${open_tag}', in_tag = '${in_tag}', out_tag = '$out_tag'\n";
-    }
-
-    return $out_tag;
-}
-
-sub hrule ($%)
-{
-    my $self = shift;
-    my %args = (
-        para_lines_ref  => undef,
-        para_action_ref => undef,
-        ind             => 0,
-        @_
-    );
-    my $para_lines_ref  = $args{para_lines_ref};
-    my $para_action_ref = $args{para_action_ref};
-    my $ind             = $args{ind};
-
-    my $hrmin = $self->{hrule_min};
-    if ($para_lines_ref->[$ind] =~ /^\s*([-_~=\*]\s*){$hrmin,}$/)
-    {
-        my $tag = $self->get_tag("HR", tag_type => 'empty');
-        $para_lines_ref->[$ind] = "$tag\n";
-        $para_action_ref->[$ind] |= $HRULE;
-    }
-    elsif ($para_lines_ref->[$ind] =~ /\014/)
-    {
-        # Linefeeds become horizontal rules
-        $para_action_ref->[$ind] |= $HRULE;
-        my $tag = $self->get_tag("HR", tag_type => 'empty');
-        $para_lines_ref->[$ind] =~ s/\014/\n${tag}\n/g;
-    }
-}
-
-sub shortline ($%)
-{
-    my $self = shift;
-    my %args = (
-        line_ref        => undef,
-        line_action_ref => undef,
-        prev_ref        => undef,
-        prev_action_ref => undef,
-        prev_line_len   => 0,
-        @_
-    );
-    my $mode_ref        = $args{mode_ref};
-    my $line_ref        = $args{line_ref};
-    my $line_action_ref = $args{line_action_ref};
-    my $prev_ref        = $args{prev_ref};
-    my $prev_action_ref = $args{prev_action_ref};
-    my $prev_line_len   = $args{prev_line_len};
-
-    # Short lines should be broken even on list item lines iff the
-    # following line is more text.  I haven't figured out how to do
-    # that yet.  For now, I'll just not break on short lines in lists.
-    # (sorry)
-
-    my $tag = $self->get_tag('BR', tag_type => 'empty');
-    if (
-           ${$line_ref} !~ /^\s*$/
-        && ${$prev_ref} !~ /^\s*$/
-        && ($prev_line_len < $self->{short_line_length})
-        && !(
-            ${$line_action_ref} &
-            ($END | $HEADER | $HRULE | $LIST | $IND_BREAK | $PAR)
-        )
-        && !(${$prev_action_ref} & ($HEADER | $HRULE | $BREAK | $IND_BREAK))
-      )
-    {
-        ${$prev_ref} .= $tag . chop(${$prev_ref});
-        ${$prev_action_ref} |= $BREAK;
-    }
-}
-
-sub is_mailheader ($%)
-{
-    my $self = shift;
-    my %args = (
-        rows_ref => undef,
-        @_
-    );
-    my $rows_ref = $args{rows_ref};
-
-    # a mail header is assumed to be the whole
-    # paragraph which starts with a From , From: or Newsgroups: line
-
-    if ($rows_ref->[0] =~ /^(From:?)|(Newsgroups:) /)
-    {
-        return 1;
-    }
-    return 0;
-
-}    # is_mailheader
-
-sub mailheader ($%)
-{
-    my $self = shift;
-    my %args = (
-        rows_ref => undef,
-        @_
-    );
-    my $rows_ref = $args{rows_ref};
-
-    # a mail header is assumed to be the whole
-    # paragraph which starts with a From: or Newsgroups: line
-    my $tag  = '';
-    my @rows = @{$rows_ref};
-
-    if ($self->is_mailheader(%args))
-    {
-        $self->{__mode} |= $MAILHEADER;
-        if ($self->{escape_HTML_chars})
-        {
-            $rows[0] = escape($rows[0]);
-        }
-        $self->anchor_mail(\$rows[0]);
-        chomp ${rows}[0];
-        $tag = $self->get_tag('P', inside_tag => " class='mail_header'");
-        my $tag2 = $self->get_tag('BR', tag_type => 'empty');
-        $rows[0] =
-          join('', "<!-- New Message -->\n", $tag, $rows[0], $tag2, "\n");
-        # now put breaks on the rest of the paragraph
-        # apart from the last line
-        for (my $rn = 1; $rn < @rows; $rn++)
-        {
-            if ($self->{escape_HTML_chars})
-            {
-                $rows[$rn] = escape($rows[$rn]);
-            }
-            if ($rn != (@rows - 1))
-            {
-                $tag = $self->get_tag('BR', tag_type => 'empty');
-                chomp $rows[$rn];
-                $rows[$rn] =~ s/$/${tag}\n/;
-            }
-        }
-    }
-    @{$rows_ref} = @rows;
-
-}    # mailheader
-
-sub mailquote ($%)
-{
-    my $self = shift;
-    my %args = (
-        line_ref        => undef,
-        line_action_ref => undef,
-        prev_ref        => undef,
-        prev_action_ref => undef,
-        next_ref        => undef,
-        @_
-    );
-    my $line_ref        = $args{line_ref};
-    my $line_action_ref = $args{line_action_ref};
-    my $prev_ref        = $args{prev_ref};
-    my $prev_action_ref = $args{prev_action_ref};
-    my $next_ref        = $args{next_ref};
-
-    my $tag = '';
-    if (
-        (
-            (${$line_ref} =~ /^\w*>/)    # Handle "FF> Werewolves."
-            || (${$line_ref} =~ /^[\|:]/)
-        )                                  # Handle "[|:] There wolves."
-        && defined($next_ref) && (${$next_ref} !~ /^\s*$/)
-      )
-    {
-        $tag = $self->get_tag('BR', tag_type => 'empty');
-        ${$line_ref} =~ s/$/${tag}/;
-        ${$line_action_ref} |= ($BREAK | $MAILQUOTE);
-        if (!(${$prev_action_ref} & ($BREAK | $MAILQUOTE)))
-        {
-            $tag = $self->get_tag('P', inside_tag => " class='quote_mail'");
-            ${$prev_ref} .= $tag;
-            ${$line_action_ref} |= $PAR;
-        }
-    }
-}
-
-# Subtracts modes listed in $mask from $vector.
-sub subtract_modes ($$)
-{
-    my ($vector, $mask) = @_;
-    return ($vector | $mask) - $mask;
-}
-
-sub paragraph ($%)
-{
-    my $self = shift;
-    my %args = (
-        line_ref        => undef,
-        line_action_ref => undef,
-        prev_ref        => undef,
-        prev_action_ref => undef,
-        line_indent     => 0,
-        prev_indent     => 0,
-        is_fragment     => 0,
-        ind             => 0,
-        @_
-    );
-    my $line_ref        = $args{line_ref};
-    my $line_action_ref = $args{line_action_ref};
-    my $prev_ref        = $args{prev_ref};
-    my $prev_action_ref = $args{prev_action_ref};
-    my $line_indent     = $args{line_indent};
-    my $prev_indent     = $args{prev_indent};
-    my $is_fragment     = $args{is_fragment};
-    my $line_no         = $args{ind};
-
-    my $tag = '';
-    if (
-        ${$line_ref} !~ /^\s*$/
-        && !subtract_modes(
-            ${$line_action_ref}, $END | $MAILQUOTE | $CAPS | $BREAK
-        )
-        && (   ${$prev_ref} =~ /^\s*$/
-            || (${$line_action_ref} & $END)
-            || ($line_indent > $prev_indent + $self->{par_indent}))
-        && !($is_fragment && $line_no == 0)
-      )
-    {
-
-        if (   $self->{indent_par_break}
-            && ${$prev_ref} !~ /^\s*$/
-            && !(${$line_action_ref} & $END)
-            && ($line_indent > $prev_indent + $self->{par_indent}))
-        {
-            $tag = $self->get_tag('BR', tag_type => 'empty');
-            ${$prev_ref} .= $tag;
-            ${$prev_ref} .= " " x $line_indent;
-            ${$line_ref} =~ s/^ {$line_indent}//;
-            ${$prev_action_ref} |= $BREAK;
-            ${$line_action_ref} |= $IND_BREAK;
-        }
-        elsif ($self->{preserve_indent})
-        {
-            $tag = $self->get_tag('P');
-            ${$prev_ref} .= $tag;
-            ${$prev_ref} .= " " x $line_indent;
-            ${$line_ref} =~ s/^ {$line_indent}//;
-            ${$line_action_ref} |= $PAR;
-        }
-        else
-        {
-            $tag = $self->get_tag('P');
-            ${$prev_ref} .= $tag;
-            ${$line_action_ref} |= $PAR;
-        }
-    }
-    # detect also a continuing indentation at the same level
-    elsif ($self->{indent_par_break}
-        && !($self->{__mode} & ($PRE | $TABLE | $LIST))
-        && ${$prev_ref} !~ /^\s*$/
-        && !(${$line_action_ref} & $END)
-        && (${$prev_action_ref} & ($IND_BREAK | $PAR))
-        && !subtract_modes(${$line_action_ref}, $END | $MAILQUOTE | $CAPS)
-        && ($line_indent > $self->{par_indent})
-        && ($line_indent == $prev_indent))
-    {
-        $tag = $self->get_tag('BR', tag_type => 'empty');
-        ${$prev_ref} .= $tag;
-        ${$prev_ref} .= " " x $line_indent;
-        ${$line_ref} =~ s/^ {$line_indent}//;
-        ${$prev_action_ref} |= $BREAK;
-        ${$line_action_ref} |= $IND_BREAK;
-    }
-}
-
-sub listprefix ($$)
-{
-    my $self = shift;
-    my $line = shift;
-
-    my ($prefix, $number, $rawprefix, $term);
-
-    my $bullets         = $self->{bullets};
-    my $bullets_ordered = $self->{bullets_ordered};
-    my $number_match    = '(\d+|[^\W\d])';
-    if ($bullets_ordered)
-    {
-        $number_match = '(\d+|[a-zA-Z]|[' . "${bullets_ordered}])";
-    }
-    $self->{__number_match} = $number_match;
-    my $term_match = '(\w\w+)';
-    $self->{__term_match} = $term_match;
-    return (0, 0, 0, 0)
-      if ( !($line =~ /^\s*[${bullets}]\s+\S/)
-        && !($line =~ /^\s*${number_match}[\.\)\]:]\s+\S/)
-        && !($line =~ /^\s*${term_match}:$/));
-
-    ($term)   = $line =~ /^\s*${term_match}:$/;
-    ($number) = $line =~ /^\s*${number_match}\S\s+\S/;
-    $number = 0 unless defined($number);
-    if (   $bullets_ordered
-        && $number =~ /[${bullets_ordered}]/)
-    {
-        $number = 1;
-    }
-
-    # That slippery exception of "o" as a bullet
-    # (This ought to be determined using the context of what lists
-    #  we have in progress, but this will probably work well enough.)
-    if ($bullets =~ /o/ && $line =~ /^\s*o\s/)
-    {
-        $number = 0;
-    }
-
-    if ($term)
-    {
-        ($rawprefix) = $line =~ /^(\s*${term_match}.)$/;
-        $prefix = $rawprefix;
-        $prefix =~ s/${term_match}//;    # Take the term out
-    }
-    elsif ($number)
-    {
-        ($rawprefix) = $line =~ /^(\s*${number_match}.)/;
-        $prefix = $rawprefix;
-        $prefix =~ s/${number_match}//;    # Take the number out
-    }
-    else
-    {
-        ($rawprefix) = $line =~ /^(\s*[${bullets}].)/;
-        $prefix = $rawprefix;
-    }
-    ($prefix, $number, $rawprefix, $term);
-}    # listprefix
-
-sub startlist ($%)
-{
-    my $self = shift;
-    my %args = (
-        prefix          => '',
-        number          => 0,
-        rawprefix       => '',
-        term            => '',
-        para_lines_ref  => undef,
-        para_action_ref => undef,
-        ind             => 0,
-        prev_ref        => undef,
-        total_prefix    => '',
-        @_
-    );
-    my $prefix          = $args{prefix};
-    my $number          = $args{number};
-    my $rawprefix       = $args{rawprefix};
-    my $term            = $args{term};
-    my $para_lines_ref  = $args{para_lines_ref};
-    my $para_action_ref = $args{para_action_ref};
-    my $ind             = $args{ind};
-    my $prev_ref        = $args{prev_ref};
-
-    my $tag = '';
-    $self->{__listprefix}->[$self->{__listnum}] = $prefix;
-    if ($number)
-    {
-
-        # It doesn't start with 1,a,A.  Let's not screw with it.
-        if (($number ne "1") && ($number ne "a") && ($number ne "A"))
-        {
-            return 0;
-        }
-        $tag = $self->get_tag('OL');
-        ${$prev_ref} .= join('', $self->{__list_nice_indent}, $tag, "\n");
-        $self->{__list}->[$self->{__listnum}] = $OL;
-    }
-    elsif ($term)
-    {
-        $tag = $self->get_tag('DL');
-        ${$prev_ref} .= join('', $self->{__list_nice_indent}, $tag, "\n");
-        $self->{__list}->[$self->{__listnum}] = $DL;
-    }
-    else
-    {
-        $tag = $self->get_tag('UL');
-        ${$prev_ref} .= join('', $self->{__list_nice_indent}, $tag, "\n");
-        $self->{__list}->[$self->{__listnum}] = $UL;
-    }
-
-    $self->{__list_indent}->[$self->{__listnum}] = length($args{total_prefix});
-    $self->{__listnum}++;
-    $self->{__list_nice_indent} =
-      " " x $self->{__listnum} x $self->{indent_width};
-    $para_action_ref->[$ind] |= $LIST;
-    $para_action_ref->[$ind] |= $LIST_START;
-    $self->{__mode}          |= $LIST;
-    1;
-}    # startlist
-
-# End N lists
-sub endlist ($%)
-{
-    my $self = shift;
-    my %args = (
-        num_lists       => 0,
-        prev_ref        => undef,
-        line_action_ref => undef,
-        @_
-    );
-    my $n               = $args{num_lists};
-    my $prev_ref        = $args{prev_ref};
-    my $line_action_ref = $args{line_action_ref};
-
-    my $tag = '';
-    for (; $n > 0; $n--, $self->{__listnum}--)
-    {
-        $self->{__list_nice_indent} =
-          " " x ($self->{__listnum} - 1) x $self->{indent_width};
-        if ($self->{__list}->[$self->{__listnum} - 1] == $UL)
-        {
-            $tag = $self->get_tag('UL', tag_type => 'end');
-            ${$prev_ref} .= join('', $self->{__list_nice_indent}, $tag, "\n");
-            pop @{$self->{__list_indent}};
-        }
-        elsif ($self->{__list}->[$self->{__listnum} - 1] == $OL)
-        {
-            $tag = $self->get_tag('OL', tag_type => 'end');
-            ${$prev_ref} .= join('', $self->{__list_nice_indent}, $tag, "\n");
-            pop @{$self->{__list_indent}};
-        }
-        elsif ($self->{__list}->[$self->{__listnum} - 1] == $DL)
-        {
-            $tag = $self->get_tag('DL', tag_type => 'end');
-            ${$prev_ref} .= join('', $self->{__list_nice_indent}, $tag, "\n");
-            pop @{$self->{__list_indent}};
-        }
-        else
-        {
-            print STDERR "Encountered list of unknown type\n";
-        }
-    }
-    ${$line_action_ref} |= $END;
-    $self->{__mode} ^= $LIST if (!$self->{__listnum});
-}    # endlist
-
-sub continuelist ($%)
-{
-    my $self = shift;
-    my %args = (
-        para_lines_ref  => undef,
-        para_action_ref => undef,
-        ind             => 0,
-        term            => '',
-        @_
-    );
-    my $para_lines_ref  = $args{para_lines_ref};
-    my $para_action_ref = $args{para_action_ref};
-    my $ind             = $args{ind};
-    my $term            = $args{term};
-
-    my $list_indent = $self->{__list_nice_indent};
-    my $bullets     = $self->{bullets};
-    my $num_match   = $self->{__number_match};
-    my $term_match  = $self->{__term_match};
-    my $tag         = '';
-    if (   $self->{__list}->[$self->{__listnum} - 1] == $UL
-        && $para_lines_ref->[$ind] =~ /^\s*[${bullets}]\s*/)
-    {
-        $tag = $self->get_tag('LI');
-        $para_lines_ref->[$ind] =~ s/^\s*[${bullets}]\s*/${list_indent}${tag}/;
-        $para_action_ref->[$ind] |= $LIST_ITEM;
-    }
-    if ($self->{__list}->[$self->{__listnum} - 1] == $OL)
-    {
-        $tag = $self->get_tag('LI');
-        $para_lines_ref->[$ind] =~ s/^\s*${num_match}.\s*/${list_indent}${tag}/;
-        $para_action_ref->[$ind] |= $LIST_ITEM;
-    }
-    if (   $self->{__list}->[$self->{__listnum} - 1] == $DL
-        && $term)
-    {
-        $tag = $self->get_tag('DT');
-        my $tag2 = $self->get_tag('DT', tag_type => 'end');
-        $term =~ s/_/ /g;    # underscores are now spaces in the term
-        $para_lines_ref->[$ind] =~
-          s/^\s*${term_match}.$/${list_indent}${tag}${term}${tag2}/;
-        $tag = $self->get_tag('DD');
-        $para_lines_ref->[$ind] .= ${tag};
-        $para_action_ref->[$ind] |= $LIST_ITEM;
-    }
-    $para_action_ref->[$ind] |= $LIST;
-}    # continuelist
-
-sub liststuff ($%)
-{
-    my $self = shift;
-    my %args = (
-        para_lines_ref       => undef,
-        para_action_ref      => undef,
-        para_line_indent_ref => undef,
-        ind                  => 0,
-        prev_ref             => undef,
-        @_
-    );
-    my $para_lines_ref       = $args{para_lines_ref};
-    my $para_action_ref      = $args{para_action_ref};
-    my $para_line_indent_ref = $args{para_line_indent_ref};
-    my $ind                  = $args{ind};
-    my $prev_ref             = $args{prev_ref};
-
-    my $i;
-
-    my ($prefix, $number, $rawprefix, $term) =
-      $self->listprefix($para_lines_ref->[$ind]);
-
-    if (!$prefix)
-    {
-        # if the previous line is not blank
-        if ($ind > 0 && $para_lines_ref->[$ind - 1] !~ /^\s*$/)
-        {
-            # inside a list item
-            return;
-        }
-        # This might be a new paragraph within an existing list item;
-        # It will be the first line, and have the same indentation
-        # as the list's indentation.
-        if (   $ind == 0
-            && $self->{__listnum}
-            && $para_line_indent_ref->[$ind] ==
-            $self->{__list_indent}->[$self->{__listnum} - 1])
-        {
-            # start a paragraph
-            my $tag = $self->get_tag('P');
-            ${$prev_ref} .= $tag;
-            $para_action_ref->[$ind] |= $PAR;
-            return;
-        }
-        # This ain't no list.  We'll want to end all of them.
-        if ($self->{__listnum})
-        {
-            $self->endlist(
-                num_lists       => $self->{__listnum},
-                prev_ref        => $prev_ref,
-                line_action_ref => \$para_action_ref->[$ind]
-            );
-        }
-        return;
-    }
-
-    # If numbers with more than one digit grow to the left instead of
-    # to the right, the prefix will shrink and we'll fail to match the
-    # right list.  We need to account for this.
-    my $prefix_alternate;
-    if (length("" . $number) > 1)
-    {
-        $prefix_alternate = (" " x (length("" . $number) - 1)) . $prefix;
-    }
-
-    # Maybe we're going back up to a previous list
-    for (
-        $i = $self->{__listnum} - 1;
-        ($i >= 0) && ($prefix ne $self->{__listprefix}->[$i]);
-        $i--
-      )
-    {
-        if (length("" . $number) > 1)
-        {
-            last if $prefix_alternate eq $self->{__listprefix}->[$i];
-        }
-    }
-
-    my $islist;
-
-    # Measure the indent from where the text starts, not where the
-    # prefix starts.  This won't screw anything up, and if we don't do
-    # it, the next line might appear to be indented relative to this
-    # line, and get tagged as a new paragraph.
-    my $bullets         = $self->{bullets};
-    my $bullets_ordered = $self->{bullets_ordered};
-    my $term_match      = $self->{__term_match};
-    my ($total_prefix)  =
-      $para_lines_ref->[$ind] =~ /^(\s*[${bullets}${bullets_ordered}\w]+.\s*)/;
-    # a DL indent starts from the edge of the term, plus indent_width
-    if ($term)
-    {
-        ($total_prefix) = $para_lines_ref->[$ind] =~ /^(\s*)${term_match}.$/;
-        $total_prefix .= " " x $self->{indent_width};
-    }
-
-    # Of course, we only use it if it really turns out to be a list.
-
-    $islist = 1;
-    $i++;
-    if (($i > 0) && ($i != $self->{__listnum}))
-    {
-        $self->endlist(
-            num_lists       => $self->{__listnum} - $i,
-            prev_ref        => $prev_ref,
-            line_action_ref => \$para_action_ref->[$ind]
-        );
-        $islist = 0;
-    }
-    elsif (!$self->{__listnum} || ($i != $self->{__listnum}))
-    {
-        if (
-               ($para_line_indent_ref->[$ind] > 0)
-            || $ind == 0
-            || ($ind > 0 && ($para_lines_ref->[$ind - 1] =~ /^\s*$/))
-            || (   $ind > 0
-                && $para_action_ref->[$ind - 1] & ($BREAK | $HEADER | $CAPS))
-          )
-        {
-            $islist = $self->startlist(
-                prefix          => $prefix,
-                number          => $number,
-                rawprefix       => $rawprefix,
-                term            => $term,
-                para_lines_ref  => $para_lines_ref,
-                para_action_ref => $para_action_ref,
-                ind             => $ind,
-                prev_ref        => $prev_ref,
-                total_prefix    => $total_prefix
-            );
-        }
-        else
-        {
-
-            # We have something like this: "- foo" which usually
-            # turns out not to be a list.
-            return;
-        }
-    }
-
-    $self->continuelist(
-        para_lines_ref  => $para_lines_ref,
-        para_action_ref => $para_action_ref,
-        ind             => $ind,
-        term            => $term
-      )
-      if ($self->{__mode} & $LIST);
-    $para_line_indent_ref->[$ind] = length($total_prefix) if $islist;
-}    # liststuff
-
-# figure out the table type of this table, if any
-sub get_table_type ($%)
-{
-    my $self = shift;
-    my %args = (
-        rows_ref => undef,
-        para_len => 0,
-        @_
-    );
-    my $table_type = 0;
-    if (   $self->{table_type}->{DELIM}
-        && $self->is_delim_table(%args))
-    {
-        $table_type = $TAB_DELIM;
-    }
-    elsif ($self->{table_type}->{ALIGN}
-        && $self->is_aligned_table(%args))
-    {
-        $table_type = $TAB_ALIGN;
-    }
-    elsif ($self->{table_type}->{PGSQL}
-        && $self->is_pgsql_table(%args))
-    {
-        $table_type = $TAB_PGSQL;
-    }
-    elsif ($self->{table_type}->{BORDER}
-        && $self->is_border_table(%args))
-    {
-        $table_type = $TAB_BORDER;
-    }
-
-    return $table_type;
-}
-
-# check if the given paragraph-array is an aligned table
-sub is_aligned_table ($%)
-{
-    my $self = shift;
-    my %args = (
-        rows_ref => undef,
-        para_len => 0,
-        @_
-    );
-    my $rows_ref = $args{rows_ref};
-    my $para_len = $args{para_len};
-
-    # TABLES: spot and mark up tables.  We combine the lines of the
-    # paragraph using the string bitwise or (|) operator, the result
-    # being in $spaces.  A character in $spaces is a space only if
-    # there was a space at that position in every line of the
-    # paragraph.  $space can be used to search for contiguous spaces
-    # that occur on all lines of the paragraph.  If this results in at
-    # least two columns, the paragraph is identified as a table.
-
-    # Note that this sub must be called before checking for preformatted
-    # lines because a table may well have whitespace to the left, in
-    # which case it must not be incorrectly recognised as a preformat.
-    my @rows = @{$rows_ref};
-    my @starts;
-    my $spaces = '';
-    my $max    = 0;
-    my $min    = $para_len;
-    foreach my $row (@rows)
-    {
-        ($spaces |= $row) =~ tr/ /\xff/c;
-        $min = length $row if length $row < $min;
-        $max = length $row if $max < length $row;
-    }
-    $spaces = substr $spaces, 0, $min;
-    push(@starts, 0) unless $spaces =~ /^ /;
-    while ($spaces =~ /((?:^| ) +)(?=[^ ])/g)
-    {
-        push @starts, pos($spaces);
-    }
-
-    if (2 <= @rows and 2 <= @starts)
-    {
-        return 1;
-    }
-    else
-    {
-        return 0;
-    }
-}
-
-sub is_pgsql_table ($%)
-{
-    my $self = shift;
-    my %args = (
-        rows_ref => undef,
-        para_len => 0,
-        @_
-    );
-    my $rows_ref = $args{rows_ref};
-    my $para_len = $args{para_len};
-
-    # a PGSQL table can start with an optional table-caption,
-    # then it has a row of column headings separated by |
-    # then it has a row of ------+-----
-    # then it has one or more rows of column values separated by |
-    # then it has a row-count (N rows)
-    # Thus it must have at least 4 rows.
-    if (@{$rows_ref} < 4)
-    {
-        return 0;
-    }
-
-    my @rows = @{$rows_ref};
-    if ($rows[0] !~ /\|/ && $rows[0] =~ /^\s*\w+/)    # possible caption
-    {
-        shift @rows;
-    }
-    if (@rows < 4)
-    {
-        return 0;
-    }
-    if ($rows[0] !~ /^\s*\w+\s+\|\s+/)                # Colname |
-    {
-        return 0;
-    }
-    if ($rows[1] !~ /^\s*[-]+[+][-]+/)                # ----+----
-    {
-        return 0;
-    }
-    if ($rows[2] !~ /^\s*[^|]*\s+\|\s+/)              # value |
-    {
-        return 0;
-    }
-    # check the last row for rowcount
-    if ($rows[$#rows] !~ /\(\d+\s+rows\)/)
-    {
-        return 0;
-    }
-
-    return 1;
-}
-
-sub is_border_table ($%)
-{
-    my $self = shift;
-    my %args = (
-        rows_ref => undef,
-        para_len => 0,
-        @_
-    );
-    my $rows_ref = $args{rows_ref};
-    my $para_len = $args{para_len};
-
-    # a BORDER table can start with an optional table-caption,
-    # then it has a row of +------+-----+
-    # then it has a row of column headings separated by |
-    # then it has a row of +------+-----+
-    # then it has one or more rows of column values separated by |
-    # then it has a row of +------+-----+
-    # Thus it must have at least 5 rows.
-    # And note that it could be indented with spaces
-    if (@{$rows_ref} < 5)
-    {
-        return 0;
-    }
-
-    my @rows = @{$rows_ref};
-    if ($rows[0] !~ /\|/ && $rows[0] =~ /^\s*\w+/)    # possible caption
-    {
-        shift @rows;
-    }
-    if (@rows < 5)
-    {
-        return 0;
-    }
-    if ($rows[0] !~ /^\s*[+][-]+[+][-]+[+][-+]*$/)    # +----+----+
-    {
-        return 0;
-    }
-    if ($rows[1] !~ /^\s*\|\s*\w+\s+\|\s+.*\|$/)      # | Colname |
-    {
-        return 0;
-    }
-    if ($rows[2] !~ /^\s*[+][-]+[+][-]+[+][-+]*$/)    # +----+----+
-    {
-        return 0;
-    }
-    if ($rows[3] !~ /^\s*\|\s*[^|]*\s+\|\s+.*\|$/)    # | value |
-    {
-        return 0;
-    }
-    # check the last row for +------+------+
-    if ($rows[$#rows] !~ /^\s*[+][-]+[+][-]+[+][-+]*$/)    # +----+----+
-    {
-        return 0;
-    }
-
-    return 1;
-}    # is_border_table
-
-sub is_delim_table ($%)
-{
-    my $self = shift;
-    my %args = (
-        rows_ref => undef,
-        para_len => 0,
-        @_
-    );
-    my $rows_ref = $args{rows_ref};
-    my $para_len = $args{para_len};
-
-    # a DELIM table can start with an optional table-caption,
-    # then it has at least two rows which start and end and are
-    # punctuated by a non-alphanumeric delimiter.
-    #
-    # | val1 | val2 |
-    # | val3 | val4 |
-    #
-    # And note that it could be indented with spaces
-    if (@{$rows_ref} < 2)
-    {
-        return 0;
-    }
-
-    my @rows = @{$rows_ref};
-    if ($rows[0] !~ /[^\w\s]/ && $rows[0] =~ /^\s*\w+/)    # possible caption
-    {
-        shift @rows;
-    }
-    if (@rows < 2)
-    {
-        return 0;
-    }
-    # figure out if the row starts with a possible delimiter
-    my $delim = '';
-    if ($rows[0] =~ /^\s*([^a-zA-Z0-9])/)
-    {
-        $delim = $1;
-        # have to get rid of ^ and []
-        $delim =~ s/\^//g;
-        $delim =~ s/\[//g;
-        $delim =~ s/\]//g;
-        if (!$delim)    # no delimiter after all
-        {
-            return 0;
-        }
-    }
-    else
-    {
-        return 0;
-    }
-    # There needs to be at least three delimiters in the row
-    my @all_delims = ($rows[0] =~ /[${delim}]/g);
-    my $total_num_delims = @all_delims;
-    if ($total_num_delims < 3)
-    {
-        return 0;
-    }
-    # All rows must start and end with the delimiter
-    # and have $total_num_delims number of them
-    foreach my $row (@rows)
-    {
-        if ($row !~ /^\s*[${delim}]/)
-        {
-            return 0;
-        }
-        if ($row !~ /[${delim}]\s*$/)
-        {
-            return 0;
-        }
-        @all_delims = ($row =~ /[${delim}]/g);
-        if (@all_delims != $total_num_delims)
-        {
-            return 0;
-        }
-    }
-
-    return 1;
-}    # is_delim_table
-
-sub tablestuff ($%)
-{
-    my $self = shift;
-    my %args = (
-        table_type => 0,
-        rows_ref   => undef,
-        para_len   => 0,
-        @_
-    );
-    my $table_type = $args{table_type};
-    if ($table_type eq $TAB_ALIGN)
-    {
-        return $self->make_aligned_table(%args);
-    }
-    if ($table_type eq $TAB_PGSQL)
-    {
-        return $self->make_pgsql_table(%args);
-    }
-    if ($table_type eq $TAB_BORDER)
-    {
-        return $self->make_border_table(%args);
-    }
-    if ($table_type eq $TAB_DELIM)
-    {
-        return $self->make_delim_table(%args);
-    }
-}    # tablestuff
-
-sub make_aligned_table ($%)
-{
-    my $self = shift;
-    my %args = (
-        rows_ref => undef,
-        para_len => 0,
-        @_
-    );
-    my $rows_ref = $args{rows_ref};
-    my $para_len = $args{para_len};
-
-    # TABLES: spot and mark up tables.  We combine the lines of the
-    # paragraph using the string bitwise or (|) operator, the result
-    # being in $spaces.  A character in $spaces is a space only if
-    # there was a space at that position in every line of the
-    # paragraph.  $space can be used to search for contiguous spaces
-    # that occur on all lines of the paragraph.  If this results in at
-    # least two columns, the paragraph is identified as a table.
-
-    # Note that this sub must be called before checking for preformatted
-    # lines because a table may well have whitespace to the left, in
-    # which case it must not be incorrectly recognised as a preformat.
-    my @rows = @{$rows_ref};
-    my @starts;
-    my @ends;
-    my $spaces;
-    my $max = 0;
-    my $min = $para_len;
-    foreach my $row (@rows)
-    {
-        ($spaces |= $row) =~ tr/ /\xff/c;
-        $min = length $row if length $row < $min;
-        $max = length $row if $max < length $row;
-    }
-    $spaces = substr $spaces, 0, $min;
-    push(@starts, 0) unless $spaces =~ /^ /;
-    while ($spaces =~ /((?:^| ) +)(?=[^ ])/g)
-    {
-        push @ends,   pos($spaces) - length $1;
-        push @starts, pos($spaces);
-    }
-    shift(@ends) if $spaces =~ /^ /;
-    push(@ends, $max);
-
-    # Two or more rows and two or more columns indicate a table.
-    if (2 <= @rows and 2 <= @starts)
-    {
-        $self->{__mode} |= $TABLE;
-
-        # For each column, guess whether it should be left, centre or
-        # right aligned by examining all cells in that column for space
-        # to the left or the right.  A simple majority among those cells
-        # that actually have space to one side or another decides (if no
-        # alignment gets a majority, left alignment wins by default).
-        my @align;
-        my $cell = '';
-        foreach my $col (0 .. $#starts)
-        {
-            my @count = (0, 0, 0, 0);
-            foreach my $row (@rows)
-            {
-                my $width = $ends[$col] - $starts[$col];
-                $cell = substr $row, $starts[$col], $width;
-                ++$count[($cell =~ /^ / ? 2 : 0) +
-                  ($cell =~ / $/ || length($cell) < $width ? 1 : 0)];
-            }
-            $align[$col] = 0;
-            my $population = $count[1] + $count[2] + $count[3];
-            foreach (1 .. 3)
-            {
-                if ($count[$_] * 2 > $population)
-                {
-                    $align[$col] = $_;
-                    last;
-                }
-            }
-        }
-
-        foreach my $row (@rows)
-        {
-            $row = join '', $self->get_tag('TR'), (
-                map {
-                    $cell = substr $row, $starts[$_], $ends[$_] - $starts[$_];
-                    $cell =~ s/^ +//;
-                    $cell =~ s/ +$//;
-
-                    if ($self->{escape_HTML_chars})
-                    {
-                        $cell = escape($cell);
-                    }
-
-                    (
-                        $self->get_tag(
-                            'TD',
-                            inside_tag => (
-                                $self->{xhtml} ? $xhtml_alignments[$align[$_]]
-                                : (
-                                      $self->{lower_case_tags}
-                                    ? $lc_alignments[$align[$_]]
-                                    : $alignments[$align[$_]]
-                                )
-                            )
-                        ),
-                        $cell,
-                        $self->close_tag('TD')
-                    );
-                  } 0 .. $#starts
-              ),
-              $self->close_tag('TR');
-        }
-
-        # put the <TABLE> around the rows
-        my $tag;
-        if ($self->{xhtml})
-        {
-            $tag = $self->get_tag('TABLE', inside_tag => ' summary=""');
-        }
-        else
-        {
-            $tag = $self->get_tag('TABLE');
-        }
-        $rows[0] = join("\n", $tag, $rows[0]);
-        $tag = $self->close_tag('TABLE', tag_type => 'end');
-        $rows[$#rows] .= "\n${tag}";
-        @{$rows_ref} = @rows;
-        return 1;
-    }
-    else
-    {
-        return 0;
-    }
-}    # make_aligned_table
-
-sub make_pgsql_table ($%)
-{
-    my $self = shift;
-    my %args = (
-        rows_ref => undef,
-        para_len => 0,
-        @_
-    );
-    my $rows_ref = $args{rows_ref};
-    my $para_len = $args{para_len};
-
-    # a PGSQL table can start with an optional table-caption,
-    # then it has a row of column headings separated by |
-    # then it has a row of ------+-----
-    # then it has one or more rows of column values separated by |
-    # then it has a row-count (N rows)
-    # Thus it must have at least 4 rows.
-    my @rows    = @{$rows_ref};
-    my $caption = '';
-    if ($rows[0] !~ /\|/ && $rows[0] =~ /^\s*\w+/)    # possible caption
-    {
-        $caption = shift @rows;
-    }
-    my @headings = split(/\s+\|\s+/, shift @rows);
-    # skip the ----+--- line
-    shift @rows;
-    # grab the N rows line
-    my $n_rows = pop @rows;
-
-    # now start making the table
-    my @tab_lines = ();
-    my $tag;
-    my $tag2;
-    if ($self->{xhtml})
-    {
-        $tag = $self->get_tag('TABLE', inside_tag => ' border="1" summary=""');
-    }
-    else
-    {
-        $tag = $self->get_tag('TABLE', inside_tag => ' border="1"');
-    }
-    push @tab_lines, "$tag\n";
-    if ($caption)
-    {
-        $caption =~ s/^\s+//;
-        $caption =~ s/\s+$//;
-        $tag     = $self->get_tag('CAPTION');
-        $tag2    = $self->close_tag('CAPTION');
-        $caption = join('', $tag, $caption, $tag2, "\n");
-        push @tab_lines, $caption;
-    }
-    # table header
-    my $thead = '';
-    $tag = $self->get_tag('THEAD');
-    $thead .= $tag;
-    $tag = $self->get_tag('TR');
-    $thead .= $tag;
-    foreach my $col (@headings)
-    {
-        $col =~ s/^\s+//;
-        $col =~ s/\s+$//;
-        $tag  = $self->get_tag('TH');
-        $tag2 = $self->close_tag('TH');
-        $thead .= join('', $tag, $col, $tag2);
-    }
-    $tag = $self->close_tag('TR');
-    $thead .= $tag;
-    $tag = $self->close_tag('THEAD');
-    $thead .= $tag;
-    push @tab_lines, "${thead}\n";
-    $tag = $self->get_tag('TBODY');
-    push @tab_lines, "$tag\n";
-
-    # each row
-    foreach my $row (@rows)
-    {
-        my $this_row = '';
-        $tag = $self->get_tag('TR');
-        $this_row .= $tag;
-        my @cols = split(/\|/, $row);
-        foreach my $cell (@cols)
-        {
-            $cell =~ s/^\s+//;
-            $cell =~ s/\s+$//;
-            if ($self->{escape_HTML_chars})
-            {
-                $cell = escape($cell);
-            }
-            if (!$cell)
-            {
-                $cell = ' ';
-            }
-            $tag  = $self->get_tag('TD');
-            $tag2 = $self->close_tag('TD');
-            $this_row .= join('', $tag, $cell, $tag2);
-        }
-        $tag = $self->close_tag('TR');
-        $this_row .= $tag;
-        push @tab_lines, "${this_row}\n";
-    }
-
-    # end the table
-    $tag = $self->close_tag('TBODY');
-    push @tab_lines, "$tag\n";
-    $tag = $self->get_tag('TABLE', tag_type => 'end');
-    push @tab_lines, "$tag\n";
-
-    # and add the N rows line
-    $tag = $self->get_tag('P');
-    push @tab_lines, "${tag}${n_rows}\n";
-    if ($self->{xhtml})
-    {
-        $tag = $self->get_tag('P', tag_type => 'end');
-        $tab_lines[$#tab_lines] =~ s/\n/${tag}\n/;
-    }
-
-    # replace the rows
-    @{$rows_ref} = @tab_lines;
-}    # make_pgsql_table
-
-sub make_border_table ($%)
-{
-    my $self = shift;
-    my %args = (
-        rows_ref => undef,
-        para_len => 0,
-        @_
-    );
-    my $rows_ref = $args{rows_ref};
-    my $para_len = $args{para_len};
-
-    # a BORDER table can start with an optional table-caption,
-    # then it has a row of +------+-----+
-    # then it has a row of column headings separated by |
-    # then it has a row of +------+-----+
-    # then it has one or more rows of column values separated by |
-    # then it has a row of +------+-----+
-    my @rows    = @{$rows_ref};
-    my $caption = '';
-    if ($rows[0] !~ /\|/ && $rows[0] =~ /^\s*\w+/)    # possible caption
-    {
-        $caption = shift @rows;
-    }
-    # skip the +----+---+ line
-    shift @rows;
-    # get the head row and cut off the start and end |
-    my $head_row = shift @rows;
-    $head_row =~ s/^\s*\|//;
-    $head_row =~ s/\|$//;
-    my @headings = split(/\s+\|\s+/, $head_row);
-    # skip the +----+---+ line
-    shift @rows;
-    # skip the last +----+---+ line
-    pop @rows;
-
-    # now start making the table
-    my @tab_lines = ();
-    my $tag;
-    if ($self->{xhtml})
-    {
-        $tag = $self->get_tag('TABLE', inside_tag => ' border="1" summary=""');
-    }
-    else
-    {
-        $tag = $self->get_tag('TABLE', inside_tag => ' border="1"');
-    }
-    push @tab_lines, "$tag\n";
-    if ($caption)
-    {
-        $caption =~ s/^\s+//;
-        $caption =~ s/\s+$//;
-        $tag     = $self->get_tag('CAPTION');
-        $caption = $tag . $caption;
-        $tag     = $self->close_tag('CAPTION');
-        $caption .= $tag;
-        push @tab_lines, "$caption\n";
-    }
-    # table header
-    my $thead = '';
-    $tag = $self->get_tag('THEAD');
-    $thead .= $tag;
-    $tag = $self->get_tag('TR');
-    $thead .= $tag;
-    foreach my $col (@headings)
-    {
-        $col =~ s/^\s+//;
-        $col =~ s/\s+$//;
-        $tag = $self->get_tag('TH');
-        $thead .= $tag;
-        $thead .= $col;
-        $tag = $self->close_tag('TH');
-        $thead .= $tag;
-    }
-    $tag = $self->close_tag('TR');
-    $thead .= $tag;
-    $tag = $self->close_tag('THEAD');
-    $thead .= $tag;
-    push @tab_lines, "${thead}\n";
-    $tag = $self->get_tag('TBODY');
-    push @tab_lines, "$tag\n";
-
-    # each row
-    foreach my $row (@rows)
-    {
-        # cut off the start and end |
-        $row =~ s/^\s*\|//;
-        $row =~ s/\|$//;
-        my $this_row = '';
-        $tag = $self->get_tag('TR');
-        $this_row .= $tag;
-        my @cols = split(/\|/, $row);
-        foreach my $cell (@cols)
-        {
-            $cell =~ s/^\s+//;
-            $cell =~ s/\s+$//;
-            if ($self->{escape_HTML_chars})
-            {
-                $cell = escape($cell);
-            }
-            if (!$cell)
-            {
-                $cell = ' ';
-            }
-            $tag = $self->get_tag('TD');
-            $this_row .= $tag;
-            $this_row .= $cell;
-            $tag = $self->close_tag('TD');
-            $this_row .= $tag;
-        }
-        $tag = $self->close_tag('TR');
-        $this_row .= $tag;
-        push @tab_lines, "${this_row}\n";
-    }
-
-    # end the table
-    $tag = $self->close_tag('TBODY');
-    push @tab_lines, "$tag\n";
-    $tag = $self->get_tag('TABLE', tag_type => 'end');
-    push @tab_lines, "$tag\n";
-
-    # replace the rows
-    @{$rows_ref} = @tab_lines;
-}    # make_border_table
-
-sub make_delim_table ($%)
-{
-    my $self = shift;
-    my %args = (
-        rows_ref => undef,
-        para_len => 0,
-        @_
-    );
-    my $rows_ref = $args{rows_ref};
-    my $para_len = $args{para_len};
-
-    # a DELIM table can start with an optional table-caption,
-    # then it has at least two rows which start and end and are
-    # punctuated by a non-alphanumeric delimiter.
-    # A DELIM table has no table-header.
-    my @rows    = @{$rows_ref};
-    my $caption = '';
-    if ($rows[0] !~ /\|/ && $rows[0] =~ /^\s*\w+/)    # possible caption
-    {
-        $caption = shift @rows;
-    }
-    # figure out the delimiter
-    my $delim = '';
-    if ($rows[0] =~ /^\s*([^a-zA-Z0-9])/)
-    {
-        $delim = $1;
-    }
-    else
-    {
-        return 0;
-    }
-
-    # now start making the table
-    my @tab_lines = ();
-    my $tag;
-    if ($self->{xhtml})
-    {
-        $tag = $self->get_tag('TABLE', inside_tag => ' border="1" summary=""');
-    }
-    else
-    {
-        $tag = $self->get_tag('TABLE', inside_tag => ' border="1"');
-    }
-    push @tab_lines, "$tag\n";
-    if ($caption)
-    {
-        $caption =~ s/^\s+//;
-        $caption =~ s/\s+$//;
-        $tag     = $self->get_tag('CAPTION');
-        $caption = $tag . $caption;
-        $tag     = $self->close_tag('CAPTION');
-        $caption .= $tag;
-        push @tab_lines, "$caption\n";
-    }
-
-    # each row
-    foreach my $row (@rows)
-    {
-        # cut off the start and end delimiter
-        $row =~ s/^\s*[${delim}]//;
-        $row =~ s/[${delim}]$//;
-        my $this_row = '';
-        $tag = $self->get_tag('TR');
-        $this_row .= $tag;
-        my @cols = split(/[${delim}]/, $row);
-        foreach my $cell (@cols)
-        {
-            $cell =~ s/^\s+//;
-            $cell =~ s/\s+$//;
-            if ($self->{escape_HTML_chars})
-            {
-                $cell = escape($cell);
-            }
-            if (!$cell)
-            {
-                $cell = ' ';
-            }
-            $tag = $self->get_tag('TD');
-            $this_row .= $tag;
-            $this_row .= $cell;
-            $tag = $self->close_tag('TD');
-            $this_row .= $tag;
-        }
-        $tag = $self->close_tag('TR');
-        $this_row .= $tag;
-        push @tab_lines, "${this_row}\n";
-    }
-
-    # end the table
-    $tag = $self->get_tag('TABLE', tag_type => 'end');
-    push @tab_lines, "$tag\n";
-
-    # replace the rows
-    @{$rows_ref} = @tab_lines;
-}    # make_delim_table
-
-# Returns true if the passed string is considered to be preformatted
-sub is_preformatted ($$)
-{
-    my $self = shift;
-    my $line = shift;
-
-    my $pre_white_min = $self->{preformat_whitespace_min};
-    my $result        = (
-        ($line =~ /\s{$pre_white_min,}\S+/o)    # whitespaces
-          || ($line =~ /\.{$pre_white_min,}\S+/o)
-    );                                          # dots
-    return $result;
-}
-
-# modifies the given string,
-# and returns the front preformatted part
-sub split_end_explicit_preformat ($%)
-{
-    my $self = shift;
-    my %args = (
-        para_ref => undef,
-        @_
-    );
-    my $para_ref = $args{para_ref};
-
-    my $tag      = '';
-    my $pre_str  = '';
-    my $post_str = '';
-    if ($self->{__mode} & $PRE_EXPLICIT)
-    {
-        my $pe_mark = $self->{preformat_end_marker};
-        if (${para_ref} =~ /$pe_mark/io)
-        {
-            ($pre_str, $post_str) = split(/$pe_mark/, ${$para_ref}, 2);
-            if ($self->{escape_HTML_chars})
-            {
-                $pre_str = escape($pre_str);
-            }
-            $tag = $self->close_tag('PRE');
-            $pre_str .= "${tag}\n";
-            $self->{__mode} ^= (($PRE | $PRE_EXPLICIT) & $self->{__mode});
-        }
-        else    # no end -- the whole thing is preformatted
-        {
-            $pre_str = ${$para_ref};
-            if ($self->{escape_HTML_chars})
-            {
-                $pre_str = escape($pre_str);
-            }
-            ${$para_ref} = '';
-        }
-    }
-    return $pre_str;
-}    # split_end_explicit_preformat
-
-sub endpreformat ($%)
-{
-    my $self = shift;
-    my %args = (
-        para_lines_ref  => undef,
-        para_action_ref => undef,
-        ind             => 0,
-        prev_ref        => undef,
-        @_
-    );
-    my $para_lines_ref  = $args{para_lines_ref};
-    my $para_action_ref = $args{para_action_ref};
-    my $ind             = $args{ind};
-    my $prev_ref        = $args{prev_ref};
-
-    my $tag = '';
-    if ($self->{__mode} & $PRE_EXPLICIT)
-    {
-        my $pe_mark = $self->{preformat_end_marker};
-        if ($para_lines_ref->[$ind] =~ /$pe_mark/io)
-        {
-            if ($ind == 0)
-            {
-                $tag = $self->close_tag('PRE');
-                $para_lines_ref->[$ind] = "${tag}\n";
-            }
-            else
-            {
-                $tag = $self->close_tag('PRE');
-                $para_lines_ref->[$ind - 1] .= "${tag}\n";
-                $para_lines_ref->[$ind] = "";
-            }
-            $self->{__mode} ^= (($PRE | $PRE_EXPLICIT) & $self->{__mode});
-            $para_action_ref->[$ind] |= $END;
-        }
-        return;
-    }
-
-    if (
-        !$self->is_preformatted($para_lines_ref->[$ind])
-        && (
-            $self->{endpreformat_trigger_lines} == 1
-            || ($ind + 1 < @{$para_lines_ref}
-                && !$self->is_preformatted($para_lines_ref->[$ind + 1]))
-            || $ind + 1 >= @{$para_lines_ref}    # last line of para
-        )
-      )
-    {
-        if ($ind == 0)
-        {
-            $tag = $self->close_tag('PRE');
-            ${$prev_ref} = "${tag}\n";
-        }
-        else
-        {
-            $tag = $self->close_tag('PRE');
-            $para_lines_ref->[$ind - 1] .= "${tag}\n";
-        }
-        $self->{__mode} ^= ($PRE & $self->{__mode});
-        $para_action_ref->[$ind] |= $END;
-    }
-}    # endpreformat
-
-sub preformat ($%)
-{
-    my $self = shift;
-    my %args = (
-        mode_ref        => undef,
-        line_ref        => undef,
-        line_action_ref => undef,
-        prev_ref        => undef,
-        next_ref        => undef,
-        prev_action_ref => undef,
-        @_
-    );
-    my $mode_ref        = $args{mode_ref};
-    my $line_ref        = $args{line_ref};
-    my $line_action_ref = $args{line_action_ref};
-    my $prev_ref        = $args{prev_ref};
-    my $next_ref        = $args{next_ref};
-    my $prev_action_ref = $args{prev_action_ref};
-
-    my $tag = '';
-    if ($self->{use_preformat_marker})
-    {
-        my $pstart = $self->{preformat_start_marker};
-        if (${$line_ref} =~ /$pstart/io)
-        {
-            if (${$prev_ref} =~ s/<P>$//)
-            {
-                pop @{$self->{__tags}};
-            }
-            $tag =
-              $self->get_tag('PRE', inside_tag => " class='quote_explicit'");
-            ${$line_ref} = "${tag}\n";
-            ${$mode_ref}        |= $PRE | $PRE_EXPLICIT;
-            ${$line_action_ref} |= $PRE;
-            return;
-        }
-    }
-
-    if (
-           !(${$line_action_ref} & $MAILQUOTE)
-        && !(${$prev_action_ref} & $MAILQUOTE)
-        && (
-            $self->{preformat_trigger_lines} == 0
-            || (
-                $self->is_preformatted(${$line_ref})
-                && (
-                    $self->{preformat_trigger_lines} == 1
-                    || (defined $next_ref
-                        && $self->is_preformatted(${$next_ref}))
-                )
-            )
-        )
-      )
-    {
-        if (${$prev_ref} =~ s/<P>$//)
-        {
-            pop @{$self->{__tags}};
-        }
-        $tag = $self->get_tag('PRE');
-        ${$line_ref} =~ s/^/${tag}\n/;
-        ${$mode_ref}        |= $PRE;
-        ${$line_action_ref} |= $PRE;
-    }
-}    # preformat
-
-sub make_new_anchor ($$)
-{
-    my $self          = shift;
-    my $heading_level = shift;
-
-    my ($anchor, $i);
-
-    return sprintf("%d", $self->{__non_header_anchor}++) if (!$heading_level);
-
-    $anchor = "section";
-    $self->{__heading_count}->[$heading_level - 1]++;
-
-    # Reset lower order counters
-    for ($i = @{$self->{__heading_count}}; $i > $heading_level; $i--)
-    {
-        $self->{__heading_count}->[$i - 1] = 0;
-    }
-
-    for ($i = 0; $i < $heading_level; $i++)
-    {
-        $self->{__heading_count}->[$i] = 1
-          if !$self->{__heading_count}->[$i];    # In case they skip any
-        $anchor .= sprintf("_%d", $self->{__heading_count}->[$i]);
-    }
-    chomp($anchor);
-    $anchor;
-}    # make_new_anchor
-
-sub anchor_mail ($$)
-{
-    my $self     = shift;
-    my $line_ref = shift;
-
-    if ($self->{make_anchors})
-    {
-        my ($anchor) = $self->make_new_anchor(0);
-        if ($self->{lower_case_tags})
-        {
-            ${$line_ref} =~ s/([^ ]*)/<a name="$anchor">$1<\/a>/;
-        }
-        else
-        {
-            ${$line_ref} =~ s/([^ ]*)/<A NAME="$anchor">$1<\/A>/;
-        }
-    }
-}    # anchor_mail
-
-sub anchor_heading ($$$)
-{
-    my $self     = shift;
-    my $level    = shift;
-    my $line_ref = shift;
-
-    if ($self->{dict_debug} & 8)
-    {
-        print STDERR "anchor_heading: ", ${$line_ref}, "\n";
-    }
-    if ($self->{make_anchors})
-    {
-        my ($anchor) = $self->make_new_anchor($level);
-        if ($self->{lower_case_tags})
-        {
-            ${$line_ref} =~ s/(<h.>)(.*)(<\/h.>)/$1<a name="$anchor">$2<\/a>$3/;
-        }
-        else
-        {
-            ${$line_ref} =~ s/(<H.>)(.*)(<\/H.>)/$1<A NAME="$anchor">$2<\/A>$3/;
-        }
-    }
-    if ($self->{dict_debug} & 8)
-    {
-        print STDERR "anchor_heading(after): ", ${$line_ref}, "\n";
-    }
-}    # anchor_heading
-
-sub heading_level ($$)
-{
-    my $self = shift;
-
-    my ($style) = @_;
-    $self->{__heading_styles}->{$style} = ++$self->{__num_heading_styles}
-      if !$self->{__heading_styles}->{$style};
-    $self->{__heading_styles}->{$style};
-}    # heading_level
-
-sub is_ul_list_line ($%)
-{
-    my $self = shift;
-    my %args = (
-        line => undef,
-        @_
-    );
-    my $line = $args{line};
-
-    my ($prefix, $number, $rawprefix, $term) = $self->listprefix($line);
-    if ($prefix && !$number)
-    {
-        return 1;
-    }
-    return 0;
-}
-
-sub is_heading ($%)
-{
-    my $self = shift;
-    my %args = (
-        line_ref => undef,
-        next_ref => undef,
-        @_
-    );
-    my $line_ref = $args{line_ref};
-    my $next_ref = $args{next_ref};
-
-    if (   ${$line_ref} !~ /^\s*$/
-        && !$self->is_ul_list_line(line => ${$line_ref})
-        && defined $next_ref
-        && ${$next_ref} =~ /^\s*[-=*.~+]+\s*$/)
-    {
-        my ($hoffset, $heading) = ${$line_ref} =~ /^(\s*)(.+)$/;
-        $hoffset = "" unless defined($hoffset);
-        $heading = "" unless defined($heading);
-        # Unescape chars so we get an accurate length
-        $heading =~ s/&[^;]+;/X/g;
-        my ($uoffset, $underline) = ${$next_ref} =~ /^(\s*)(\S+)\s*$/;
-        $uoffset   = "" unless defined($uoffset);
-        $underline = "" unless defined($underline);
-        my ($lendiff, $offsetdiff);
-        $lendiff = length($heading) - length($underline);
-        $lendiff *= -1 if $lendiff < 0;
-
-        $offsetdiff = length($hoffset) - length($uoffset);
-        $offsetdiff *= -1 if $offsetdiff < 0;
-        if (   ($lendiff <= $self->{underline_length_tolerance})
-            || ($offsetdiff <= $self->{underline_offset_tolerance}))
-        {
-            return 1;
-        }
-    }
-
-    return 0;
-
-}    # is_heading
-
-# make a heading
-# assumes is_heading is true
-sub heading ($%)
-{
-    my $self = shift;
-    my %args = (
-        line_ref => undef,
-        next_ref => undef,
-        @_
-    );
-    my $line_ref = $args{line_ref};
-    my $next_ref = $args{next_ref};
-
-    my ($hoffset, $heading) = ${$line_ref} =~ /^(\s*)(.+)$/;
-    $hoffset = "" unless defined($hoffset);
-    $heading = "" unless defined($heading);
-    $heading =~ s/&[^;]+;/X/g;    # Unescape chars so we get an accurate length
-    my ($uoffset, $underline) = ${$next_ref} =~ /^(\s*)(\S+)\s*$/;
-    $uoffset   = "" unless defined($uoffset);
-    $underline = "" unless defined($underline);
-
-    $underline = substr($underline, 0, 1);
-
-    # Call it a different style if the heading is in all caps.
-    $underline .= "C" if $self->iscaps(${$line_ref});
-    ${$next_ref} = " ";           # Eat the underline
-    $self->{__heading_level} = $self->heading_level($underline);
-    if ($self->{escape_HTML_chars})
-    {
-        ${$line_ref} = escape(${$line_ref});
-    }
-    $self->tagline("H" . $self->{__heading_level}, $line_ref);
-    $self->anchor_heading($self->{__heading_level}, $line_ref);
-}    # heading
-
-# check if the given line matches a custom heading
-sub is_custom_heading ($%)
-{
-    my $self = shift;
-    my %args = (
-        line => undef,
-        @_
-    );
-    my $line = $args{line};
-
-    foreach my $reg (@{$self->{custom_heading_regexp}})
-    {
-        return 1 if ($line =~ /$reg/);
-    }
-    return 0;
-}    # is_custom_heading
-
-sub custom_heading ($%)
-{
-    my $self = shift;
-    my %args = (
-        line_ref => undef,
-        @_
-    );
-    my $line_ref = $args{line_ref};
-
-    my $level;
-    my $i = 0;
-    foreach my $reg (@{$self->{custom_heading_regexp}})
-    {
-        if (${$line_ref} =~ /$reg/)
-        {
-            if ($self->{explicit_headings})
-            {
-                $level = $i + 1;
-            }
-            else
-            {
-                $level = $self->heading_level("Cust" . $i);
-            }
-            if ($self->{escape_HTML_chars})
-            {
-                ${$line_ref} = escape(${$line_ref});
-            }
-            $self->tagline("H" . $level, $line_ref);
-            $self->anchor_heading($level, $line_ref);
-            last;
-        }
-        $i++;
-    }
-}    # custom_heading
-
-sub unhyphenate_para ($$)
-{
-    my $self     = shift;
-    my $para_ref = shift;
-
-    # Treating this whole paragraph as one string, look for
-    # 1 - whitespace
-    # 2 - a word (ending in a hyphen, followed by a newline)
-    # 3 - whitespace (starting on the next line)
-    # 4 - a word with its punctuation
-    # Substitute this with
-    # 1-whitespace 2-word 4-word newline 3-whitespace
-    # We preserve the 3-whitespace because we don't want to mess up
-    # our existing indentation.
-    ${$para_ref} =~
-      /(\s*)([^\W\d_]*)\-\n(\s*)([^\W\d_]+[\)\}\]\.,:;\'\"\>]*\s*)/s;
-    ${$para_ref} =~
-s/(\s*)([^\W\d_]*)\-\n(\s*)([^\W\d_]+[\)\}\]\.,:;\'\"\>]*\s*)/$1$2$4\n$3/gs;
-}    # unhyphenate_para
-
-sub tagline ($$$)
-{
-    my $self     = shift;
-    my $tag      = shift;
-    my $line_ref = shift;
-
-    chomp ${$line_ref};    # Drop newline
-    my $tag1 = $self->get_tag($tag);
-    my $tag2 = $self->close_tag($tag);
-    ${$line_ref} =~ s/^\s*(.*)$/${tag1}$1${tag2}\n/;
-}    # tagline
-
-sub iscaps
-{
-    my $self = shift;
-    local ($_) = @_;
-
-    my $min_caps_len = $self->{min_caps_length};
-
-    # This is ugly, but I don't know a better way to do it.
-    # (And, yes, I could use the literal characters instead of the
-    # numeric codes, but this keeps the script 8-bit clean, which will
-    # save someone a big headache when they transfer via ASCII ftp.
-/^[^a-z\341\343\344\352\353\354\363\370\337\373\375\342\345\347\350\355\357\364\365\376\371\377\340\346\351\360\356\361\362\366\372\374<]*[A-Z\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\330\331\332\333\334\335\336]{$min_caps_len,}[^a-z\341\343\344\352\353\354\363\370\337\373\375\342\345\347\350\355\357\364\365\376\371\377\340\346\351\360\356\361\362\366\372\374<]*$/;
-}    # iscaps
-
-sub caps
-{
-    my $self = shift;
-    my %args = (
-        line_ref        => undef,
-        line_action_ref => undef,
-        @_
-    );
-    my $line_ref        = $args{line_ref};
-    my $line_action_ref = $args{line_action_ref};
-
-    if (   $self->{caps_tag}
-        && $self->iscaps(${$line_ref}))
-    {
-        $self->tagline($self->{caps_tag}, $line_ref);
-        ${$line_action_ref} |= $CAPS;
-    }
-}    # caps
-
-sub do_delim
-{
-    my $self = shift;
-    my %args = (
-        line_ref        => undef,
-        line_action_ref => undef,
-        delim           => '*',
-        tag             => 'STRONG',
-        @_
-    );
-    my $line_ref        = $args{line_ref};
-    my $line_action_ref = $args{line_action_ref};
-    my $delim           = $args{delim};
-    my $tag             = $args{tag};
-
-    if ($delim eq '#')    # special treatment of # for the #num case
-    {
-        ${$line_ref} =~
-s/#([^0-9#](?![^#]*(?:<li>|<LI>|<P>|<p>))[^#]*[^# \t\n])#/<${tag}>$1<\/${tag}>/gs;
-        ${$line_ref} =~ s/\B#([a-zA-Z])#\B/<${tag}>$1<\/${tag}>/gs;
-    }
-    elsif ($delim eq '^')
-    {
-        ${$line_ref} =~
-s/\^((?![^^]*(?:<li>|<LI>|<p>|<P>))(\w|["'<>])[^^]*)\^/<${tag}>$1<\/${tag}>/gs;
-        ${$line_ref} =~ s/\B\^([a-zA-Z])\^\B/<${tag}>$1<\/${tag}>/gs;
-    }
-    elsif (length($delim) eq 1)    # one-character, general
-    {
-        ${$line_ref} =~
-s/(?<![${delim}])[${delim}](?![^${delim}]*(?:<li>|<LI>|<p>|<P>))((\w|["'<>])[^${delim}]*)[${delim}]/<${tag}>$1<\/${tag}>/gs;
-        ${$line_ref} =~
-          s/\B[${delim}]([a-zA-Z])[${delim}]\B/<${tag}>$1<\/${tag}>/gs;
-    }
-    else
-    {
-        ${$line_ref} =~
-s/(?<!${delim})${delim}((\w|["'])(\w|[-\s\.;:,!?"'])*[^\s])${delim}/<${tag}>$1<\/${tag}>/gs;
-        ${$line_ref} =~ s/${delim}]([a-zA-Z])${delim}/<${tag}>$1<\/${tag}>/gs;
-    }
-}    # do_delim
-
-# Convert very simple globs to regexps
-sub glob2regexp
-{
-    my ($glob) = @_;
-
-    # Escape funky chars
-    $glob =~ s/[^\w\[\]\*\?\|\\]/\\$&/g;
-    my ($regexp, $i, $len, $escaped) = ("", 0, length($glob), 0);
-
-    for (; $i < $len; $i++)
-    {
-        my $char = substr($glob, $i, 1);
-        if ($escaped)
-        {
-            $escaped = 0;
-            $regexp .= $char;
-            next;
-        }
-        if ($char eq "\\")
-        {
-            $escaped = 1;
-            next;
-            $regexp .= $char;
-        }
-        if ($char eq "?")
-        {
-            $regexp .= ".";
-            next;
-        }
-        if ($char eq "*")
-        {
-            $regexp .= ".*";
-            next;
-        }
-        $regexp .= $char;    # Normal character
-    }
-    join('', "\\b", $regexp, "\\b");
-}    # glob2regexp
-
-sub add_regexp_to_links_table ($$$$)
-{
-    my $self = shift;
-    my ($key, $URL, $switches) = @_;
-
-    # No sense adding a second one if it's already in there.
-    # It would never get used.
-    if (!$self->{__links_table}->{$key})
-    {
-
-        # Keep track of the order they were added so we can
-        # look for matches in the same order
-        push(@{$self->{__links_table_order}}, ($key));
-
-        $self->{__links_table}->{$key}        = $URL;      # Put it in The Table
-        $self->{__links_switch_table}->{$key} = $switches;
-        my $ind = @{$self->{__links_table_order}} - 1;
-        print STDERR " (", $ind,
-          ")\tKEY: $key\n\tVALUE: $URL\n\tSWITCHES: $switches\n\n"
-          if ($self->{dict_debug} & 1);
-    }
-    else
-    {
-        if ($self->{dict_debug} & 1)
-        {
-            print STDERR " Skipping entry.  Key already in table.\n";
-            print STDERR "\tKEY: $key\n\tVALUE: $URL\n\n";
-        }
-    }
-}    # add_regexp_to_links_table
-
-sub add_literal_to_links_table ($$$$)
-{
-    my $self = shift;
-    my ($key, $URL, $switches) = @_;
-
-    $key =~ s/(\W)/\\$1/g;    # Escape non-alphanumeric chars
-    $key = "\\b$key\\b";      # Make a regexp out of it
-    $self->add_regexp_to_links_table($key, $URL, $switches);
-}    # add_literal_to_links_table
-
-sub add_glob_to_links_table ($$$$)
-{
-    my $self = shift;
-    my ($key, $URL, $switches) = @_;
-
-    $self->add_regexp_to_links_table(glob2regexp($key), $URL, $switches);
-}    # add_glob_to_links_table
-
-# Parse the dictionary file.
-# (see also load_dictionary_links, for things that were stripped)
-sub parse_dict ($$$)
-{
-    my $self = shift;
-
-    my ($dictfile, $dict) = @_;
-
-    print STDERR "Parsing dictionary file $dictfile\n"
-      if ($self->{dict_debug} & 1);
-
-    if ($dict =~ /->\s*->/)
-    {
-        my $message = "Two consecutive '->'s found in $dictfile\n";
-        my $near;
-
-        # Print out any useful context so they can find it.
-        ($near) = $dict =~ /([\S ]*\s*->\s*->\s*\S*)/;
-        $message .= "\n$near\n" if $near =~ /\S/;
-        die $message;
-    }
-
-    my ($key, $URL, $switches, $options);
-    while ($dict =~ /\s*(.+)\s+\-+([iehos]+\-+)?\>\s*(.*\S+)\s*\n/ig)
-    {
-        $key      = $1;
-        $options  = $2;
-        $options  = "" unless defined($options);
-        $URL      = $3;
-        $switches = 0;
-        # Case insensitivity
-        $switches += $LINK_NOCASE if $options =~ /i/i;
-        # Evaluate as Perl code
-        $switches += $LINK_EVAL if $options =~ /e/i;
-        # provides HTML, not just URL
-        $switches += $LINK_HTML if $options =~ /h/i;
-        # Only do this link once
-        $switches += $LINK_ONCE if $options =~ /o/i;
-        # Only do this link once per section
-        $switches += $LINK_SECT_ONCE if $options =~ /s/i;
-
-        $key =~ s/\s*$//;    # Chop trailing whitespace
-
-        if ($key =~ m|^/|)   # Regexp
-        {
-            $key = substr($key, 1);
-            $key =~ s|/$||;    # Allow them to forget the closing /
-            $self->add_regexp_to_links_table($key, $URL, $switches);
-        }
-        elsif ($key =~ /^\|/)    # alternate regexp format
-        {
-            $key = substr($key, 1);
-            $key =~ s/\|$//;      # Allow them to forget the closing |
-            $key =~ s|/|\\/|g;    # Escape all slashes
-            $self->add_regexp_to_links_table($key, $URL, $switches);
-        }
-        elsif ($key =~ /\"/)
-        {
-            $key = substr($key, 1);
-            $key =~ s/\"$//;      # Allow them to forget the closing "
-            $self->add_literal_to_links_table($key, $URL, $switches);
-        }
-        else
-        {
-            $self->add_glob_to_links_table($key, $URL, $switches);
-        }
-    }
-
-}    # parse_dict
-
-sub setup_dict_checking ($)
-{
-    my $self = shift;
-
-    # now create the replace funcs and precomile the regexes
-    my ($URL, $switches, $options, $tag1, $tag2);
-    my ($href, $r_sw);
-    my @subs;
-    my $i = 0;
-    foreach my $pattern (@{$self->{__links_table_order}})
-    {
-        $switches = $self->{__links_switch_table}->{$pattern};
-
-        $href = $self->{__links_table}->{$pattern};
-
-        if (!($switches & $LINK_HTML))
-        {
-            $href =~ s#/#\\/#g;
-            $href = (
-                $self->{lower_case_tags}
-                ? join('', '<a href="', $href, '">$&<\\/a>')
-                : join('', '<A HREF="', $href, '">$&<\\/A>')
-            );
-        }
-        else
-        {
-            # change the uppercase tags to lower case
-            if ($self->{lower_case_tags})
-            {
-                $href =~ s#(</)([A-Z]*)(>)#${1}\L${2}${3}#g;
-                $href =~ s/(<)([A-Z]*)(>)/${1}\L${2}${3}/g;
-                # and the anchors
-                $href =~ s/(<)(A\s*HREF)([^>]*>)/$1\L$2$3/g;
-            }
-            $href =~ s#/#\\/#g;
-        }
-
-        $r_sw = "s";    # Options for replacing
-        $r_sw .= "i" if ($switches & $LINK_NOCASE);
-        $r_sw .= "e" if ($switches & $LINK_EVAL);
-
-        # Generate code for replacements.
-        # Create an anonymous subroutine for each replacement,
-        # and store its reference in an array.
-        # We need to do an "eval" to create these because we need to
-        # be able to treat the *contents* of the $href variable
-        # as if it were perl code, because sometimes the $href
-        # contains things which need to be evaluated, such as $& or $1,
-        # not just those cases where we have a "e" switch.
-        my $code = <<EOT;
-\$self->{__repl_code}->[$i] =
-sub {
-my \$al = shift;
-\$al =~ s/$pattern/$href/$r_sw;
-return \$al;
-};
-EOT
-        print STDERR $code if ($self->{dict_debug} & 2);
-        push @subs, $code;
-
-        # compile searching pattern
-        if ($switches & $LINK_NOCASE)    # i
-        {
-            $self->{__search_patterns}->[$i] = qr/$pattern/si;
-        }
-        else
-        {
-            $self->{__search_patterns}->[$i] = qr/$pattern/s;
-        }
-        $i++;
-    }
-    # now eval the replacements code string
-    my $codes = join('', @subs);
-    eval "$codes";
-}    # setup_dict_checking
-
-sub in_link_context ($$$)
-{
-    my $self = shift;
-    my ($match, $before) = @_;
-    return 1 if $match =~ m@</?A>@i;    # No links allowed inside match
-
-    my ($final_open, $final_close);
-    if ($self->{lower_case_tags})
-    {
-        $final_open  = rindex($before, "<a ") - $[;
-        $final_close = rindex($before, "</a>") - $[;
-    }
-    else
-    {
-        $final_open  = rindex($before, "<A ") - $[;
-        $final_close = rindex($before, "</A>") - $[;
-    }
-
-    return 1 if ($final_open >= 0)    # Link opened
-      && (
-        ($final_close < 0)            # and not closed    or
-        || ($final_open > $final_close)
-      );                              # one opened after last close
-
-    # Now check to see if we're inside a tag, matching a tag name,
-    # or attribute name or value
-    $final_open  = rindex($before, "<") - $[;
-    $final_close = rindex($before, ">") - $[;
-    ($final_open >= 0)                # Tag opened
-      && (
-        ($final_close < 0)            # and not closed    or
-        || ($final_open > $final_close)
-      );                              # one opened after last close
-}    # in_link_context
-
-# apply links and formatting to this paragraph
-sub apply_links ($%)
-{
-    my $self = shift;
-    my %args = (
-        para_ref        => undef,
-        para_action_ref => undef,
-        @_
-    );
-    my $para_ref        = $args{para_ref};
-    my $para_action_ref = $args{para_action_ref};
-
-    if ($self->{make_links}
-        && @{$self->{__links_table_order}})
-    {
-        $self->check_dictionary_links(
-            line_ref        => $para_ref,
-            line_action_ref => $para_action_ref
-        );
-    }
-    if ($self->{bold_delimiter})
-    {
-        my $tag = ($self->{lower_case_tags} ? 'strong' : 'STRONG');
-        $self->do_delim(
-            line_ref        => $para_ref,
-            line_action_ref => $para_action_ref,
-            delim           => $self->{bold_delimiter},
-            tag             => $tag
-        );
-    }
-    if ($self->{italic_delimiter})
-    {
-        my $tag = ($self->{lower_case_tags} ? 'em' : 'EM');
-        $self->do_delim(
-            line_ref        => $para_ref,
-            line_action_ref => $para_action_ref,
-            delim           => $self->{italic_delimiter},
-            tag             => $tag
-        );
-    }
-
-}    # apply_links
-
-# Check (and alter if need be) the bits in this line matching
-# the patterns in the link dictionary.
-sub check_dictionary_links ($%)
-{
-    my $self = shift;
-    my %args = (
-        line_ref        => undef,
-        line_action_ref => undef,
-        @_
-    );
-    my $line_ref        = $args{line_ref};
-    my $line_action_ref = $args{line_action_ref};
-
-    my ($switches, $options, $repl_func);
-    my ($linkme, $line_with_links);
-
-    # for each pattern, check and alter the line
-    my $i = 0;
-    foreach my $pattern (@{$self->{__links_table_order}})
-    {
-        $switches = $self->{__links_switch_table}->{$pattern};
-
-        # check the pattern
-        if ($switches & $LINK_ONCE)    # Do link only once
-        {
-            $line_with_links = '';
-            if (!$self->{__done_with_link}->[$i]
-                && ${$line_ref} =~ $self->{__search_patterns}->[$i])
-            {
-                $self->{__done_with_link}->[$i] = 1;
-                $line_with_links .= $`;
-                $linkme = $&;
-
-                ${$line_ref} = $';
-                if (!$self->in_link_context($linkme, $line_with_links))
-                {
-                    print STDERR "Link rule $i matches $linkme\n"
-                      if ($self->{dict_debug} & 4);
-
-                    # call the special subroutine already created to do
-                    # this replacement
-                    $repl_func = $self->{__repl_code}->[$i];
-                    $linkme    = &$repl_func($linkme);
-                }
-                $line_with_links .= $linkme;
-            }
-            ${$line_ref} = $line_with_links . ${$line_ref};
-        }
-        elsif ($switches & $LINK_SECT_ONCE)    # Do link only once per section
-        {
-            $line_with_links = '';
-            if (!$self->{__done_with_sect_link}->[$i]
-                && ${$line_ref} =~ $self->{__search_patterns}->[$i])
-            {
-                $self->{__done_with_sect_link}->[$i] = 1;
-                $line_with_links .= $`;
-                $linkme = $&;
-
-                ${$line_ref} = $';
-                if (!$self->in_link_context($linkme, $line_with_links))
-                {
-                    print STDERR "Link rule $i matches $linkme\n"
-                      if ($self->{dict_debug} & 4);
-
-                    # call the special subroutine already created to do
-                    # this replacement
-                    $repl_func = $self->{__repl_code}->[$i];
-                    $linkme    = &$repl_func($linkme);
-                }
-                $line_with_links .= $linkme;
-            }
-            ${$line_ref} = $line_with_links . ${$line_ref};
-        }
-        else
-        {
-            $line_with_links = '';
-            while (${$line_ref} =~ $self->{__search_patterns}->[$i])
-            {
-                $line_with_links .= $`;
-                $linkme = $&;
-
-                ${$line_ref} = $';
-                if (!$self->in_link_context($linkme, $line_with_links))
-                {
-                    print STDERR "Link rule $i matches $linkme\n"
-                      if ($self->{dict_debug} & 4);
-
-                    # call the special subroutine already created to do
-                    # this replacement
-                    $repl_func = $self->{__repl_code}->[$i];
-                    $linkme    = &$repl_func($linkme);
-                }
-                $line_with_links .= $linkme;
-            }
-            ${$line_ref} = $line_with_links . ${$line_ref};
-        }
-        $i++;
-    }
-    ${$line_action_ref} |= $LINK;
-}    # check_dictionary_links
-
-sub load_dictionary_links ($)
-{
-    my $self = shift;
-
-    @{$self->{__links_table_order}} = ();
-    %{$self->{__links_table}}       = ();
-
-    my $dict;
-    foreach $dict (@{$self->{links_dictionaries}})
-    {
-        next unless $dict;
-        open(DICT, "$dict") || die "Can't open Dictionary file $dict\n";
-
-        my @lines = ();
-        while (<DICT>)
-        {
-            # skip lines that start with '#'
-            next if /^\#/;
-            # skip lines that end with unescaped ':'
-            next if /^.*[^\\]:\s*$/;
-            push @lines, $_;
-        }
-        close(DICT);
-        my $contents = join('', @lines);
-        $self->parse_dict($dict, $contents);
-    }
-    # last of all, do the system dictionary, already read in from DATA
-    if ($self->{__global_links_data})
-    {
-        $self->parse_dict("DATA", $self->{__global_links_data});
-    }
-
-    $self->setup_dict_checking();
-}    # load_dictionary_links
-
-# do_file_start
-#    extra stuff needed for the beginning
-# Args:
-#   $self
-#   $para
-# Return:
-#   processed $para string
-sub do_file_start ($$$)
-{
-    my $self      = shift;
-    my $outhandle = shift;
-    my $para      = shift;
-
-    if (!$self->{extract})
-    {
-        my @para_lines = split(/\n/, $para);
-        my $first_line = $para_lines[0];
-
-        if ($self->{doctype})
-        {
-            if ($self->{xhtml})
-            {
-                print $outhandle
-'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"',
-                  "\n";
-                print $outhandle
-                  '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
-                  "\n";
-            }
-            else
-            {
-                print $outhandle '<!DOCTYPE HTML PUBLIC "', $self->{doctype},
-                  "\">\n";
-            }
-        }
-        print $outhandle $self->get_tag('HTML'), "\n";
-        print $outhandle $self->get_tag('HEAD'), "\n";
-
-        # if --titlefirst is set and --title isn't, use the first line
-        # as the title.
-        if ($self->{titlefirst} && !$self->{title})
-        {
-            my ($tit) = $first_line =~ /^ *(.*)/;    # grab first line
-            $tit =~ s/ *$//;                         # strip trailing whitespace
-            $tit = escape($tit) if $self->{escape_HTML_chars};
-            $self->{'title'} = $tit;
-        }
-        if (!$self->{title})
-        {
-            $self->{'title'} = "";
-        }
-        print $outhandle $self->get_tag('TITLE'), $self->{title},
-          $self->close_tag('TITLE'), "\n";
-
-        if ($self->{append_head})
-        {
-            open(APPEND, $self->{append_head})
-              || die "Failed to open ", $self->{append_head}, "\n";
-            while (<APPEND>)
-            {
-                print $outhandle $_;
-            }
-            close(APPEND);
-        }
-
-        if ($self->{lower_case_tags})
-        {
-            print $outhandle $self->get_tag(
-                'META',
-                tag_type   => 'empty',
-                inside_tag => " name=\"generator\" content=\"$PROG v$VERSION\""
-              ),
-              "\n";
-        }
-        else
-        {
-            print $outhandle $self->get_tag(
-                'META',
-                tag_type   => 'empty',
-                inside_tag => " NAME=\"generator\" CONTENT=\"$PROG v$VERSION\""
-              ),
-              "\n";
-        }
-        if ($self->{style_url})
-        {
-            my $style_url = $self->{style_url};
-            if ($self->{lower_case_tags})
-            {
-                print $outhandle $self->get_tag(
-                    'LINK',
-                    tag_type   => 'empty',
-                    inside_tag =>
-" rel=\"stylesheet\" type=\"text/css\" href=\"$style_url\""
-                  ),
-                  "\n";
-            }
-            else
-            {
-                print $outhandle $self->get_tag(
-                    'LINK',
-                    tag_type   => 'empty',
-                    inside_tag =>
-" REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"$style_url\""
-                  ),
-                  "\n";
-            }
-        }
-        print $outhandle $self->close_tag('HEAD'), "\n";
-        if ($self->{body_deco})
-        {
-            print $outhandle $self->get_tag('BODY',
-                inside_tag => $self->{body_deco}), "\n";
-        }
-        else
-        {
-            print $outhandle $self->get_tag('BODY'), "\n";
-        }
-    }
-
-    if ($self->{prepend_file})
-    {
-        if (-r $self->{prepend_file})
-        {
-            open(PREPEND, $self->{prepend_file});
-            while (<PREPEND>)
-            {
-                print $outhandle $_;
-            }
-            close(PREPEND);
-        }
-        else
-        {
-            print STDERR "Can't find or read file ", $self->{prepend_file},
-              " to prepend.\n";
-        }
-    }
-}    # do_file_start
-
-# do_init_call
-# certain things, like reading link dictionaries, need to be
-# done once
-sub do_init_call ($)
-{
-    my $self = shift;
-
-    if (!$self->{__call_init_done})
-    {
-        push(@{$self->{links_dictionaries}}, ($self->{default_link_dict}))
-          if ($self->{make_links} && (-f $self->{default_link_dict}));
-        $self->deal_with_options();
-        if ($self->{make_links})
-        {
-            $self->load_dictionary_links();
-        }
-
-        # various initializations
-        $self->{__non_header_anchor} = 0;
-        $self->{__mode}              = 0;
-        $self->{__listnum}           = 0;
-        $self->{__list_nice_indent}  = '';
-        $self->{__list_indent}       = [];
-        $self->{__tags}              = [];
-
-        $self->{__call_init_done} = 1;
-    }
-}    # do_init_call
-
-=head1 FILE FORMATS
-
-There are two files which are used which can affect the outcome of the
-conversion.  One is the link dictionary, which contains patterns (of how
-to recognise http links and other things) and how to convert them. The
-other is, naturally, the format of the input file itself.
-
-=head2 Link Dictionary
-
-A link dictionary file contains patterns to match, and what to convert
-them to.  It is called a "link" dictionary because it was intended to be
-something which defined what a href link was, but it can be used for
-more than that.  However, if you wish to define your own links, it is
-strongly advised to read up on regular expressions (regexes) because
-this relies heavily on them.
-
-The file consists of comments (which are lines starting with #)
-and blank lines, and link entries.
-Each entry consists of a regular expression, a -> separator (with
-optional flags), and a link "result".
-
-In the simplest case, with no flags, the regular expression
-defines the pattern to look for, and the result says what part
-of the regular expression is the actual link, and the link which
-is generated has the href as the link, and the whole matched pattern
-as the visible part of the link.  The first character of the regular
-expression is taken to be the separator for the regex, so one
-could either use the traditional / separator, or something else
-such as | (which can be helpful with URLs which are full of / characters).
-
-So, for example, an ftp URL might be defined as:
-
-    |ftp:[\w/\.:+\-]+|      -> $&
-
-This takes the whole pattern as the href, and the resultant link
-has the same thing in the href as in the contents of the anchor.
-
-But sometimes the href isn't the whole pattern.
-
-    /<URL:\s*(\S+?)\s*>/ --> $1
-
-With the above regex, a () grouping marks the first subexpression,
-which is represented as $1 (rather than $& the whole expression).
-This entry matches a URL which was marked explicity as a URL
-with the pattern <URL:foo>  (note the < is shown as the
-entity, not the actual character.  This is because by the
-time the links dictionary is checked, all such things have
-already been converted to their HTML entity forms, unless, of course,
-the escape_HTML_chars option was turned off)
-This would give us a link in the form
-<A HREF="foo"><URL:foo></A>
-
-B<The h flag>
-
-However, if we want more control over the way the link is constructed,
-we can construct it ourself.  If one gives the h flag, then the
-"result" part of the entry is taken not to contain the href part of
-the link, but the whole link.
-
-For example, the entry:
-
-    /<URL:\s*(\S+?)\s*>/ -h-> <A HREF="$1">$1</A>
-
-will take <URL:foo> and give us <A HREF="foo">foo</A>
-
-However, this is a very powerful mechanism, because it
-can be used to construct custom tags which aren't links at all.
-For example, to flag *italicised words* the following
-entry will surround the words with EM tags.
-
-    /\B\*([a-z][a-z -]*[a-z])\*\B/ -hi-> <EM>$1</EM>
-
-B<The i flag>
-
-This turns on ignore case in the pattern matching.
-
-B<The e flag>
-
-This turns on execute in the pattern substitution.  This really
-only makes sense if h is turned on too.  In that case, the "result"
-part of the entry is taken as perl code to be executed, and the
-result of that code is what replaces the pattern.
-
-B<The o flag>
-
-This marks the entry as a once-only link.  This will convert the
-first instance of a matching pattern, and ignore any others
-further on.
-
-For example, the following pattern will take the first mention
-of HTML::TextToHTML and convert it to a link to the module's home page.
-
-    "HTML::TextToHTML"  -io-> http://www.katspace.com/tools/text_to_html/
-
-=head2 Input File Format
-
-For the most part, this module tries to use intuitive conventions for
-determining the structure of the text input.  Unordered lists are
-marked by bullets; ordered lists are marked by numbers or letters;
-in either case, an increase in indentation marks a sub-list contained
-in the outer list.
-
-Headers (apart from custom headers) are distinguished by "underlines"
-underneath them; headers in all-capitals are distinguished from
-those in mixed case.  All headers, both normal and custom headers,
-are expected to start at the first line in a "paragraph".
-
-In other words, the following is a header:
-
-    I am Head Man
-    -------------
-
-But the following does not have a header:
-
-    I am not a head Man, man
-    I am Head Man
-    -------------
-
-Tables require a more rigid convention.  A table must be marked as a
-separate paragraph, that is, it must be surrounded by blank lines.
-Tables come in different types.  For a table to be parsed, its
---table_type option must be on, and the --make_tables option must be true.
-
-B<ALIGN Table Type>
-
-Columns must be separated by two or more spaces (this prevents
-accidental incorrect recognition of a paragraph where interword spaces
-happen to line up).  If there are two or more rows in a paragraph and
-all rows share the same set of (two or more) columns, the paragraph is
-assumed to be a table.  For example
-
-    -e  File exists.
-    -z  File has zero size.
-    -s  File has nonzero size (returns size).
-
-becomes
-
-    <TABLE>
-    <TR><TD>-e</TD><TD>File exists.</TD></TR>
-    <TR><TD>-z</TD><TD>File has zero size.</TD></TR>
-    <TR><TD>-s</TD><TD>File has nonzero size (returns size).</TD></TR>
-    </TABLE>
-
-This guesses for each column whether it is intended to be left,
-centre or right aligned.
-
-B<BORDER Table Type>
-
-This table type has nice borders around it, and will be rendered
-with a border, like so:
-
-    +---------+---------+
-    | Column1 | Column2 |
-    +---------+---------+
-    | val1    | val2    |
-    | val3    | val3    |
-    +---------+---------+
-
-The above becomes
-
-    <TABLE border="1">
-    <THEAD><TR><TH>Column1</TH><TH>Column2</TH></TR></THEAD>
-    <TBODY>
-    <TR><TD>val1</TD><TD>val2</TD></TR>
-    <TR><TD>val3</TD><TD>val3</TD></TR>
-    </TBODY>
-    </TABLE>
-
-It can also have an optional caption at the start.
-
-         My Caption
-    +---------+---------+
-    | Column1 | Column2 |
-    +---------+---------+
-    | val1    | val2    |
-    | val3    | val3    |
-    +---------+---------+
-
-B<PGSQL Table Type>
-
-This format of table is what one gets from the output of a Postgresql
-query.
-
-     Column1 | Column2
-    ---------+---------
-     val1    | val2
-     val3    | val3
-    (2 rows)
-
-This can also have an optional caption at the start.
-This table is also rendered with a border and table-headers like
-the BORDER type.
-
-B<DELIM Table Type>
-
-This table type is delimited by non-alphanumeric characters, and has to
-have at least two rows and two columns before it's recognised as a table.
-
-This one is delimited by the '| character:
-
-    | val1  | val2  |
-    | val3  | val3  |
-
-But one can use almost any suitable character such as : # $ % + and so on.
-This is clever enough to figure out what you are using as the delimiter
-if you have your data set up like a table.  Note that the line has to
-both begin and end with the delimiter, as well as using it to separate
-values.
-
-This can also have an optional caption at the start.
-
-=head1 EXAMPLES
-
-    use HTML::TextToHTML;
- 
-=head2 Create a new object
-
-    my $conv = new HTML::TextToHTML();
-
-    my $conv = new HTML::TextToHTML(title=>"Wonderful Things",
-			    default_link_dict=>$my_link_file,
-      );
-
-=head2 Add further arguments
-
-    $conv->args(short_line_length=>60,
-	       preformat_trigger_lines=>4,
-	       caps_tag=>"strong",
-      );
-
-=head2 Convert a file
-
-    $conv->txt2html(infile=>[$text_file],
-                     outfile=>$html_file,
-		     title=>"Wonderful Things",
-		     mail=>1
-      );
-
-=head2 Make a pipleline
-
-    open(IN, "ls |") or die "could not open!";
-    $conv->txt2html(inhandle=>[\*IN],
-                     outfile=>'-',
-      );
-
-=head1 NOTES
-
-=over
-
-=item *
-
-One cannot use "CLEAR" as a value for the cumulative arguments.
-
-=item *
-
-If the underline used to mark a header is off by more than 1, then 
-that part of the text will not be picked up as a header unless you
-change the value of --underline_length_tolerance and/or
---underline_offset_tolerance.  People tend to forget this.
-
-=back
-
-=head1 BUGS
-
-Tell me about them.
-
-=head1 SEE ALSO
-
-perl
-L<txt2html>.
-Data::Dumper
-
-=head1 AUTHOR
-
-    Kathryn Andersen (RUBYKAT)
-    perlkat AT katspace dot com
-    http//www.katspace.com/
-
-based on txt2html by Seth Golub
-
-=head1 COPYRIGHT AND LICENCE
-
-Original txt2html script copyright (c) 1994-2000 Seth Golub <seth AT aigeek.com>
-
-Copyright (c) 2002-2005 by Kathryn Andersen
-
-This program is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
-
-=cut
-
-#------------------------------------------------------------------------
-1;
-__DATA__
-#
-# Global links dictionary file for HTML::TextToHTML
-# http://www.katspace.com/tools/text_to_html
-# http://txt2html.sourceforge.net/
-# based on links dictionary for Seth Golub's txt2html
-# http://www.aigeek.com/txt2html/
-#
-# This dictionary contains some patterns for converting obvious URLs,
-# ftp sites, hostnames, email addresses and the like to hrefs.
-#
-# Original adapted from the html.pl package by Oscar Nierstrasz in
-# the Software Archive of the Software Composition Group
-# http://iamwww.unibe.ch/~scg/Src/
-#
-
-# Some people even like to mark the URL label explicitly <URL:foo:label>
-/<URL:([-\w\.\/:~_\@]+):([a-zA-Z0-9'() ]+)>/ -h-> <A HREF="$1">$2</A>
-
-# Some people like to mark URLs explicitly <URL:foo>
-/<URL:\s*(\S+?)\s*>/ -h-> <A HREF="$1">$1</A>
-
-#  <http://site>
-/<(http:\S+?)\s*>/ -h-> <<A HREF="$1">$1</A>>
-
-# Urls: <service>:<rest-of-url>
-
-|snews:[\w\.]+|        -> $&
-|news:[\w\.]+|         -> $&
-|nntp:[\w/\.:+\-]+|    -> $&
-|http:[\w/\.:\@+\-~\%#?=&;,]+[\w/]|  -> $&
-|shttp:[\w/\.:+\-~\%#?=&;,]+| -> $&
-|https:[\w/\.:+\-~\%#?=&;,]+| -> $&
-|file:[\w/\.:+\-]+|     -> $&
-|ftp:[\w/\.:+\-]+|      -> $&
-|wais:[\w/\.:+\-]+|     -> $&
-|gopher:[\w/\.:+\-]+|   -> $&
-|telnet:[\w/\@\.:+\-]+|   -> $&
-
-
-# catch some newsgroups to avoid confusion with sites:
-|([^\w\-/\.:\@>])(alt\.[\w\.+\-]+[\w+\-]+)|    -h-> $1<A HREF="news:$2">$2</A>
-|([^\w\-/\.:\@>])(bionet\.[\w\.+\-]+[\w+\-]+)| -h-> $1<A HREF="news:$2">$2</A>
-|([^\w\-/\.:\@>])(bit\.[\w\.+\-]+[\w+\-]+)|    -h-> $1<A HREF="news:$2">$2</A>
-|([^\w\-/\.:\@>])(biz\.[\w\.+\-]+[\w+\-]+)|    -h-> $1<A HREF="news:$2">$2</A>
-|([^\w\-/\.:\@>])(clari\.[\w\.+\-]+[\w+\-]+)|  -h-> $1<A HREF="news:$2">$2</A>
-|([^\w\-/\.:\@>])(comp\.[\w\.+\-]+[\w+\-]+)|   -h-> $1<A HREF="news:$2">$2</A>
-|([^\w\-/\.:\@>])(gnu\.[\w\.+\-]+[\w+\-]+)|    -h-> $1<A HREF="news:$2">$2</A>
-|([^\w\-/\.:\@>])(humanities\.[\w\.+\-]+[\w+\-]+)| 
-          -h-> $1<A HREF="news:$2">$2</A>
-|([^\w\-/\.:\@>])(k12\.[\w\.+\-]+[\w+\-]+)|    -h-> $1<A HREF="news:$2">$2</A>
-|([^\w\-/\.:\@>])(misc\.[\w\.+\-]+[\w+\-]+)|   -h-> $1<A HREF="news:$2">$2</A>
-|([^\w\-/\.:\@>])(news\.[\w\.+\-]+[\w+\-]+)|   -h-> $1<A HREF="news:$2">$2</A>
-|([^\w\-/\.:\@>])(rec\.[\w\.+\-]+[\w+\-]+)|    -h-> $1<A HREF="news:$2">$2</A>
-|([^\w\-/\.:\@>])(soc\.[\w\.+\-]+[\w+\-]+)|    -h-> $1<A HREF="news:$2">$2</A>
-|([^\w\-/\.:\@>])(talk\.[\w\.+\-]+[\w+\-]+)|   -h-> $1<A HREF="news:$2">$2</A>
-|([^\w\-/\.:\@>])(us\.[\w\.+\-]+[\w+\-]+)|     -h-> $1<A HREF="news:$2">$2</A>
-|([^\w\-/\.:\@>])(ch\.[\w\.+\-]+[\w+\-]+)|     -h-> $1<A HREF="news:$2">$2</A>
-|([^\w\-/\.:\@>])(de\.[\w\.+\-]+[\w+\-]+)|     -h-> $1<A HREF="news:$2">$2</A>
-
-# FTP locations (with directory):
-# anonymous@<site>:<path>
-|(anonymous\@)([a-zA-Z][\w\.+\-]+\.[a-zA-Z]{2,}):(\s*)([\w\d+\-/\.]+)|
-  -h-> $1<A HREF="ftp://$2/$4">$2:$4</A>$3
-
-# ftp@<site>:<path>
-|(ftp\@)([a-zA-Z][\w\.+\-]+\.[a-zA-Z]{2,}):(\s*)([\w\d+\-/\.]+)|
-  -h-> $1<A HREF="ftp://$2/$4">$2:$4</A>$3
-
-# Email address
-|[a-zA-Z0-9_\+\-\.]+\@([a-zA-Z0-9][\w\.+\-]+\.[a-zA-Z]{2,})|
-  -> mailto:$&
-
-# <site>:<path>
-|([^\w\-/\.:\@>])([a-zA-Z][\w\.+\-]+\.[a-zA-Z]{2,}):(\s*)([\w\d+\-/\.]+)|
-  -h-> $1<A HREF="ftp://$2/$4">$2:$4</A>$3
-
-# NB: don't confuse an http server with a port number for
-# an FTP location!
-# internet number version: <internet-num>:<path>
-|([^\w\-/\.:\@])(\d{2,}\.\d{2,}\.\d+\.\d+):([\w\d+\-/\.]+)|
-  -h-> $1<A HREF="ftp://$2/$3">$2:$3</A>
-
-# telnet <site> <port>
-|telnet ([a-zA-Z][\w+\-]+(\.[\w\.+\-]+)+\.[a-zA-Z]{2,})\s+(\d{2,4})|
-  -h-> telnet <A HREF="telnet://$1:$3/">$1 $3</A>
-
-# ftp <site>
-|ftp ([a-zA-Z][\w+\-]+(\.[\w\.+\-]+)+\.[a-zA-Z]{2,})|
-  -h-> ftp <A HREF="ftp://$1/">$1</A>
-
-# host with "ftp" in the machine name
-|\b([a-zA-Z][\w])*ftp[\w]*(\.[\w+\-]+){2,}| -h-> ftp <A HREF="ftp://$&/">$&</A>
-
-# ftp.foo.net/blah/
-|ftp(\.[a-zA-Z0-9_\@:-]+)+/\S+| -> ftp://$&
-
-# www.thehouse.org/txt2html/
-|www(\.[a-zA-Z0-9_\@:-]+)+/\S+| -> http://$&
-
-# host with "www" in the machine name
-|\b([a-zA-Z][\w])*www[\w]*(\.[\w+\-]+){2,}| -> http://$&/
-
-# <site> <port>
-|([a-zA-Z][\w+\-]+\.[\w+\-]+\.[a-zA-Z]{2,})\s+(\d{2,4})|
-  -h-> <A HREF="telnet://$1:$2/">$1 $2</A>
-
-# just internet numbers with port:
-|([^\w\-/\.:\@])(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+(\d{1,4})|
-  -h-> $1<A HREF="telnet://$2:$3">$2 $3</A>
-
-# just internet numbers:
-|([^\w\-/\.:\@])(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|
-  -h-> $1<A HREF="telnet://$2">$2</A>
-
-# RFCs
-/RFC ?(\d+)/ -i-> http://www.cis.ohio-state.edu/rfc/rfc$1.txt
-
-# This would turn "f^H_o^H_o^H_" into "<U>foo</U>".  Gross, isn't it?
-# Thanks to Mark O'Dell <emark@cns.caltech.edu> for fixing this. 
-#
-# /(.\\010_)+/ -he-> $tmp = $&;$tmp =~ s@\010_@@g;"<U>$tmp</U>"
-# /(_\\010.)+/ -he-> $tmp = $&;$tmp =~ s@_\010@@g;"<U>$tmp</U>"
-# /(.\^H_)+/ -he-> $tmp = $&;$tmp =~ s@\^H_@@g;"<U>$tmp</U>"
-# /(_\^H.)+/ -he-> $tmp = $&;$tmp =~ s@_\^H@@g;"<U>$tmp</U>"
-
-# Mark _underlined stuff_ as <U>underlined stuff</U>
-# Don't mistake variable names for underlines, and
-# take account of possible trailing punctuation
-/([ \t\n])_([a-z][a-z0-9 -]*[a-z])_([ \t\n\.;:,\!\?])/ -hi-> $1<U>$2</U>$3
-
-# Seth and his amazing conversion program    :-)
-
-"Seth Golub"  -io-> http://www.aigeek.com/
-"txt2html"    -io-> http://txt2html.sourceforge.net/
-
-# Kathryn and her amazing modules 8-)
-"Kathryn Andersen"  -io-> http://www.katspace.com/
-"HTML::TextToHTML"  -io-> http://www.katspace.com/tools/text_to_html/
-"hypertoc"          -io-> http://www.katspace.com/tools/hypertoc/
-"HTML::GenToc"      -io-> http://www.katspace.com/tools/hypertoc/
-
-# End of global dictionary
-
diff --git a/lib/MP3/Info.pm b/lib/MP3/Info.pm
deleted file mode 100644
index 3303ac5..0000000
--- a/lib/MP3/Info.pm
+++ /dev/null
@@ -1,1563 +0,0 @@
-package MP3::Info;
-use overload;
-use strict;
-use Carp;
-use Symbol;
-
-use vars qw(
-	@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION $REVISION
-	@mp3_genres %mp3_genres @winamp_genres %winamp_genres $try_harder
-	@t_bitrate @t_sampling_freq @frequency_tbl %v1_tag_fields
-	@v1_tag_names %v2_tag_names %v2_to_v1_names $AUTOLOAD
-	@mp3_info_fields
-);
-
-@ISA = 'Exporter';
-@EXPORT = qw(
-	set_mp3tag get_mp3tag get_mp3info remove_mp3tag
-	use_winamp_genres
-);
-@EXPORT_OK = qw(@mp3_genres %mp3_genres use_mp3_utf8);
-%EXPORT_TAGS = (
-	genres	=> [qw(@mp3_genres %mp3_genres)],
-	utf8	=> [qw(use_mp3_utf8)],
-	all	=> [@EXPORT, @EXPORT_OK]
-);
-
-# $Id: Info.pm,v 1.15 2003/03/02 19:16:43 pudge Exp $
-($REVISION) = ' $Revision: 1.15 $ ' =~ /\$Revision:\s+([^\s]+)/;
-$VERSION = '1.02';
-
-=pod
-
-=head1 NAME
-
-MP3::Info - Manipulate / fetch info from MP3 audio files
-
-=head1 SYNOPSIS
-
-	#!perl -w
-	use MP3::Info;
-	my $file = 'Pearls_Before_Swine.mp3';
-	set_mp3tag($file, 'Pearls Before Swine', q"77's",
-		'Sticks and Stones', '1990',
-		q"(c) 1990 77's LTD.", 'rock & roll');
-
-	my $tag = get_mp3tag($file) or die "No TAG info";
-	$tag->{GENRE} = 'rock';
-	set_mp3tag($file, $tag);
-
-	my $info = get_mp3info($file);
-	printf "$file length is %d:%d\n", $info->{MM}, $info->{SS};
-
-=cut
-
-{
-	my $c = -1;
-	# set all lower-case and regular-cased versions of genres as keys
-	# with index as value of each key
-	%mp3_genres = map {($_, ++$c, lc, $c)} @mp3_genres;
-
-	# do it again for winamp genres
-	$c = -1;
-	%winamp_genres = map {($_, ++$c, lc, $c)} @winamp_genres;
-}
-
-=pod
-
-	my $mp3 = new MP3::Info $file;
-	$mp3->title('Perls Before Swine');
-	printf "$file length is %s, title is %s\n",
-		$mp3->time, $mp3->title;
-
-
-=head1 DESCRIPTION
-
-=over 4
-
-=item $mp3 = MP3::Info-E<gt>new(FILE)
-
-OOP interface to the rest of the module.  The same keys
-available via get_mp3info and get_mp3tag are available
-via the returned object (using upper case or lower case;
-but note that all-caps "VERSION" will return the module
-version, not the MP3 version).
-
-Passing a value to one of the methods will set the value
-for that tag in the MP3 file, if applicable.
-
-=cut
-
-sub new {
-	my($pack, $file) = @_;
-
-	my $info = get_mp3info($file) or return undef;
-	my $tags = get_mp3tag($file) || { map { ($_ => undef) } @v1_tag_names };
-	my %self = (
-		FILE		=> $file,
-		TRY_HARDER	=> 0
-	);
-
-	@self{@mp3_info_fields, @v1_tag_names, 'file'} = (
-		@{$info}{@mp3_info_fields},
-		@{$tags}{@v1_tag_names},
-		$file
-	);
-
-	return bless \%self, $pack;
-}
-
-sub can {
-	my $self = shift;
-	return $self->SUPER::can(@_) unless ref $self;
-	my $name = uc shift;
-	return sub { $self->$name(@_) } if exists $self->{$name};
-	return undef;
-}
-
-sub AUTOLOAD {
-	my($self) = @_;
-	(my $name = uc $AUTOLOAD) =~ s/^.*://;
-
-	if (exists $self->{$name}) {
-		my $sub = exists $v1_tag_fields{$name}
-			? sub {
-				if (defined $_[1]) {
-					$_[0]->{$name} = $_[1];
-					set_mp3tag($_[0]->{FILE}, $_[0]);
-				}
-				return $_[0]->{$name};
-			}
-			: sub {
-				return $_[0]->{$name}
-			};
-
-		no strict 'refs';
-		*{$AUTOLOAD} = $sub;
-		goto &$AUTOLOAD;
-
-	} else {
-		carp(sprintf "No method '$name' available in package %s.",
-			__PACKAGE__);
-	}
-}
-
-sub DESTROY {
-
-}
-
-
-=item use_mp3_utf8([STATUS])
-
-Tells MP3::Info to (or not) return TAG info in UTF-8.
-TRUE is 1, FALSE is 0.  Default is FALSE.
-
-Will only be able to it on if Unicode::String is available.  ID3v2
-tags will be converted to UTF-8 according to the encoding specified
-in each tag; ID3v1 tags will be assumed Latin-1 and converted
-to UTF-8.
-
-Function returns status (TRUE/FALSE).  If no argument is supplied,
-or an unaccepted argument is supplied, function merely returns status.
-
-This function is not exported by default, but may be exported
-with the C<:utf8> or C<:all> export tag.
-
-=cut
-
-my $unicode_module = 0; #eval { require Unicode::String };
-my $UNICODE = 0;
-
-sub use_mp3_utf8 {
-	my($val) = @_;
-	if ($val == 1) {
-		$UNICODE = 1 if $unicode_module;
-	} elsif ($val == 0) {
-		$UNICODE = 0;
-	}
-	return $UNICODE;
-}
-
-=pod
-
-=item use_winamp_genres()
-
-Puts WinAmp genres into C<@mp3_genres> and C<%mp3_genres>
-(adds 68 additional genres to the default list of 80).
-This is a separate function because these are non-standard
-genres, but they are included because they are widely used.
-
-You can import the data structures with one of:
-
-	use MP3::Info qw(:genres);
-	use MP3::Info qw(:DEFAULT :genres);
-	use MP3::Info qw(:all);
-
-=cut
-
-sub use_winamp_genres {
-	%mp3_genres = %winamp_genres;
-	@mp3_genres = @winamp_genres;
-	return 1;
-}
-
-=pod
-
-=item remove_mp3tag (FILE [, VERSION, BUFFER])
-
-Can remove ID3v1 or ID3v2 tags.  VERSION should be C<1> for ID3v1,
-C<2> for ID3v2, and C<ALL> for both.
-
-For ID3v1, removes last 128 bytes from file if those last 128 bytes begin
-with the text 'TAG'.  File will be 128 bytes shorter.
-
-For ID3v2, removes ID3v2 tag.  Because an ID3v2 tag is at the
-beginning of the file, we rewrite the file after removing the tag data.
-The buffer for rewriting the file is 4MB.  BUFFER (in bytes) ca
-change the buffer size.
-
-Returns the number of bytes removed, or -1 if no tag removed,
-or undef if there is an error.
-
-=cut
-
-sub remove_mp3tag {
-	my($file, $version, $buf) = @_;
-	my($fh, $return);
-
-	$buf ||= 4096*1024;  # the bigger the faster
-	$version ||= 1;
-
-	if (not (defined $file && $file ne '')) {
-		$@ = "No file specified";
-		return undef;
-	}
-
-	if (not -s $file) {
-		$@ = "File is empty";
-		return undef;
-	}
-
-	if (ref $file) { # filehandle passed
-		$fh = $file;
-	} else {
-		$fh = gensym;
-		if (not open $fh, "+< $file\0") {
-			$@ = "Can't open $file: $!";
-			return undef;
-		}
-	}
-
-	binmode $fh;
-
-	if ($version eq 1 || $version eq 'ALL') {
-		seek $fh, -128, 2;
-		my $tell = tell $fh;
-		if (<$fh> =~ /^TAG/) {
-			truncate $fh, $tell or carp "Can't truncate '$file': $!";
-			$return += 128;
-		}
-	}
-
-	if ($version eq 2 || $version eq 'ALL') {
-		my $h = _get_v2head($fh);
-		if ($h) {
-			local $\;
-			seek $fh, 0, 2;
-			my $eof = tell $fh;
-			my $off = $h->{tag_size};
-
-			while ($off < $eof) {
-				seek $fh, $off, 0;
-				read $fh, my($bytes), $buf;
-				seek $fh, $off - $h->{tag_size}, 0;
-				print $fh $bytes;
-				$off += $buf;
-			}
-
-			truncate $fh, $eof - $h->{tag_size}
-				or carp "Can't truncate '$file': $!";
-			$return += $h->{tag_size};
-		}
-	}
-
-	_close($file, $fh);
-
-	return $return || -1;
-}
-
-
-=pod
-
-=item set_mp3tag (FILE, TITLE, ARTIST, ALBUM, YEAR, COMMENT, GENRE [, TRACKNUM])
-
-=item set_mp3tag (FILE, $HASHREF)
-
-Adds/changes tag information in an MP3 audio file.  Will clobber
-any existing information in file.
-
-Fields are TITLE, ARTIST, ALBUM, YEAR, COMMENT, GENRE.  All fields have
-a 30-byte limit, except for YEAR, which has a four-byte limit, and GENRE,
-which is one byte in the file.  The GENRE passed in the function is a
-case-insensitive text string representing a genre found in C<@mp3_genres>.
-
-Will accept either a list of values, or a hashref of the type
-returned by C<get_mp3tag>.
-
-If TRACKNUM is present (for ID3v1.1), then the COMMENT field can only be
-28 bytes.
-
-ID3v2 support may come eventually.  Note that if you set a tag on a file
-with ID3v2, the set tag will be for ID3v1[.1] only, and if you call
-C<get_mp3_tag> on the file, it will show you the (unchanged) ID3v2 tags,
-unless you specify ID3v1.
-
-=cut
-
-sub set_mp3tag {
-	my($file, $title, $artist, $album, $year, $comment, $genre, $tracknum) = @_;
-	my(%info, $oldfh, $ref, $fh);
-	local %v1_tag_fields = %v1_tag_fields;
-
-	# set each to '' if undef
-	for ($title, $artist, $album, $year, $comment, $tracknum, $genre,
-		(@info{@v1_tag_names}))
-		{$_ = defined() ? $_ : ''}
-
-	($ref) = (overload::StrVal($title) =~ /^(?:.*\=)?([^=]*)\((?:[^\(]*)\)$/)
-		if ref $title;
-	# populate data to hashref if hashref is not passed
-	if (!$ref) {
-		(@info{@v1_tag_names}) =
-			($title, $artist, $album, $year, $comment, $tracknum, $genre);
-
-	# put data from hashref into hashref if hashref is passed
-	} elsif ($ref eq 'HASH') {
-		%info = %$title;
-
-	# return otherwise
-	} else {
-		carp(<<'EOT');
-Usage: set_mp3tag (FILE, TITLE, ARTIST, ALBUM, YEAR, COMMENT, GENRE [, TRACKNUM])
-       set_mp3tag (FILE, $HASHREF)
-EOT
-		return undef;
-	}
-
-	if (not (defined $file && $file ne '')) {
-		$@ = "No file specified";
-		return undef;
-	}
-
-	if (not -s $file) {
-		$@ = "File is empty";
-		return undef;
-	}
-
-	# comment field length 28 if ID3v1.1
-	$v1_tag_fields{COMMENT} = 28 if $info{TRACKNUM};
-
-
-	# only if -w is on
-	if ($^W) {
-		# warn if fields too long
-		foreach my $field (keys %v1_tag_fields) {
-			$info{$field} = '' unless defined $info{$field};
-			if (length($info{$field}) > $v1_tag_fields{$field}) {
-				carp "Data too long for field $field: truncated to " .
-					 "$v1_tag_fields{$field}";
-			}
-		}
-
-		if ($info{GENRE}) {
-			carp "Genre `$info{GENRE}' does not exist\n"
-				unless exists $mp3_genres{$info{GENRE}};
-		}
-	}
-
-	if ($info{TRACKNUM}) {
-		$info{TRACKNUM} =~ s/^(\d+)\/(\d+)$/$1/;
-		unless ($info{TRACKNUM} =~ /^\d+$/ &&
-			$info{TRACKNUM} > 0 && $info{TRACKNUM} < 256) {
-			carp "Tracknum `$info{TRACKNUM}' must be an integer " .
-				"from 1 and 255\n" if $^W;
-			$info{TRACKNUM} = '';
-		}
-	}
-
-	if (ref $file) { # filehandle passed
-		$fh = $file;
-	} else {
-		$fh = gensym;
-		if (not open $fh, "+< $file\0") {
-			$@ = "Can't open $file: $!";
-			return undef;
-		}
-	}
-
-	binmode $fh;
-	$oldfh = select $fh;
-	seek $fh, -128, 2;
-	# go to end of file if no tag, beginning of file if tag
-	seek $fh, (<$fh> =~ /^TAG/ ? -128 : 0), 2;
-
-	# get genre value
-	$info{GENRE} = $info{GENRE} && exists $mp3_genres{$info{GENRE}} ?
-		$mp3_genres{$info{GENRE}} : 255;  # some default genre
-
-	local $\;
-	# print TAG to file
-	if ($info{TRACKNUM}) {
-		print pack "a3a30a30a30a4a28xCC", 'TAG', @info{@v1_tag_names};
-	} else {
-		print pack "a3a30a30a30a4a30C", 'TAG', @info{@v1_tag_names[0..4, 6]};
-	}
-
-	select $oldfh;
-
-	_close($file, $fh);
-
-	return 1;
-}
-
-=pod
-
-=item get_mp3tag (FILE [, VERSION, RAW_V2])
-
-Returns hash reference containing tag information in MP3 file.  The keys
-returned are the same as those supplied for C<set_mp3tag>, except in the
-case of RAW_V2 being set.
-
-If VERSION is C<1>, the information is taken from the ID3v1 tag (if present).
-If VERSION is C<2>, the information is taken from the ID3v2 tag (if present).
-If VERSION is not supplied, or is false, the ID3v1 tag is read if present, and
-then, if present, the ID3v2 tag information will override any existing ID3v1
-tag info.
-
-If RAW_V2 is C<1>, the raw ID3v2 tag data is returned, without any manipulation
-of text encoding.  The key name is the same as the frame ID (ID to name mappings
-are in the global %v2_tag_names).
-
-If RAW_V2 is C<2>, the ID3v2 tag data is returned, manipulating for Unicode if
-necessary, etc.  It also takes multiple values for a given key (such as comments)
-and puts them in an arrayref.
-
-If the ID3v2 version is older than ID3v2.2.0 or newer than ID3v2.4.0, it will
-not be read.
-
-Strings returned will be in Latin-1, unless UTF-8 is specified (L<use_mp3_utf8>),
-(unless RAW_V2 is C<1>).
-
-Also returns a TAGVERSION key, containing the ID3 version used for the returned
-data (if TAGVERSION argument is C<0>, may contain two versions).
-
-=cut
-
-sub get_mp3tag {
-	my($file, $ver, $raw_v2) = @_;
-	my($tag, $v1, $v2, $v2h, %info, @array, $fh);
-	$raw_v2 ||= 0;
-	$ver = !$ver ? 0 : ($ver == 2 || $ver == 1) ? $ver : 0;
-
-	if (not (defined $file && $file ne '')) {
-		$@ = "No file specified";
-		return undef;
-	}
-
-	if (not -s $file) {
-		$@ = "File is empty";
-		return undef;
-	}
-
-	if (ref $file) { # filehandle passed
-		$fh = $file;
-	} else {
-		$fh = gensym;
-		if (not open $fh, "< $file\0") {
-			$@ = "Can't open $file: $!";
-			return undef;
-		}
-	}
-
-	binmode $fh;
-
-	if ($ver < 2) {
-		seek $fh, -128, 2;
-		while(defined(my $line = <$fh>)) { $tag .= $line }
-
-		if ($tag =~ /^TAG/) {
-			$v1 = 1;
-			if (substr($tag, -3, 2) =~ /\000[^\000]/) {
-				(undef, @info{@v1_tag_names}) =
-					(unpack('a3a30a30a30a4a28', $tag),
-					ord(substr($tag, -2, 1)),
-					$mp3_genres[ord(substr $tag, -1)]);
-				$info{TAGVERSION} = 'ID3v1.1';
-			} else {
-				(undef, @info{@v1_tag_names[0..4, 6]}) =
-					(unpack('a3a30a30a30a4a30', $tag),
-					$mp3_genres[ord(substr $tag, -1)]);
-				$info{TAGVERSION} = 'ID3v1';
-			}
-			if ($UNICODE) {
-				for my $key (keys %info) {
-					next unless $info{$key};
-					my $u = Unicode::String::latin1($info{$key});
-					$info{$key} = $u->utf8;
-				}
-			}
-		} elsif ($ver == 1) {
-			_close($file, $fh);
-			$@ = "No ID3v1 tag found";
-			return undef;
-		}
-	}
-
-	($v2, $v2h) = _get_v2tag($fh);
-
-	unless ($v1 || $v2) {
-		_close($file, $fh);
-		$@ = "No ID3 tag found";
-		return undef;
-	}
-
-	if (($ver == 0 || $ver == 2) && $v2) {
-		if ($raw_v2 == 1 && $ver == 2) {
-			%info = %$v2;
-			$info{TAGVERSION} = $v2h->{version};
-		} else {
-			my $hash = $raw_v2 == 2 ? { map { ($_, $_) } keys %v2_tag_names } : \%v2_to_v1_names;
-			for my $id (keys %$hash) {
-				if (exists $v2->{$id}) {
-					if ($id =~ /^TCON?$/ && $v2->{$id} =~ /^.?\((\d+)\)/) {
-						$info{$hash->{$id}} = $mp3_genres[$1];
-					} else {
-						my $data1 = $v2->{$id};
-
-						# this is tricky ... if this is an arrayref,
-						# we want to only return one, so we pick the
-						# first one.  but if it is a comment, we pick
-						# the first one where the first charcter after
-						# the language is NULL and not an additional
-						# sub-comment, because that is most likely to be
-						# the user-supplied comment
-						if (ref $data1 && !$raw_v2) {
-							if ($id =~ /^COMM?$/) {
-								my($newdata) = grep /^(....\000)/, @{$data1};
-								$data1 = $newdata || $data1->[0];
-							} else {
-								$data1 = $data1->[0];
-							}
-						}
-
-						$data1 = [ $data1 ] if ! ref $data1;
-
-						for my $data (@$data1) {
-							$data =~ s/^(.)//; # strip first char (text encoding)
-							my $encoding = $1;
-							my $desc;
-							if ($id =~ /^COM[M ]?$/) {
-								$data =~ s/^(?:...)//;		# strip language
-								$data =~ s/^(.*?)\000+//;	# strip up to first NULL(s),
-												# for sub-comment
-								$desc = $1;
-							}
-
-							if ($UNICODE) {
-								if ($encoding eq "\001" || $encoding eq "\002") {  # UTF-16, UTF-16BE
-									my $u = Unicode::String::utf16($data);
-									$data = $u->utf8;
-									$data =~ s/^\xEF\xBB\xBF//;	# strip BOM
-								} elsif ($encoding eq "\000") {
-									my $u = Unicode::String::latin1($data);
-									$data = $u->utf8;
-								}
-							}
-
-							if ($raw_v2 == 2 && $desc) {
-								$data = { $desc => $data };
-							}
-
-							if ($raw_v2 == 2 && exists $info{$hash->{$id}}) {
-								if (ref $info{$hash->{$id}} eq 'ARRAY') {
-									push @{$info{$hash->{$id}}}, $data;
-								} else {
-									$info{$hash->{$id}} = [ $info{$hash->{$id}}, $data ];
-								}
-							} else {
-								$info{$hash->{$id}} = $data;
-							}
-						}
-					}
-				}
-			}
-			if ($ver == 0 && $info{TAGVERSION}) {
-				$info{TAGVERSION} .= ' / ' . $v2h->{version};
-			} else {
-				$info{TAGVERSION} = $v2h->{version};
-			}
-		}
-	}
-
-	unless ($raw_v2 && $ver == 2) {
-		foreach my $key (keys %info) {
-			if (defined $info{$key}) {
-				$info{$key} =~ s/\000+.*//g;
-				$info{$key} =~ s/\s+$//;
-			}
-		}
-
-		for (@v1_tag_names) {
-			$info{$_} = '' unless defined $info{$_};
-		}
-	}
-
-	if (keys %info && exists $info{GENRE} && ! defined $info{GENRE}) {
-		$info{GENRE} = '';
-	}
-
-	_close($file, $fh);
-
-	return keys %info ? {%info} : undef;
-}
-
-sub _get_v2tag {
-	my($fh) = @_;
-	my($off, $myseek, $myseek_22, $myseek_23, $v2, $h, $hlen, $num);
-	$h = {};
-
-	$v2 = _get_v2head($fh) or return;
-	if ($v2->{major_version} < 2) {
-		carp "This is $v2->{version}; " .
-		     "ID3v2 versions older than ID3v2.2.0 not supported\n"
-		     if $^W;
-		return;
-	}
-
-	if ($v2->{major_version} == 2) {
-		$hlen = 6;
-		$num = 3;
-	} else {
-		$hlen = 10;
-		$num = 4;
-	}
-
-	$myseek = sub {
-		seek $fh, $off, 0;
-		read $fh, my($bytes), $hlen;
-		return unless $bytes =~ /^([A-Z0-9]{$num})/
-			|| ($num == 4 && $bytes =~ /^(COM )/);  # stupid iTunes
-		my($id, $size) = ($1, $hlen);
-		my @bytes = reverse unpack "C$num", substr($bytes, $num, $num);
-		for my $i (0 .. ($num - 1)) {
-			$size += $bytes[$i] * 256 ** $i;
-		}
-		return($id, $size);
-	};
-
-	$off = $v2->{ext_header_size} + 10;
-
-	while ($off < $v2->{tag_size}) {
-		my($id, $size) = &$myseek or last;
-		seek $fh, $off + $hlen, 0;
-		read $fh, my($bytes), $size - $hlen;
-		if (exists $h->{$id}) {
-			if (ref $h->{$id} eq 'ARRAY') {
-				push @{$h->{$id}}, $bytes;
-			} else {
-				$h->{$id} = [$h->{$id}, $bytes];
-			}
-		} else {
-			$h->{$id} = $bytes;
-		}
-		$off += $size;
-	}
-
-	return($h, $v2);
-}
-
-
-=pod
-
-=item get_mp3info (FILE)
-
-Returns hash reference containing file information for MP3 file.
-This data cannot be changed.  Returned data:
-
-	VERSION		MPEG audio version (1, 2, 2.5)
-	LAYER		MPEG layer description (1, 2, 3)
-	STEREO		boolean for audio is in stereo
-
-	VBR		boolean for variable bitrate
-	BITRATE		bitrate in kbps (average for VBR files)
-	FREQUENCY	frequency in kHz
-	SIZE		bytes in audio stream
-
-	SECS		total seconds
-	MM		minutes
-	SS		leftover seconds
-	MS		leftover milliseconds
-	TIME		time in MM:SS
-
-	COPYRIGHT	boolean for audio is copyrighted
-	PADDING		boolean for MP3 frames are padded
-	MODE		channel mode (0 = stereo, 1 = joint stereo,
-			2 = dual channel, 3 = single channel)
-	FRAMES		approximate number of frames
-	FRAME_LENGTH	approximate length of a frame
-	VBR_SCALE	VBR scale from VBR header
-
-On error, returns nothing and sets C<$@>.
-
-=cut
-
-sub get_mp3info {
-	my($file) = @_;
-	my($off, $myseek, $byte, $eof, $h, $tot, $fh);
-
-	if (not (defined $file && $file ne '')) {
-		$@ = "No file specified";
-		return undef;
-	}
-
-	if (not -s $file) {
-		$@ = "File is empty";
-		return undef;
-	}
-
-	if (ref $file) { # filehandle passed
-		$fh = $file;
-	} else {
-		$fh = gensym;
-		if (not open $fh, "< $file\0") {
-			$@ = "Can't open $file: $!";
-			return undef;
-		}
-	}
-
-	$off = 0;
-	$tot = 4096;
-
-	$myseek = sub {
-		seek $fh, $off, 0;
-		read $fh, $byte, 4;
-	};
-
-	binmode $fh;
-	&$myseek;
-
-	if ($off == 0) {
-		if (my $id3v2 = _get_v2head($fh)) {
-			$tot += $off += $id3v2->{tag_size};
-			&$myseek;
-		}
-	}
-
-	$h = _get_head($byte);
-	until (_is_mp3($h)) {
-		$off++;
-		&$myseek;
-		$h = _get_head($byte);
-		if ($off > $tot && !$try_harder) {
-			_close($file, $fh);
-			$@ = "Couldn't find MP3 header (perhaps set " .
-			     '$MP3::Info::try_harder and retry)';
-			return undef;
-		}
-	}
-
-	my $vbr = _get_vbr($fh, $h, \$off);
-
-	seek $fh, 0, 2;
-	$eof = tell $fh;
-	seek $fh, -128, 2;
-	$off += 128 if <$fh> =~ /^TAG/ ? 1 : 0;
-
-	_close($file, $fh);
-
-	$h->{size} = $eof - $off;
-
-	return _get_info($h, $vbr);
-}
-
-sub _get_info {
-	my($h, $vbr) = @_;
-	my $i;
-
-	$i->{VERSION}	= $h->{IDR} == 2 ? 2 : $h->{IDR} == 3 ? 1 :
-				$h->{IDR} == 0 ? 2.5 : 0;
-	$i->{LAYER}	= 4 - $h->{layer};
-	$i->{VBR}	= defined $vbr ? 1 : 0;
-
-	$i->{COPYRIGHT}	= $h->{copyright} ? 1 : 0;
-	$i->{PADDING}	= $h->{padding_bit} ? 1 : 0;
-	$i->{STEREO}	= $h->{mode} == 3 ? 0 : 1;
-	$i->{MODE}	= $h->{mode};
-
-	$i->{SIZE}	= $vbr && $vbr->{bytes} ? $vbr->{bytes} : $h->{size};
-
-	my $mfs		= $h->{fs} / ($h->{ID} ? 144000 : 72000);
-	$i->{FRAMES}	= int($vbr && $vbr->{frames}
-				? $vbr->{frames}
-				: $i->{SIZE} / $h->{bitrate} / $mfs
-			  );
-
-	if ($vbr) {
-		$i->{VBR_SCALE}	= $vbr->{scale} if $vbr->{scale};
-		$h->{bitrate}	= $i->{SIZE} / $i->{FRAMES} * $mfs;
-		if (not $h->{bitrate}) {
-			$@ = "Couldn't determine VBR bitrate";
-			return undef;
-		}
-	}
-
-	$h->{'length'}	= ($i->{SIZE} * 8) / $h->{bitrate} / 10;
-	$i->{SECS}	= $h->{'length'} / 100;
-	$i->{MM}	= int $i->{SECS} / 60;
-	$i->{SS}	= int $i->{SECS} % 60;
-	$i->{MS}	= (($i->{SECS} - ($i->{MM} * 60) - $i->{SS}) * 1000);
-#	$i->{LF}	= ($i->{MS} / 1000) * ($i->{FRAMES} / $i->{SECS});
-#	int($i->{MS} / 100 * 75);  # is this right?
-	$i->{TIME}	= sprintf "%.2d:%.2d", @{$i}{'MM', 'SS'};
-
-	$i->{BITRATE}		= int $h->{bitrate};
-	# should we just return if ! FRAMES?
-	$i->{FRAME_LENGTH}	= int($h->{size} / $i->{FRAMES}) if $i->{FRAMES};
-	$i->{FREQUENCY}		= $frequency_tbl[3 * $h->{IDR} + $h->{sampling_freq}];
-
-	return $i;
-}
-
-sub _get_head {
-	my($byte) = @_;
-	my($bytes, $h);
-
-	$bytes = _unpack_head($byte);
-	@$h{qw(IDR ID layer protection_bit
-		bitrate_index sampling_freq padding_bit private_bit
-		mode mode_extension copyright original
-		emphasis version_index bytes)} = (
-		($bytes>>19)&3, ($bytes>>19)&1, ($bytes>>17)&3, ($bytes>>16)&1,
-		($bytes>>12)&15, ($bytes>>10)&3, ($bytes>>9)&1, ($bytes>>8)&1,
-		($bytes>>6)&3, ($bytes>>4)&3, ($bytes>>3)&1, ($bytes>>2)&1,
-		$bytes&3, ($bytes>>19)&3, $bytes
-	);
-
-	$h->{bitrate} = $t_bitrate[$h->{ID}][3 - $h->{layer}][$h->{bitrate_index}];
-	$h->{fs} = $t_sampling_freq[$h->{IDR}][$h->{sampling_freq}];
-
-	return $h;
-}
-
-sub _is_mp3 {
-	my $h = $_[0] or return undef;
-	return ! (	# all below must be false
-		 $h->{bitrate_index} == 0
-			||
-		 $h->{version_index} == 1
-			||
-		($h->{bytes} & 0xFFE00000) != 0xFFE00000
-			||
-		!$h->{fs}
-			||
-		!$h->{bitrate}
-			||
-		 $h->{bitrate_index} == 15
-			||
-		!$h->{layer}
-			||
-		 $h->{sampling_freq} == 3
-			||
-		 $h->{emphasis} == 2
-			||
-		!$h->{bitrate_index}
-			||
-		($h->{bytes} & 0xFFFF0000) == 0xFFFE0000
-			||
-		($h->{ID} == 1 && $h->{layer} == 3 && $h->{protection_bit} == 1)
-			||
-		($h->{mode_extension} != 0 && $h->{mode} != 1)
-	);
-}
-
-sub _get_vbr {
-	my($fh, $h, $roff) = @_;
-	my($off, $bytes, @bytes, $myseek, %vbr);
-
-	$off = $$roff;
-	@_ = ();	# closure confused if we don't do this
-
-	$myseek = sub {
-		my $n = $_[0] || 4;
-		seek $fh, $off, 0;
-		read $fh, $bytes, $n;
-		$off += $n;
-	};
-
-	$off += 4;
-
-	if ($h->{ID}) {	# MPEG1
-		$off += $h->{mode} == 3 ? 17 : 32;
-	} else {	# MPEG2
-		$off += $h->{mode} == 3 ? 9 : 17;
-	}
-
-	&$myseek;
-	return unless $bytes eq 'Xing';
-
-	&$myseek;
-	$vbr{flags} = _unpack_head($bytes);
-
-	if ($vbr{flags} & 1) {
-		&$myseek;
-		$vbr{frames} = _unpack_head($bytes);
-	}
-
-	if ($vbr{flags} & 2) {
-		&$myseek;
-		$vbr{bytes} = _unpack_head($bytes);
-	}
-
-	if ($vbr{flags} & 4) {
-		$myseek->(100);
-# Not used right now ...
-#		$vbr{toc} = _unpack_head($bytes);
-	}
-
-	if ($vbr{flags} & 8) { # (quality ind., 0=best 100=worst)
-		&$myseek;
-		$vbr{scale} = _unpack_head($bytes);
-	} else {
-		$vbr{scale} = -1;
-	}
-
-	$$roff = $off;
-	return \%vbr;
-}
-
-sub _get_v2head {
-	my $fh = $_[0] or return;
-	my($h, $bytes, @bytes);
-
-	# check first three bytes for 'ID3'
-	seek $fh, 0, 0;
-	read $fh, $bytes, 3;
-	return unless $bytes eq 'ID3';
-
-	# get version
-	read $fh, $bytes, 2;
-	$h->{version} = sprintf "ID3v2.%d.%d",
-		@$h{qw[major_version minor_version]} =
-			unpack 'c2', $bytes;
-
-	# get flags
-	read $fh, $bytes, 1;
-	if ($h->{major_version} == 2) {
-		@$h{qw[unsync compression]} =
-			(unpack 'b8', $bytes)[7, 6];
-		$h->{ext_header} = 0;
-		$h->{experimental} = 0;
-	} else {
-		@$h{qw[unsync ext_header experimental]} =
-			(unpack 'b8', $bytes)[7, 6, 5];
-	}
-
-	# get ID3v2 tag length from bytes 7-10
-	$h->{tag_size} = 10;	# include ID3v2 header size
-	read $fh, $bytes, 4;
-	@bytes = reverse unpack 'C4', $bytes;
-	foreach my $i (0 .. 3) {
-		# whoaaaaaa nellllllyyyyyy!
-		$h->{tag_size} += $bytes[$i] * 128 ** $i;
-	}
-
-	# get extended header size
-	$h->{ext_header_size} = 0;
-	if ($h->{ext_header}) {
-		$h->{ext_header_size} += 10;
-		read $fh, $bytes, 4;
-		@bytes = reverse unpack 'C4', $bytes;
-		for my $i (0..3) {
-			$h->{ext_header_size} += $bytes[$i] * 256 ** $i;
-		}
-	}
-
-	return $h;
-}
-
-sub _unpack_head {
-	unpack('l', pack('L', unpack('N', $_[0])));
-}
-
-sub _close {
-	my($file, $fh) = @_;
-	unless (ref $file) { # filehandle not passed
-		close $fh or carp "Problem closing '$file': $!";
-	}
-}
-
-BEGIN {
-	@mp3_genres = (
-		'Blues',
-		'Classic Rock',
-		'Country',
-		'Dance',
-		'Disco',
-		'Funk',
-		'Grunge',
-		'Hip-Hop',
-		'Jazz',
-		'Metal',
-		'New Age',
-		'Oldies',
-		'Other',
-		'Pop',
-		'R&B',
-		'Rap',
-		'Reggae',
-		'Rock',
-		'Techno',
-		'Industrial',
-		'Alternative',
-		'Ska',
-		'Death Metal',
-		'Pranks',
-		'Soundtrack',
-		'Euro-Techno',
-		'Ambient',
-		'Trip-Hop',
-		'Vocal',
-		'Jazz+Funk',
-		'Fusion',
-		'Trance',
-		'Classical',
-		'Instrumental',
-		'Acid',
-		'House',
-		'Game',
-		'Sound Clip',
-		'Gospel',
-		'Noise',
-		'AlternRock',
-		'Bass',
-		'Soul',
-		'Punk',
-		'Space',
-		'Meditative',
-		'Instrumental Pop',
-		'Instrumental Rock',
-		'Ethnic',
-		'Gothic',
-		'Darkwave',
-		'Techno-Industrial',
-		'Electronic',
-		'Pop-Folk',
-		'Eurodance',
-		'Dream',
-		'Southern Rock',
-		'Comedy',
-		'Cult',
-		'Gangsta',
-		'Top 40',
-		'Christian Rap',
-		'Pop/Funk',
-		'Jungle',
-		'Native American',
-		'Cabaret',
-		'New Wave',
-		'Psychadelic',
-		'Rave',
-		'Showtunes',
-		'Trailer',
-		'Lo-Fi',
-		'Tribal',
-		'Acid Punk',
-		'Acid Jazz',
-		'Polka',
-		'Retro',
-		'Musical',
-		'Rock & Roll',
-		'Hard Rock',
-	);
-
-	@winamp_genres = (
-		@mp3_genres,
-		'Folk',
-		'Folk-Rock',
-		'National Folk',
-		'Swing',
-		'Fast Fusion',
-		'Bebob',
-		'Latin',
-		'Revival',
-		'Celtic',
-		'Bluegrass',
-		'Avantgarde',
-		'Gothic Rock',
-		'Progressive Rock',
-		'Psychedelic Rock',
-		'Symphonic Rock',
-		'Slow Rock',
-		'Big Band',
-		'Chorus',
-		'Easy Listening',
-		'Acoustic',
-		'Humour',
-		'Speech',
-		'Chanson',
-		'Opera',
-		'Chamber Music',
-		'Sonata',
-		'Symphony',
-		'Booty Bass',
-		'Primus',
-		'Porn Groove',
-		'Satire',
-		'Slow Jam',
-		'Club',
-		'Tango',
-		'Samba',
-		'Folklore',
-		'Ballad',
-		'Power Ballad',
-		'Rhythmic Soul',
-		'Freestyle',
-		'Duet',
-		'Punk Rock',
-		'Drum Solo',
-		'Acapella',
-		'Euro-House',
-		'Dance Hall',
-		'Goa',
-		'Drum & Bass',
-		'Club-House',
-		'Hardcore',
-		'Terror',
-		'Indie',
-		'BritPop',
-		'Negerpunk',
-		'Polsk Punk',
-		'Beat',
-		'Christian Gangsta Rap',
-		'Heavy Metal',
-		'Black Metal',
-		'Crossover',
-		'Contemporary Christian',
-		'Christian Rock',
-		'Merengue',
-		'Salsa',
-		'Thrash Metal',
-		'Anime',
-		'JPop',
-		'Synthpop',
-	);
-
-	@t_bitrate = ([
-		[0, 32, 48, 56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256],
-		[0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160],
-		[0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160]
-	],[
-		[0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448],
-		[0, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384],
-		[0, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320]
-	]);
-
-	@t_sampling_freq = (
-		[11025, 12000,  8000],
-		[undef, undef, undef],	# reserved
-		[22050, 24000, 16000],
-		[44100, 48000, 32000]
-	);
-
-	@frequency_tbl = map { $_ ? eval "${_}e-3" : 0 }
-		map { @$_ } @t_sampling_freq;
-
-	@mp3_info_fields = qw(
-		VERSION
-		LAYER
-		STEREO
-		VBR
-		BITRATE
-		FREQUENCY
-		SIZE
-		SECS
-		MM
-		SS
-		MS
-		TIME
-		COPYRIGHT
-		PADDING
-		MODE
-		FRAMES
-		FRAME_LENGTH
-		VBR_SCALE
-	);
-
-	%v1_tag_fields =
-		(TITLE => 30, ARTIST => 30, ALBUM => 30, COMMENT => 30, YEAR => 4);
-
-	@v1_tag_names = qw(TITLE ARTIST ALBUM YEAR COMMENT TRACKNUM GENRE);
-
-	%v2_to_v1_names = (
-		# v2.2 tags
-		'TT2' => 'TITLE',
-		'TP1' => 'ARTIST',
-		'TAL' => 'ALBUM',
-		'TYE' => 'YEAR',
-		'COM' => 'COMMENT',
-		'TRK' => 'TRACKNUM',
-		'TCO' => 'GENRE', # not clean mapping, but ...
-		# v2.3 tags
-		'TIT2' => 'TITLE',
-		'TPE1' => 'ARTIST',
-		'TALB' => 'ALBUM',
-		'TYER' => 'YEAR',
-		'COMM' => 'COMMENT',
-		'TRCK' => 'TRACKNUM',
-		'TCON' => 'GENRE',
-	);
-
-	%v2_tag_names = (
-		# v2.2 tags
-		'BUF' => 'Recommended buffer size',
-		'CNT' => 'Play counter',
-		'COM' => 'Comments',
-		'CRA' => 'Audio encryption',
-		'CRM' => 'Encrypted meta frame',
-		'ETC' => 'Event timing codes',
-		'EQU' => 'Equalization',
-		'GEO' => 'General encapsulated object',
-		'IPL' => 'Involved people list',
-		'LNK' => 'Linked information',
-		'MCI' => 'Music CD Identifier',
-		'MLL' => 'MPEG location lookup table',
-		'PIC' => 'Attached picture',
-		'POP' => 'Popularimeter',
-		'REV' => 'Reverb',
-		'RVA' => 'Relative volume adjustment',
-		'SLT' => 'Synchronized lyric/text',
-		'STC' => 'Synced tempo codes',
-		'TAL' => 'Album/Movie/Show title',
-		'TBP' => 'BPM (Beats Per Minute)',
-		'TCM' => 'Composer',
-		'TCO' => 'Content type',
-		'TCR' => 'Copyright message',
-		'TDA' => 'Date',
-		'TDY' => 'Playlist delay',
-		'TEN' => 'Encoded by',
-		'TFT' => 'File type',
-		'TIM' => 'Time',
-		'TKE' => 'Initial key',
-		'TLA' => 'Language(s)',
-		'TLE' => 'Length',
-		'TMT' => 'Media type',
-		'TOA' => 'Original artist(s)/performer(s)',
-		'TOF' => 'Original filename',
-		'TOL' => 'Original Lyricist(s)/text writer(s)',
-		'TOR' => 'Original release year',
-		'TOT' => 'Original album/Movie/Show title',
-		'TP1' => 'Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group',
-		'TP2' => 'Band/Orchestra/Accompaniment',
-		'TP3' => 'Conductor/Performer refinement',
-		'TP4' => 'Interpreted, remixed, or otherwise modified by',
-		'TPA' => 'Part of a set',
-		'TPB' => 'Publisher',
-		'TRC' => 'ISRC (International Standard Recording Code)',
-		'TRD' => 'Recording dates',
-		'TRK' => 'Track number/Position in set',
-		'TSI' => 'Size',
-		'TSS' => 'Software/hardware and settings used for encoding',
-		'TT1' => 'Content group description',
-		'TT2' => 'Title/Songname/Content description',
-		'TT3' => 'Subtitle/Description refinement',
-		'TXT' => 'Lyricist/text writer',
-		'TXX' => 'User defined text information frame',
-		'TYE' => 'Year',
-		'UFI' => 'Unique file identifier',
-		'ULT' => 'Unsychronized lyric/text transcription',
-		'WAF' => 'Official audio file webpage',
-		'WAR' => 'Official artist/performer webpage',
-		'WAS' => 'Official audio source webpage',
-		'WCM' => 'Commercial information',
-		'WCP' => 'Copyright/Legal information',
-		'WPB' => 'Publishers official webpage',
-		'WXX' => 'User defined URL link frame',
-
-		# v2.3 tags
-		'AENC' => 'Audio encryption',
-		'APIC' => 'Attached picture',
-		'COMM' => 'Comments',
-		'COMR' => 'Commercial frame',
-		'ENCR' => 'Encryption method registration',
-		'EQUA' => 'Equalization',
-		'ETCO' => 'Event timing codes',
-		'GEOB' => 'General encapsulated object',
-		'GRID' => 'Group identification registration',
-		'IPLS' => 'Involved people list',
-		'LINK' => 'Linked information',
-		'MCDI' => 'Music CD identifier',
-		'MLLT' => 'MPEG location lookup table',
-		'OWNE' => 'Ownership frame',
-		'PCNT' => 'Play counter',
-		'POPM' => 'Popularimeter',
-		'POSS' => 'Position synchronisation frame',
-		'PRIV' => 'Private frame',
-		'RBUF' => 'Recommended buffer size',
-		'RVAD' => 'Relative volume adjustment',
-		'RVRB' => 'Reverb',
-		'SYLT' => 'Synchronized lyric/text',
-		'SYTC' => 'Synchronized tempo codes',
-		'TALB' => 'Album/Movie/Show title',
-		'TBPM' => 'BPM (beats per minute)',
-		'TCOM' => 'Composer',
-		'TCON' => 'Content type',
-		'TCOP' => 'Copyright message',
-		'TDAT' => 'Date',
-		'TDLY' => 'Playlist delay',
-		'TENC' => 'Encoded by',
-		'TEXT' => 'Lyricist/Text writer',
-		'TFLT' => 'File type',
-		'TIME' => 'Time',
-		'TIT1' => 'Content group description',
-		'TIT2' => 'Title/songname/content description',
-		'TIT3' => 'Subtitle/Description refinement',
-		'TKEY' => 'Initial key',
-		'TLAN' => 'Language(s)',
-		'TLEN' => 'Length',
-		'TMED' => 'Media type',
-		'TOAL' => 'Original album/movie/show title',
-		'TOFN' => 'Original filename',
-		'TOLY' => 'Original lyricist(s)/text writer(s)',
-		'TOPE' => 'Original artist(s)/performer(s)',
-		'TORY' => 'Original release year',
-		'TOWN' => 'File owner/licensee',
-		'TPE1' => 'Lead performer(s)/Soloist(s)',
-		'TPE2' => 'Band/orchestra/accompaniment',
-		'TPE3' => 'Conductor/performer refinement',
-		'TPE4' => 'Interpreted, remixed, or otherwise modified by',
-		'TPOS' => 'Part of a set',
-		'TPUB' => 'Publisher',
-		'TRCK' => 'Track number/Position in set',
-		'TRDA' => 'Recording dates',
-		'TRSN' => 'Internet radio station name',
-		'TRSO' => 'Internet radio station owner',
-		'TSIZ' => 'Size',
-		'TSRC' => 'ISRC (international standard recording code)',
-		'TSSE' => 'Software/Hardware and settings used for encoding',
-		'TXXX' => 'User defined text information frame',
-		'TYER' => 'Year',
-		'UFID' => 'Unique file identifier',
-		'USER' => 'Terms of use',
-		'USLT' => 'Unsychronized lyric/text transcription',
-		'WCOM' => 'Commercial information',
-		'WCOP' => 'Copyright/Legal information',
-		'WOAF' => 'Official audio file webpage',
-		'WOAR' => 'Official artist/performer webpage',
-		'WOAS' => 'Official audio source webpage',
-		'WORS' => 'Official internet radio station homepage',
-		'WPAY' => 'Payment',
-		'WPUB' => 'Publishers official webpage',
-		'WXXX' => 'User defined URL link frame',
-
-		# v2.4 additional tags
-		# note that we don't restrict tags from 2.3 or 2.4,
-		'ASPI' => 'Audio seek point index',
-		'EQU2' => 'Equalisation (2)',
-		'RVA2' => 'Relative volume adjustment (2)',
-		'SEEK' => 'Seek frame',
-		'SIGN' => 'Signature frame',
-		'TDEN' => 'Encoding time',
-		'TDOR' => 'Original release time',
-		'TDRC' => 'Recording time',
-		'TDRL' => 'Release time',
-		'TDTG' => 'Tagging time',
-		'TIPL' => 'Involved people list',
-		'TMCL' => 'Musician credits list',
-		'TMOO' => 'Mood',
-		'TPRO' => 'Produced notice',
-		'TSOA' => 'Album sort order',
-		'TSOP' => 'Performer sort order',
-		'TSOT' => 'Title sort order',
-		'TSST' => 'Set subtitle',
-
-		# grrrrrrr
-		'COM ' => 'Broken iTunes comments',
-	);
-}
-
-1;
-
-__END__
-
-=pod
-
-=back
-
-=head1 TROUBLESHOOTING
-
-If you find a bug, please send me a patch (see the project page in L<"SEE ALSO">).
-If you cannot figure out why it does not work for you, please put the MP3 file in
-a place where I can get it (preferably via FTP, or HTTP, or .Mac iDisk) and send me
-mail regarding where I can get the file, with a detailed description of the problem.
-
-If I download the file, after debugging the problem I will not keep the MP3 file
-if it is not legal for me to have it.  Just let me know if it is legal for me to
-keep it or not.
-
-
-=head1 TODO
-
-=over 4
-
-=item ID3v2 Support
-
-Still need to do more for reading tags, such as using Compress::Zlib to decompress
-compressed tags.  But until I see this in use more, I won't bother.  If something
-does not work properly with reading, follow the instructions above for
-troubleshooting.
-
-ID3v2 I<writing> is coming soon.
-
-=item Get data from scalar
-
-Instead of passing a file spec or filehandle, pass the
-data itself.  Would take some work, converting the seeks, etc.
-
-=item Padding bit ?
-
-Do something with padding bit.
-
-=item Test suite
-
-Test suite could use a bit of an overhaul and update.  Patches very welcome.
-
-=over 4
-
-=item *
-
-Revamp getset.t.  Test all the various get_mp3tag args.
-
-=item *
-
-Test Unicode.
-
-=item *
-
-Test OOP API.
-
-=item *
-
-Test error handling, check more for missing files, bad MP3s, etc.
-
-=back
-
-=item Other VBR
-
-Right now, only Xing VBR is supported.
-
-=back
-
-
-=head1 THANKS
-
-Edward Allen E<lt>allenej@c51844-a.spokn1.wa.home.comE<gt>,
-Vittorio Bertola E<lt>v.bertola@vitaminic.comE<gt>,
-Michael Blakeley E<lt>mike@blakeley.comE<gt>,
-Per Bolmstedt E<lt>tomten@kol14.comE<gt>,
-Tony Bowden E<lt>tony@tmtm.comE<gt>,
-Tom Brown E<lt>thecap@usa.netE<gt>,
-Sergio Camarena E<lt>scamarena@users.sourceforge.netE<gt>,
-Chris Dawson E<lt>cdawson@webiphany.comE<gt>,
-Luke Drumm E<lt>lukedrumm@mypad.comE<gt>,
-Kyle Farrell E<lt>kyle@cantametrix.comE<gt>,
-Jeffrey Friedl E<lt>jfriedl@yahoo.comE<gt>,
-brian d foy E<lt>comdog@panix.comE<gt>,
-Ben Gertzfield E<lt>che@debian.orgE<gt>,
-Brian Goodwin E<lt>brian@fuddmain.comE<gt>,
-Todd Hanneken E<lt>thanneken@hds.harvard.eduE<gt>,
-Todd Harris E<lt>harris@cshl.orgE<gt>,
-Woodrow Hill E<lt>asim@mindspring.comE<gt>,
-Kee Hinckley E<lt>nazgul@somewhere.comE<gt>,
-Roman Hodek E<lt>Roman.Hodek@informatik.uni-erlangen.deE<gt>,
-Peter Kovacs E<lt>kovacsp@egr.uri.eduE<gt>,
-Johann Lindvall,
-Peter Marschall E<lt>peter.marschall@mayn.deE<gt>,
-Trond Michelsen E<lt>mike@crusaders.noE<gt>,
-Dave O'Neill E<lt>dave@nexus.carleton.caE<gt>,
-Christoph Oberauer E<lt>christoph.oberauer@sbg.ac.atE<gt>,
-Jake Palmer E<lt>jake.palmer@db.comE<gt>,
-Andrew Phillips E<lt>asp@wasteland.orgE<gt>,
-David Reuteler E<lt>reuteler@visi.comE<gt>,
-John Ruttenberg E<lt>rutt@chezrutt.comE<gt>,
-Matthew Sachs E<lt>matthewg@zevils.comE<gt>,
-E<lt>scfc_de@users.sf.netE<gt>,
-Hermann Schwaerzler E<lt>Hermann.Schwaerzler@uibk.ac.atE<gt>,
-Chris Sidi E<lt>sidi@angband.orgE<gt>,
-Roland Steinbach E<lt>roland@support-system.comE<gt>,
-Stuart E<lt>schneis@users.sourceforge.netE<gt>,
-Jeffery Sumler E<lt>jsumler@mediaone.netE<gt>,
-Predrag Supurovic E<lt>mpgtools@dv.co.yuE<gt>,
-Bogdan Surdu E<lt>tim@go.roE<gt>,
-E<lt>tim@tim-landscheidt.deE<gt>,
-Pass F. B. Travis E<lt>pftravis@bellsouth.netE<gt>,
-Tobias Wagener E<lt>tobias@wagener.nuE<gt>,
-Ronan Waide E<lt>waider@stepstone.ieE<gt>,
-Andy Waite E<lt>andy@mailroute.comE<gt>,
-Ken Williams E<lt>ken@forum.swarthmore.eduE<gt>,
-Meng Weng Wong E<lt>mengwong@pobox.comE<gt>.
-
-
-=head1 AUTHOR AND COPYRIGHT
-
-Chris Nandor E<lt>pudge@pobox.comE<gt>, http://pudge.net/
-
-Copyright (c) 1998-2003 Chris Nandor.  All rights reserved.  This program is
-free software; you can redistribute it and/or modify it under the terms
-of the Artistic License, distributed with Perl.
-
-
-=head1 SEE ALSO
-
-=over 4
-
-=item MP3::Info Project Page
-
-	http://projects.pudge.net/
-
-=item mp3tools
-
-	http://www.zevils.com/linux/mp3tools/
-
-=item mpgtools
-
-	http://www.dv.co.yu/mpgscript/mpgtools.htm
-	http://www.dv.co.yu/mpgscript/mpeghdr.htm
-
-=item mp3tool
-
-	http://www.dtek.chalmers.se/~d2linjo/mp3/mp3tool.html
-
-=item ID3v2
-
-	http://www.id3.org/
-
-=item Xing Variable Bitrate
-
-	http://www.xingtech.com/support/partner_developer/mp3/vbr_sdk/
-
-=item MP3Ext
-
-	http://rupert.informatik.uni-stuttgart.de/~mutschml/MP3ext/
-
-=item Xmms
-
-	http://www.xmms.org/
-
-
-=back
-
-=head1 VERSION
-
-v1.02, Sunday, March 2, 2003
-
-=cut
diff --git a/lib/Mail/SendEasy.pm b/lib/Mail/SendEasy.pm
index c7d5064..5b7cc43 100644
--- a/lib/Mail/SendEasy.pm
+++ b/lib/Mail/SendEasy.pm
@@ -110,7 +110,7 @@ sub send {
   {
     my @from = &_check_emails( $mail{from} ) ; return( undef ) if $ER ;
     if ($#from > 0) { $ER = "More than one From: " . join(" ; ", @from) ; return( undef ) ;}
-    $mail{from} = @from[0] ;
+    $mail{from} = $from[0] ;
 
     my @to = &_check_emails( $mail{to} ) ; return( undef ) if $ER ;
     $mail{to} = \@to ;
@@ -122,12 +122,12 @@ sub send {
 
     if ( defined $mail{reply} ) {
       my @reply = &_check_emails( $mail{reply} ) ; return( undef ) if $ER ;
-      $mail{reply} = @reply[0] ; delete $mail{reply} if $mail{reply} eq '' ;
+      $mail{reply} = $reply[0] ; delete $mail{reply} if $mail{reply} eq '' ;
     }
 
     if ( defined $mail{error} ) {
       my @error = &_check_emails( $mail{error} ) ; return( undef ) if $ER ;
-      $mail{error} = @error[0] ; delete $mail{error} if $mail{error} eq '' ;
+      $mail{error} = $error[0] ; delete $mail{error} if $mail{error} eq '' ;
     }
   }
 
diff --git a/lib/Net/Amazon.pm b/lib/Net/Amazon.pm
deleted file mode 100644
index 4630c11..0000000
--- a/lib/Net/Amazon.pm
+++ /dev/null
@@ -1,1255 +0,0 @@
-#####################################################################
-package Net::Amazon;
-######################################################################
-# Mike Schilli <m@perlmeister.com>, 2003
-######################################################################
-
-use 5.006;
-use strict;
-use warnings;
-
-our $VERSION          = '0.34';
-our @CANNED_RESPONSES = ();
-
-use LWP::UserAgent;
-use HTTP::Request::Common;
-use XML::Simple;
-use Data::Dumper;
-use URI;
-use Log::Log4perl qw(:easy get_logger);
-use Time::HiRes qw(usleep gettimeofday tv_interval);
-
-# Each key represents a search() type, and each value indicates which
-# Net::Amazon::Request:: class to use to handle it.
-use constant SEARCH_TYPE_CLASS_MAP => {
-    artist       => 'Artist',
-    asin         => 'ASIN',
-    blended      => 'Blended',
-    browsenode   => 'BrowseNode',
-    exchange     => 'Exchange',
-    keyword      => 'Keyword',
-    manufacturer => 'Manufacturer',
-    power        => 'Power',
-    seller       => 'Seller',
-    similar      => 'Similar',
-    textstream   => 'TextStream',
-    upc          => 'UPC',
-    wishlist     => 'Wishlist',
-};
-
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    if(! exists $options{token}) {
-        die "Mandatory paramter 'token' not defined";
-    }
-
-    if(! exists $options{affiliate_id}) {
-        $options{affiliate_id} = "webservices-20";
-    }
-
-    my $self = {
-        strict         => 1,
-        response_dump  => 0,
-        rate_limit     => 1.0,  # 1 req/sec
-        max_pages      => 5,
-        ua             => LWP::UserAgent->new(),
-        %options,
-               };
-
-    help_xml_simple_choose_a_parser();
-
-    bless $self, $class;
-}
-
-##################################################
-sub search {
-##################################################
-    my($self, %params) = @_;
-
-    foreach my $key ( keys %params ) {
-        next unless ( my $class = SEARCH_TYPE_CLASS_MAP->{$key} );
-        
-        return $self->_make_request($class, \%params);
-    }
-
-    # FIX?
-    # This seems like it really should be a die() instead...this is
-    # indicative of a programming problem. Generally speaking, it's
-    # best to issue warnings from a module--you can't be sure that the
-    # client has a stderr to begin with, or that he wants errors
-    # spewed to it.
-    warn "No Net::Amazon::Request type could be determined";
-
-    return undef;
-}
-
-##################################################
-sub intl_url {
-##################################################
-    my($self, $url) = @_;
-
-    # Every time Amazon is adding a new country to the web service,
-    # they're rolling a dice on what the new URL is going to be.
-    # This method will try to keep up with their crazy mappings.
-
-    if(! exists $self->{locale}) {
-        return $url;
-    }
-
-    if ($self->{locale} eq "jp") {
-       $url =~ s/\.com/.co.jp/;
-       return $url;
-    }
-
-    if($self->{locale} eq "uk" or
-       $self->{locale} eq "de") {
-        $url =~ s/xml/xml-eu/;
-        return $url;
-    }
-        
-    return $url;
-}
-
-##################################################
-sub request {
-##################################################
-    my($self, $request) = @_;
-
-    my $AMZN_WISHLIST_BUG_ENCOUNTERED = 0;
-
-    my $resp_class = $request->response_class();
-
-    eval "require $resp_class;" or 
-        die "Cannot find '$resp_class'";
-
-    my $res  = $resp_class->new();
-
-    my $url  = URI->new($self->intl_url($request->amzn_xml_url()));
-    my $page = $request->{page};
-    my $ref;
-
-    {
-        my %params = $request->params();
-        $params{page}   = $page;
-        $params{locale} = $self->{locale} if exists $self->{locale};
-
-        $url->query_form(
-            'dev-t' => $self->{token},
-            't'     => $self->{affiliate_id},
-            map { $_, $params{$_} } sort keys %params,
-        );
-
-        my $urlstr = $url->as_string;
-        my $xml = fetch_url($self, $urlstr, $res);
-
-        if(!defined $xml) {
-            return $res;
-        }
-
-        DEBUG(sub { "Received [ " . $xml . "]" });
-
-            # Let the response class parse the XML
-        $ref = $res->xml_parse($xml);
-
-        # DEBUG(sub { Data::Dumper::Dumper($ref) });
-
-        if(! defined $ref) {
-            ERROR("Invalid XML");
-            $res->messages( [ "Invalid XML" ]);
-            $res->status("");
-            return $res;
-        }
-
-        if(exists $ref->{TotalPages}) {
-            INFO("Page $page/$ref->{TotalPages}");
-        }
-
-        if(exists $ref->{TotalResults}) {
-            $res->total_results( $ref->{TotalResults} );
-        }
-
-        if(exists $ref->{ErrorMsg}) {
-
-            if($AMZN_WISHLIST_BUG_ENCOUNTERED &&
-               $ref->{ErrorMsg} =~ /no exact matches/) {
-                DEBUG("End of buggy wishlist detected");
-                last;
-            }
-                
-            if (ref($ref->{ErrorMsg}) eq "ARRAY") {
-              # multiple errors, set arrary ref
-              $res->messages( $ref->{ErrorMsg} );
-            } else {
-              # single error, create array
-              $res->messages( [ $ref->{ErrorMsg} ] );
-            }
-
-            ERROR("Fetch Error: " . $res->message );
-            $res->status("");
-            return $res;
-        }
-
-        my $new_items = $res->xmlref_add($ref);
-        DEBUG("Received valid XML ($new_items items)");
-
-        # Stop if we've fetched max_pages already
-        if($self->{max_pages} <= $page) {
-            DEBUG("Fetched max_pages ($self->{max_pages}) -- stopping");
-            last;
-        }
-
-        # Work around the Amazon bug not setting TotalPages properly
-        # for wishlists
-        if(ref($res) =~ /Wishlist/ and
-           !exists $ref->{TotalPages}  and
-           $new_items == 10
-          ) {
-            $AMZN_WISHLIST_BUG_ENCOUNTERED = 1;
-            DEBUG("Trying to fetch additional wishlist page (AMZN bug)");
-            $page++;
-            redo;
-        }
-
-        if(exists $ref->{TotalPages} and
-           $ref->{TotalPages} > $page) {
-            DEBUG("Page $page of $ref->{TotalPages} fetched - continuing");
-            $page++;
-            redo;
-        }
-
-        # We're gonna fall out of this loop here.
-    }
-
-    $res->status(1);
-    # We have a valid response, so if TotalResults isn't set, 
-    # we most likely have a single response
-    $res->total_results(1) unless defined $res->total_results();
-    return $res;
-}
-
-##################################################
-sub fetch_url {
-##################################################
-    my($self, $url, $res) = @_;
-
-    my $max_retries = 2;
-
-    INFO("Fetching $url");
-
-    if(@CANNED_RESPONSES) {
-        INFO("Serving canned response (testing)");
-        return shift @CANNED_RESPONSES;
-    }
-
-    if(exists $self->{cache}) {
-        my $resp = $self->{cache}->get($url);
-        if(defined $resp) {
-            INFO("Serving from cache");
-            return $resp;
-        }
-
-        INFO("Cache miss");
-    }
-
-    my $ua = $self->{ua};
-    $ua->env_proxy();
-
-    my $resp;
-
-    {
-        # wait up to a second before the next request so
-        # as to not violate Amazon's 1 query per second
-        # rule (or the configured rate_limit).
-        $self->pause() if $self->{strict};
-
-        $resp = $ua->request(GET $url);
-
-        $self->reset_timer() if $self->{strict};
-
-        if($resp->is_error) {
-            # retry on 503 Service Unavailable errors
-            if ($resp->code == 503) {
-                if ($max_retries-- >= 0) {
-                    INFO("Temporary Amazon error 503, retrying");
-                    redo;
-                } else {
-                    INFO("Out of retries, giving up");
-                    $res->status("");
-                    $res->messages( [ "Too many temporary Amazon errors" ] );
-                    return undef;
-                }
-            } else {
-                $res->status("");
-                $res->messages( [ $resp->message ] );
-                return undef;
-            }
-        }
-
-        if($self->{response_dump}) {
-            my $dumpfile = "response-$self->{response_dump}.txt";
-            open FILE, ">$dumpfile" or die "Cannot open $dumpfile";
-            print FILE $resp->content();
-            close FILE;
-            $self->{response_dump}++;
-        }
-
-        if($resp->content =~ /<ErrorMsg>/ &&
-           $resp->content =~ /Please retry/i) {
-            if($max_retries-- >= 0) {
-                INFO("Temporary Amazon error, retrying");
-                redo;
-            } else {
-                INFO("Out of retries, giving up");
-                $res->status("");
-                $res->messages( [ "Too many temporary Amazon errors" ] );
-                return undef;
-            }
-        }
-    }
-
-    if(exists $self->{cache}) {
-        $self->{cache}->set($url, $resp->content());
-    }
-
-    return $resp->content();
-}
-
-##################################################
-# Poor man's Class::Struct
-##################################################
-sub make_accessor {
-##################################################
-    my($package, $name) = @_;
-
-    no strict qw(refs);
-
-    my $code = <<EOT;
-        *{"$package\\::$name"} = sub {
-            my(\$self, \$value) = \@_;
-
-            if(defined \$value) {
-                \$self->{$name} = \$value;
-            }
-            if(exists \$self->{$name}) {
-                return (\$self->{$name});
-            } else {
-                return "";
-            }
-        }
-EOT
-    if(! defined *{"$package\::$name"}) {
-        eval $code or die "$@";
-    }
-}
-
-##################################################
-# Make accessors for arrays
-##################################################
-sub make_array_accessor {
-##################################################
-    my($package, $name) = @_;
-
-    no strict qw(refs);
-
-    my $code = <<EOT;
-        *{"$package\\::$name"} = sub {
-            my(\$self, \$nameref) = \@_;
-            if(defined \$nameref) {
-                if(ref \$nameref eq "ARRAY") {
-                    \$self->{$name} = \$nameref;
-                } else {
-                    \$self->{$name} = [\$nameref];
-                }
-            }
-               # Return a list
-            if(exists \$self->{$name} and
-               ref \$self->{$name} eq "ARRAY") {
-                return \@{\$self->{$name}};
-            }
-
-            return undef;
-        }
-EOT
-
-    if(! defined *{"$package\::$name"}) {
-        eval $code or die "$@";
-    }
-}
-
-##################################################
-sub artist {
-##################################################
-    my($self, $nameref) = @_;
-
-    # Only return the first artist
-    return ($self->artists($nameref))[0];
-}
-
-
-##################################################
-sub xmlref_add {
-##################################################
-    my($self, $xmlref) = @_;
-
-    my $nof_items_added = 0;
-
-    # Push a nested hash structure, retrieved via XMLSimple, onto the
-    # object's internal 'xmlref' entry, which holds a ref to an array, 
-    # whichs elements are refs to hashes holding an item's attributes
-    # (like OurPrice etc.)
-
-    #DEBUG("xmlref_add ", Data::Dumper::Dumper($xmlref));
-
-    unless(ref($self->{xmlref}) eq "HASH" &&
-           ref($self->{xmlref}->{Details}) eq "ARRAY") {
-        $self->{xmlref}->{Details} = [];
-    }
-
-    if(ref($xmlref->{Details}) eq "ARRAY") {
-        # Is it an array of items?
-        push @{$self->{xmlref}->{Details}}, @{$xmlref->{Details}};
-        $nof_items_added = scalar @{$xmlref->{Details}};
-    } else {
-        # It is a single item
-        push @{$self->{xmlref}->{Details}}, $xmlref->{Details};
-        $nof_items_added = 1;
-    }
-
-    #DEBUG("xmlref_add (after):", Data::Dumper::Dumper($self));
-    return $nof_items_added;
-}
-
-##################################################
-sub help_xml_simple_choose_a_parser {
-##################################################
-    
-    eval "require XML::Parser";
-    unless($@) {
-        $XML::Simple::PREFERRED_PARSER = "XML::Parser";
-        return;
-    }
-
-    eval "require XML::SAX::PurePerl";
-    unless($@) {
-        $XML::Simple::PREFERRED_PARSER = "XML::SAX::PurePerl";
-        return;
-    }
-}
-
-##################################################
-# This timer makes sure we don't query Amazon more
-# than once a second.
-##################################################
-sub reset_timer {
-##################################################
-
-    my $self = shift;
-    $self->{t0} = [gettimeofday];
-}
-
-##################################################
-# Pause for up to a second if necessary.
-##################################################
-sub pause {
-##################################################
-
-    my $self = shift;
-    return unless ($self->{t0});
-
-    my $t1 = [gettimeofday];
-    my $dur = (1.0/$self->{rate_limit} - 
-               tv_interval($self->{t0}, $t1)) * 1000000;
-    if($dur > 0) {
-            # Use a pseudo subclass for the logger, since the app
-            # might not want to log that as 'ERROR'. Log4perl's
-            # inheritance mechanism makes sure it does the right
-            # thing for the current class.
-        my $logger = get_logger(__PACKAGE__ . "::RateLimit");
-        $logger->error("Ratelimiting: Sleeping $dur microseconds"); 
-        usleep($dur);
-    }
-}
-
-##
-## 'PRIVATE' METHODS
-##
-
-# $self->_make_request( TYPE, PARAMS )
-#
-# Takes a TYPE that corresponds to a Net::Amazon::Request
-# class, require()s that class, instantiates it, and returns
-# the result of that instance's request() method.
-#
-sub _make_request {
-    my ($self, $type, $params) = @_;
-
-    my $class = "Net::Amazon::Request::$type";
-
-    eval "require $class";
-
-    my $req = $class->new(%{$params});
-    
-    return $self->request($req);
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon - Framework for accessing amazon.com via SOAP and XML/HTTP
-
-=head1 SYNOPSIS
-
-  use Net::Amazon;
-
-  my $ua = Net::Amazon->new(token => 'YOUR_AMZN_TOKEN');
-
-    # Get a request object
-  my $response = $ua->search(asin => '0201360683');
-
-  if($response->is_success()) {
-      print $response->as_string(), "\n";
-  } else {
-      print "Error: ", $response->message(), "\n";
-  }
-
-=head1 ABSTRACT
-
-  Net::Amazon provides an object-oriented interface to amazon.com's
-  SOAP and XML/HTTP interfaces. This way it's possible to create applications
-  using Amazon's vast amount of data via a functional interface, without
-  having to worry about the underlying communication mechanism.
-
-=head1 DESCRIPTION
-
-C<Net::Amazon> works very much like C<LWP>: First you define a useragent
-like
-
-  my $ua = Net::Amazon->new(
-      token     => 'YOUR_AMZN_TOKEN',
-      max_pages => 3,
-  );
-
-which you pass your personal amazon developer's token (can be obtained
-from L<http://amazon.com/soap>) and (optionally) the maximum number of 
-result pages the agent is going to request from Amazon in case all
-results don't fit on a single page (typically holding 20 items).  Note that
-each new page requires a minimum delay of 1 second to comply with Amazon's
-one-query-per-second policy.
-
-According to the different search methods on Amazon, there's a bunch
-of different request types in C<Net::Amazon>. The user agent's 
-convenience method C<search()> triggers different request objects, 
-depending on which parameters you pass to it:
-
-=over 4
-
-=item C<< $ua->search(asin => "0201360683") >>
-
-The C<asin> parameter has Net::Amazon search for an item with the 
-specified ASIN. If the specified value is an arrayref instead of a single
-scalar, like in
-
-    $ua->search(asin => ["0201360683", "0596005083"]) 
-
-then a search for multiple ASINs is performed, returning a list of 
-results.
-
-=item C<< $ua->search(artist => "Rolling Stones") >>
-
-The C<artist> parameter has the user agent search for items created by
-the specified artist. Can return many results.
-
-=item C<< $ua->search(browsenode=>"4025", mode=>"books" [, keywords=>"perl"]) >>
-
-Returns a list of items by category ID (node). For example node "4025"
-is the CGI books category.  You can add a keywords parameter to filter 
-the results by that keyword.
-
-=item C<< $ua->search(exchange => 'Y04Y3424291Y2398445') >>
-
-Returns an item offered by a third-party seller. The item is referenced
-by the so-called I<exchange ID>.
-
-=item C<< $ua->search(keyword => "perl xml", mode => "books") >>
-
-Search by keyword, mandatory parameters C<keyword> and C<mode>.
-Can return many results.
-
-=item C<< $ua->search(wishlist => "1XL5DWOUFMFVJ") >>
-
-Search for all items in a specified wishlist.
-Can return many results.
-
-=item C<< $ua->search(upc => "075596278324", mode => "music") >>
-
-Music search by UPC (product barcode), mandatory parameter C<upc>.
-C<mode> has to be set to C<music>. Returns at most one result.
-
-=item C<< $ua->search(similar => "0201360683") >>
-
-Search for all items similar to the one represented by the ASIN provided.
-Can return many results.
-
-=item C<< $ua->search(power => "subject: perl and author: schwartz", mode => "books") >>
-
-Initiate a power search for all books matching the power query.
-Can return many results. See L<Net::Amazon::Request::Power> for details.
-
-=item C<< $ua->search(manufacturer => "o'reilly", mode => "books") >>
-
-Initiate a search for all items made by a given manufacturrer.
-Can return many results. See L<Net::Amazon::Request::Manufacturer> 
-for details.
-
-=item C<< $ua->search(blended => "Perl") >>
-
-Initiate a search for items in all categories.
-
-=item C<< $ua->search(seller => "A2GXAGU54VOP7") >>
-
-Start a search on items sold by a specific third-party seller, referenced
-by its ID (not seller name).
-
-=item C<< $ua->search(textstream => "Blah blah Rolling Stones blah blah") >>
-
-Find items related to keywords within a text stream.
-
-=back
-
-The user agent's C<search> method returns a response object, which can be 
-checked for success or failure:
-
-  if($resp->is_success()) {
-      print $resp->as_string();
-  } else {
-      print "Error: ", $resp->message(), "\n";
-  }
-
-In case the request for an item search 
-succeeds, the response contains one or more
-Amazon 'properties', as it calls the products found.
-All matches can be retrieved from the Response 
-object using it's C<properties()> method.
-
-In case the request fails, the response contains one or more
-error messages. The response object's C<message()> method will
-return it (or them) as a single string, while C<messages()> (notice
-the plural) will
-return a reference to an array of message strings.
-
-Response objects always have the methods 
-C<is_success()>,
-C<is_error()>,
-C<message()>,
-C<total_results()>,
-C<as_string()> and
-C<properties()> available.
-
-C<total_results()> returns the total number of results the search
-yielded.
-C<properties()> returns one or more C<Net::Amazon::Property> objects of type
-C<Net::Amazon::Property> (or one of its subclasses like
-C<Net::Amazon::Property::Book>, C<Net::Amazon::Property::Music>
-or Net::Amazon::Property::DVD), each
-of which features accessors named after the attributes of the product found
-in Amazon's database:
-
-    for ($resp->properties) {
-       print $_->Asin(), " ",
-             $_->OurPrice(), "\n";
-    }
-
-In scalar context, C<properties()> just returns the I<first> 
-C<Net::Amazon::Property> object found.
-Commonly available accessors to C<Net::Amazon::Property> objects are
-C<OurPrice()>,
-C<ImageUrlLarge()>,
-C<ImageUrlMedium()>,
-C<ImageUrlSmall()>,
-C<ReleaseDate()>,
-C<Catalog()>,
-C<Asin()>,
-C<url()>,
-C<Manufacturer()>,
-C<UsedPrice()>,
-C<ListPrice()>,
-C<ProductName()>,
-C<Availability()>,
-C<SalesRank()>,
-C<CollectiblePrice()>,
-C<CollectibleCount()>,
-C<NumberOfOfferings()>,
-C<UsedCount()>,
-C<ThirdPartyNewPrice()>,
-C<ThirdPartyNewCount()>,
-C<similar_asins()>.
-For details, check L<Net::Amazon::Property>.
-
-Also, the specialized classes C<Net::Amazon::Property::Book> and
-C<Net::Amazon::Property::Music> feature convenience methods like
-C<authors()> (returning the list of authors of a book) or 
-C<album()> for CDs, returning the album title.
-
-Customer reviews:
-Every property features a C<review_set()> method which returns a
-C<Net::Amazon::Attribute::ReviewSet> object, which in turn offers
-a list of C<Net::Amazon::Attribute::Review> objects. Check the respective
-man pages for details on what's available.
-
-=head2 Requests behind the scenes
-
-C<Net::Amazon>'s C<search()> method is just a convenient way to 
-create different kinds of request objects behind the scenes and
-trigger them to send requests to Amazon.
-
-Depending on the parameters fed to the C<search> method, C<Net::Amazon> will
-determine the kind of search requested and create one of the following
-request objects:
-
-=over 4
-
-=item Net::Amazon::Request::ASIN
-
-Search by ASIN, mandatory parameter C<asin>. 
-Returns at most one result.
-
-=item Net::Amazon::Request::Artist
-
-Music search by Artist, mandatory parameter C<artist>.
-Can return many results.
-
-=item Net::Amazon::Request::BrowseNode
-
-Returns category (node) listing. Mandatory parameters C<browsenode>
-(must be numeric) and C<mode>. Can return many results.
-
-=item Net::Amazon::Request::Keyword
-
-Keyword search, mandatory parameters C<keyword> and C<mode>.
-Can return many results.
-
-=item Net::Amazon::Request::UPC
-
-Music search by UPC (product barcode), mandatory parameter C<upc>.
-C<mode> has to be set to C<music>. Returns at most one result.
-
-=item Net::Amazon::Request::Blended
-
-'Blended' search on a keyword, resulting in matches across the board.
-No 'mode' parameter is allowed. According to Amazon's developer's kit, 
-this will result in up to three matches per category and can yield
-a total of 45 matches.
-
-=item Net::Amazon::Request::Power
-
-Understands power search strings. See L<Net::Amazon::Request::Power>
-for details. Mandatory parameter C<power>.
-
-=item Net::Amazon::Request::Manufacturer
-
-Searches for all items made by a given manufacturer. Mandatory parameter
-C<manufacturer>.
-
-=item Net::Amazon::Request::Similar
-
-Finds items similar to a given one.
-
-=item Net::Amazon::Request::Wishlist
-
-Find item on someone's wish list.
-
-=item Net::Amazon::Request::Seller
-
-Searches for a third-party seller on Amazon by seller ID. This search
-is different than the previous ones, since it doesn't return Amazon
-items, but a single seller record. Don't use the C<properties()> method
-on the response, use C<result()> instead, which returns a 
-L<Net::Amazon::Result::Seller> object. Check the manpage for details.
-
-=item Net::Amazon::Request::Exchange
-
-Searches for items offered by third-party sellers. Items are referenced
-by their so-called I<Exchange ID>.
-Similar to L<Net::Amazon::Request::Seller>,
-this request doesn't return a list of Amazon properties, so please use
-C<result()> instead, which will return a I<single>
-L<Net::Amazon::Result::Seller::Listing> item.
-Check the manpage for details on what attributes are available there.
-
-=back
-
-Check the respective man pages for details on these request objects.
-Request objects are typically created like this (with a Keyword query
-as an example):
-
-    my $req = Net::Amazon::Request::Keyword->new(
-        keyword   => 'perl',
-	mode      => 'books',
-    );
-
-and are handed over to the user agent like that:
-
-    # Response is of type Net::Amazon::Response::ASIN
-  my $resp = $ua->request($req);
-
-The convenient C<search()> method just does these two steps in one.
-
-=head2 METHODS
-
-=over 4
-
-=item $ua = Net::Amazon->new(token => $token, ...)
-
-Create a new Net::Amazon useragent. C<$token> is the value of 
-the mandatory Amazon developer's token, which can be obtained from
-L<http://amazon.com/soap>. 
-
-Additional optional parameters:
-
-=over 4
-
-=item C<< max_pages => $max_pages >>
-
-Sets how many 
-result pages the module is supposed to fetch back from Amazon, which
-only sends back 10 results per page.  
-Since each page requires a new query to Amazon, at most one query 
-per second will be made in C<strict> mode to comply with Amazon's terms 
-of service. This will impact performance if you perform a search 
-returning many pages of results.
-
-=item C<< affiliate_id => $affiliate_id >>
-
-your Amazon affiliate ID, if you have one. It defaults to 
-C<webservices-20> which is currently (as of 06/2003) 
-required by Amazon.
-
-=item C<< strict => 1 >>
-
-Makes sure that C<Net::Amazon> complies with Amazon's terms of service
-by limiting the number of outgoing requests to 1 per second. Defaults
-to C<1>, enabling rate limiting as defined via C<rate_limit>.
-
-=item C<< rate_limit => $reqs_per_sec >>
-
-Sets the rate limit to C<$reqs_per_sec> requests per second if 
-rate limiting has been enabled with C<strict> (see above).
-Defaults to C<1>, limiting the number of outgoing requests to 
-1 per second.
-
-=item C<< $resp = $ua->request($request) >>
-
-Sends a request to the Amazon web service. C<$request> is of a 
-C<Net::Amazon::Request::*> type and C<$response> will be of the 
-corresponding C<Net::Amazon::Response::*> type.
-
-=back
-
-=head2 Accessing foreign Amazon Catalogs
-
-As of this writing (07/2003), Amazon also offers its web service for
-the UK, Germany, and Japan. Just pass in
-
-    locale => 'uk'
-    locale => 'de'
-    locale => 'jp'
-
-respectively to C<Net::Amazon>'s constructor C<new()> and instead of returning
-results sent by the US mothership, it will query the particular country's
-catalog and show prices in (gack!) local currencies.
-
-=head2 EXAMPLE
-
-Here's a full-fledged example doing a artist search:
-
-    use Net::Amazon;
-    use Net::Amazon::Request::Artist;
-    use Data::Dumper;
-
-    die "usage: $0 artist\n(use Zwan as an example)\n"
-        unless defined $ARGV[0];
-
-    my $ua = Net::Amazon->new(
-        token       => 'YOUR_AMZN_TOKEN',
-    );
-
-    my $req = Net::Amazon::Request::Artist->new(
-        artist  => $ARGV[0],
-    );
-
-       # Response is of type Net::Amazon::Artist::Response
-    my $resp = $ua->request($req);
-
-    if($resp->is_success()) {
-        print $resp->as_string, "\n";
-    } else {
-        print $resp->message(), "\n";
-    }
-
-And here's one displaying someone's wishlist:
-
-    use Net::Amazon;
-    use Net::Amazon::Request::Wishlist;
-
-    die "usage: $0 wishlist_id\n" .
-        "(use 1XL5DWOUFMFVJ as an example)\n" unless $ARGV[0];
-
-    my $ua = Net::Amazon->new(
-        token       => 'YOUR_AMZN_TOKEN',
-    );
-
-    my $req = Net::Amazon::Request::Wishlist->new(
-        id  => $ARGV[0]
-    );
-
-       # Response is of type Net::Amazon::ASIN::Response
-    my $resp = $ua->request($req);
-
-    if($resp->is_success()) {
-        print $resp->as_string, "\n";
-    } else {
-        print $resp->message(), "\n";
-    }
-
-=head1 CACHING
-
-Responses returned by Amazon's web service can be cached locally.
-C<Net::Amazon>'s C<new> method accepts a reference to a C<Cache>
-object. C<Cache> (or one of its companions like C<Cache::Memory>,
-C<Cache::File>, etc.) can be downloaded from CPAN, please check their
-documentation for details. In fact, any other type of cache
-implementation will do as well, see the requirements below.
-
-Here's an example utilizing a file cache which causes C<Net::Amazon> to
-cache responses for 30 minutes:
-
-    use Cache::File;
-
-    my $cache = Cache::File->new( 
-        cache_root        => '/tmp/mycache',
-        default_expires   => '30 min',
-    );
-
-    my $ua = Net::Amazon->new(
-        token       => 'YOUR_AMZN_TOKEN',
-        cache       => $cache,
-    );
-
-C<Net::Amazon> uses I<positive> caching only, errors won't be cached. 
-Erroneous requests will be sent to Amazon every time. Positive cache 
-entries are keyed by the full URL used internally by requests submitted 
-to Amazon.
-
-Caching isn't limited to the C<Cache> class. Any cache object which
-adheres to the following interface can be used:
-
-        # Set a cache value
-    $cache->set($key, $value);
-
-        # Return a cached value, 'undef' if it doesn't exist
-    $cache->get($key);
-
-=head1 PROXY SETTINGS
-
-C<Net::Amazon> uses C<LWP::UserAgent> under the hood to send
-web requests to Amazon's web site. If you're in an environment where
-all Web traffic goes through a proxy, there's two ways to configure that.
-
-First, C<Net::Amazon> picks up proxy settings from environment variables:
-
-    export http_proxy=http://proxy.my.place:8080
-
-in the surrounding shell or setting
-
-    $ENV{http_proxy} = "http://proxy.my.place:8080";
-
-in your Perl script
-will route all requests through the specified proxy.
-
-Secondly, you can
-pass a user agent instance to Net::Amazon's constructor:
-
-    use Net::Amazon;
-    use LWP::UserAgent;
-
-    my $ua = LWP::UserAgent->new();
-    my $na = Net::Amazon->new(ua => $ua, token => 'YOUR_AMZN_TOKEN');
-    # ...
-
-This way, you can configure C<$ua> up front before Net::Amazon will use it.
-
-=head1 DEBUGGING
-
-If something's going wrong and you want more verbosity, just bump up
-C<Net::Amazon>'s logging level. C<Net::Amazon> comes with C<Log::Log4perl>
-statements embedded, which are disabled by default. However, if you initialize 
-C<Log::Log4perl>, e.g. like
-
-    use Net::Amazon;
-    use Log::Log4perl qw(:easy);
-
-    Log::Log4perl->easy_init($DEBUG);
-    my Net::Amazon->new();
-    # ...
-
-you'll see what's going on behind the scenes, what URLs the module 
-is requesting from Amazon and so forth. Log::Log4perl allows all kinds
-of fancy stuff, like writing to a file or enabling verbosity in certain
-parts only -- check http://log4perl.sourceforge.net for details.
-
-=head1 LIVE TESTING
-
-Results returned by Amazon can be incomplete or simply wrong at times,
-due to their "best effort" design of the service. This is why the test
-suite that comes with this module has been changed to perform its test
-cases against canned data. If you want to perform the tests against
-the live Amazon servers instead, just set the environment variable
-
-    NET_AMAZON_LIVE_TESTS=1
-
-=head1 WHY ISN'T THERE SUPPORT FOR METHOD XYZ?
-
-Because nobody wrote it yet. If Net::Amazon doesn't yet support a method
-advertised on Amazon's web service, you could help us out. Net::Amazon
-has been designed to be expanded over time, usually it only takes a couple
-of lines to support a new method, the rest is done via inheritance within
-Net::Amazon.
-
-Here's the basic plot:
-
-=over 4
-
-=item *
-
-Get Net::Amazon from CVS. Use
-
-        # (Just hit enter when prompted for a password)
-    cvs -d:pserver:anonymous@cvs.net-amazon.sourceforge.net:/cvsroot/net-amazon login
-    cvs -z3 -d:pserver:anonymous@cvs.net-amazon.sourceforge.net:/cvsroot/net-amazon co Net-Amazon
-
-If this doesn't work, just use the latest distribution from 
-net-amazon.sourceforge.net.
-
-=item *
-
-Write a new Net::Amazon::Request::XYZ package, start with this template
-
-    ######################################
-    package Net::Amazon::Request::XYZ;
-    ######################################
-    use base qw(Net::Amazon::Request);
-
-    ######################################
-    sub new {
-    ######################################
-        my($class, %options) = @_;
-
-        if(!exists $options{XYZ_option}) {
-            die "Mandatory parameter 'XYZ_option' not defined";
-        }
-    
-        my $self = $class->SUPER::new(%options);
-    
-        bless $self, $class;   # reconsecrate
-    }
-
-and add documentation. Then, create a new Net::Amazon::Response::XYZ module:
-
-    ##############################
-    package Net::Amazon::Response;
-    ##############################
-    use base qw(Net::Amazon::Response);
-
-    use Net::Amazon::Property;
-
-    ##############################
-    sub new {
-    ##############################
-        my($class, %options) = @_;
-    
-        my $self = $class->SUPER::new(%options);
-    
-        bless $self, $class;   # reconsecrate
-    }
-
-and also add documentation to it. Then, add the line
-
-    use Net::Amazon::Request::XYZ;
-
-to Net/Amazon.pm.
-
-=back
-
-And that's it! Again, don't forget the I<add documentation> part. Modules
-without documentation are of no use to anybody but yourself. 
-
-Check out the different Net::Amazon::Request::*
-and Net::Amazon::Response modules in the distribution if you need to adapt
-your new module to fulfil any special needs, like a different Amazon URL
-or a different way to handle the as_string() method. Also, post
-and problems you might encounter to the mailing list, we're gonna help you
-out.
-
-If possible, provide a test case for your extension. When finished, send 
-a patch to the mailing list at 
-
-   net-amazon-devel@lists.sourceforge.net
-
-and if it works, I'll accept it and will work it into the main distribution.
-Your name will show up in the contributor's list below (unless you tell
-me otherwise).
-
-=head2 SAMPLE SCRIPTS
-
-There's a number of useful scripts in the distribution's eg/ directory.
-Take C<power> for example, written by Martin Streicher 
-E<lt>martin.streicher@apress.comE<gt>: I lets you perform 
-a I<power search> using Amazon's query language. To search for all books 
-written by Randal Schwartz about Perl, call this from the command line:
-
-    power 'author: schwartz subject: perl'
-
-Note that you need to quote the query string to pass it as one argument
-to C<power>. If a power search returns more results than you want to
-process at a time, just limit the number of pages, telling C<power>
-which page to start at (C<-s>) and which one to finish with (C<-f>).
-Here's a search for all books on the subject C<computer>, limited
-to the first 10 pages:
-
-    power -s 1 -f 10 'subject: computer'
-
-Check out the script C<power> in eg/ for more options.
-
-=head2 HOW TO SEND ME PATCHES
-
-If you want me to include your modification or enhancement 
-in the distribution of Net::Amazon, please do the following:
-
-=over 4
-
-=item *
-
-Work off the latest CVS version. Here's the steps to get it:
-
-    CVSROOT=:pserver:anonymous@cvs.net-amazon.sourceforge.net:/cvsroot/net-amazon
-    export CVSROOT
-    cvs login (just hit Enter)
-    cvs co Net-Amazon
-
-This will create a new C<Net-Amazon> directory with the latest 
-development version of C<Net::Amazon> on your local machine.
-
-=item *
-
-Apply your changes to this development tree.
-
-=item *
-
-Run a diff between the tree and your changes it in this way:
-
-    cd Net-Amazon
-    cvs diff -Nau >patch_to_mike.txt
-
-=item *
-
-Email me C<patch_to_mike.txt>. If your patch works (and you've included
-test cases and documentation), I'll apply it on the spot.
-
-=back
-
-=head1 INSTALLATION
-
-C<Net::Amazon> depends on Log::Log4perl, which can be pulled from CPAN by
-simply saying
-
-    perl -MCPAN -eshell 'install Log::Log4perl'
-
-Also, it needs LWP::UserAgent and XML::Simple 2.x, which can be obtained 
-in a similar way.
-
-Once all dependencies have been resolved, C<Net::Amazon> installs with
-the typical sequence
-
-    perl Makefile.PL
-    make
-    make test
-    make install
-
-Make sure you're connected to the Internet while running C<make test>
-because it will actually contact amazon.com and run a couple of live tests.
-
-The module's distribution tarball and documentation are available at
-
-    http://perlmeister.com/devel/#amzn 
-
-and on CPAN.
-
-=head1 SEE ALSO
-
-The following modules play well within the C<Net::Amazon> framework:
-
-=over 4
-
-=item C<Net::Amazon::RemoteCart>
-
-by David Emery E<lt>dave@skiddlydee.comE<gt> provides a complete API for
-creating Amazon shopping carts on a local site, managing them and finally 
-submitting them to Amazon for checkout. It is available on CPAN.
-
-=back
-
-=head1 CONTACT
-
-The C<Net::Amazon> project's home page is hosted on 
-
-    http://net-amazon.sourceforge.net
-
-where you can find documentation, news and the latest development and
-stable releases for download. If you have questions about how to
-use C<Net::Amazon>, want to report a bug or just participate in its
-development, please send a message to the mailing 
-list net-amazon-devel@lists.sourceforge.net
-
-=head1 AUTHOR
-
-Mike Schilli, E<lt>na@perlmeister.comE<gt> (Please contact me via the mailing list: net-amazon-devel@lists.sourceforge.net )
-
-Contributors (thanks y'all!):
-
-    Andy Grundman <andy@hybridized.org>
-    Barnaby Claydon <bclaydon@perseus.com>
-    Batara Kesuma <bkesuma@gaijinweb.com>
-    Bill Fitzpatrick
-    Brian <brianbrian@gmail.com>
-    Brian Hirt <bhirt@mobygames.com>
-    Dan Kreft <dan@kreft.net>
-    Dan Sully <daniel@electricrain.com>
-    Jackie Hamilton <kira@cgi101.com>
-    Konstantin Gredeskoul <kig@get.topica.com>
-    Lance Cleveland <lancec@proactivewm.com>
-    Martha Greenberg <marthag@mit.edu>
-    Martin Streicher <martin.streicher@apress.com>
-    Mike Evron <evronm@dtcinc.net>
-    Padraic Renaghan <padraic@renaghan.com>
-    rayg <rayg@varchars.com>
-    Robert Graff <rgraff@workingdemo.com>
-    Robert Rothenberg <wlkngowl@i-2000.com>
-    Steve Rushe <steve@deeden.co.uk>
-    Tatsuhiko Miyagawa <miyagawa@livedoor.jp>
-    Tony Bowden <tony@kasei.com>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2003, 2004 by Mike Schilli E<lt>na@perlmeister.comE<gt>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
diff --git a/lib/Net/Amazon/Attribute/Review.pm b/lib/Net/Amazon/Attribute/Review.pm
deleted file mode 100644
index 5a5d094..0000000
--- a/lib/Net/Amazon/Attribute/Review.pm
+++ /dev/null
@@ -1,104 +0,0 @@
-######################################################################
-package Net::Amazon::Attribute::Review;
-######################################################################
-use warnings;
-use strict;
-use Log::Log4perl qw(:easy);
-use base qw(Net::Amazon);
-
-__PACKAGE__->make_accessor($_) for qw(rating summary comment);
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    my $self = {
-        rating  => "",
-        summary => "",
-        comment => "",
-        %options,
-    };
-
-    bless $self, $class;
-}
-
-##################################################
-sub init_via_xmlref {
-##################################################
-    my($self, $xmlref) = @_;
-
-    for(qw(Rating Summary Comment)) {
-        my $method = lc($_);
-        if($xmlref->{$_}) {
-            $self->$method($xmlref->{$_});
-        } else {
-            #LOGWARN "No '$_'";
-            return undef;
-        }
-    }
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Attribute::Review - Customer Review Class
-
-=head1 SYNOPSIS
-
-    use Net::Amazon::Attribute::Review;
-    my $rev = Net::Amazon::Attribute::Review->new(
-                 'rating'  => $rating,
-                 'summary' => $summary,
-                 'comment' => $comment,
-    );
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Attribute::Review> holds customer reviews.
-
-=head2 METHODS
-
-=over 4
-
-=item rating()
-
-Accessor for the numeric value of the rating.
-
-=item summary()
-
-Accessor for the string value of the summary.
-
-=item comment()
-
-Accessor for the string value of the customer comment.
-
-=back
-
-=head1 SEE ALSO
-
-=head1 AUTHOR
-
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2003 by Mike Schilli E<lt>m@perlmeister.comE<gt>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
-
-__END__
-      <Reviews>
-         <AvgCustomerRating>4.33</AvgCustomerRating>
-         <TotalCustomerReviews>6</TotalCustomerReviews>
-         <CustomerReview>
-            <Rating>4</Rating>
-            <Summary>Good introduction to Perl, and great reference</Summary>
-            <Comment>From its corny title you might expect another one of those 
-
diff --git a/lib/Net/Amazon/Attribute/ReviewSet.pm b/lib/Net/Amazon/Attribute/ReviewSet.pm
deleted file mode 100644
index 29a34e6..0000000
--- a/lib/Net/Amazon/Attribute/ReviewSet.pm
+++ /dev/null
@@ -1,137 +0,0 @@
-######################################################################
-package Net::Amazon::Attribute::ReviewSet;
-######################################################################
-use warnings;
-use strict;
-use Log::Log4perl qw(:easy);
-use Net::Amazon::Attribute::Review;
-use base qw(Net::Amazon);
-
-__PACKAGE__->make_accessor($_) for qw(average_customer_rating total_reviews);
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    my $self = {
-        reviews => [],  # list of reviews
-    };
-
-    bless $self, $class;
-}
-
-###########################################
-sub add_review {
-###########################################
-    my($self, $review) = @_;
-
-    if(ref $review ne "Net::Amazon::Attribute::Review") {
-        warn "add_review called with type ", ref $review;
-        return undef;
-    }
-
-    push @{$self->{reviews}}, $review;
-}
-
-###########################################
-sub reviews {
-###########################################
-    my($self) = @_;
-
-    return @{$self->{reviews}};
-}
-
-##################################################
-sub init_via_xmlref {
-##################################################
-    my($self, $xmlref) = @_;
-
-    my @pairs = qw(AvgCustomerRating    average_customer_rating
-                   TotalCustomerReviews total_reviews);
-
-    while(my($field, $method) = splice @pairs, 0, 2) {
-        
-        if(defined $xmlref->{$field}) {
-            DEBUG "Setting $field via $method to $xmlref->{$field}";
-            $self->$method($xmlref->{$field});
-        } else {
-            LOGWARN "No '$field'";
-            return undef;
-        }
-    }
-
-    if(ref $xmlref->{CustomerReview} ne "ARRAY") {
-        $xmlref->{CustomerReview} = [$xmlref->{CustomerReview}];
-    }
-
-    for my $review_xmlref (@{$xmlref->{CustomerReview}}) {
-        my $review = Net::Amazon::Attribute::Review->new();
-        $review->init_via_xmlref($review_xmlref);
-        DEBUG "Adding review ", $review->summary();
-        $self->add_review($review);
-    }
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Attribute::ReviewSet - A set of customer reviews
-
-=head1 SYNOPSIS
-
-    use Net::Amazon::Attribute::ReviewSet;
-    my $rev = Net::Amazon::Attribute::Review->new(
-        average_customer_rating => $avg,
-        total_reviews  => $total,
-        );
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Attribute::ReviewSet> holds a list of customer
-reviews, each of type C<Net::Amazon::Attribute::Review>.
-
-=head2 METHODS
-
-=over 4
-
-=item C<< $self->reviews() >>
-
-Returns a list of C<Net::Amazon::Attribute::Review> objects.
-
-=item C<< $self->average_customer_rating() >>
-
-Accessor for the average customer rating, a numeric value.
-
-=item C<< $self->total_reviews() >>
-
-Accessor for the total number of reviews. Please note that this
-might not be equal to the number of reviews held in the list, since
-there might be less customer reviews than total reviews (reviews
-can also be non-customer-reviews, but they're not available by
-the web service as of Aug 2003).
-
-=item C<< $self->add_review($rev) >>
-
-Add a C<Net::Amazon::Attribute::Review> object to the list.
-(Used internally only).
-
-=back
-
-=head1 SEE ALSO
-
-=head1 AUTHOR
-
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2003 by Mike Schilli E<lt>m@perlmeister.comE<gt>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
diff --git a/lib/Net/Amazon/Property.pm b/lib/Net/Amazon/Property.pm
deleted file mode 100644
index 6c06957..0000000
--- a/lib/Net/Amazon/Property.pm
+++ /dev/null
@@ -1,320 +0,0 @@
-######################################################################
-package Net::Amazon::Property;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon);
-
-use Net::Amazon::Property::DVD;
-use Net::Amazon::Property::Book;
-use Net::Amazon::Property::Music;
-use Net::Amazon::Attribute::ReviewSet;
-use Data::Dumper;
-use Log::Log4perl qw(:easy);
-
-use warnings; 
-use strict;
-
-our @DEFAULT_ATTRIBUTES = qw(
-  OurPrice ImageUrlLarge ImageUrlMedium ImageUrlSmall
-  ReleaseDate Catalog Asin url Manufacturer UsedPrice
-  ListPrice ProductName Availability SalesRank
-  Media NumMedia ProductDescription
-  CollectiblePrice CollectibleCount NumberOfOfferings
-  UsedCount ThirdPartyNewPrice ThirdPartyNewCount
-  ThirdPartyProductInfo
-);
-
-__PACKAGE__->make_accessor($_) for @DEFAULT_ATTRIBUTES;
-__PACKAGE__->make_accessor($_) for qw(year review_set);
-__PACKAGE__->make_array_accessor($_) for qw(browse_nodes similar_asins);
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    if(!$options{xmlref}) {
-        die "Mandatory param xmlref missing";
-    }
-
-    my $self = { 
-        %options, 
-               };
-
-    bless $self, $class;
-
-        # Set default attributes
-    for my $attr (@DEFAULT_ATTRIBUTES) {
-        $self->$attr($options{xmlref}->{$attr});
-    }
-
-    # The release date is sometimes missing
-    if($options{xmlref}->{ReleaseDate}) {
-        my ($year) = ($options{xmlref}->{ReleaseDate} =~ /(\d{4})/);
-        $self->year($year);
-    } else {
-        $self->year("");
-    }
-
-    my $browse_nodes = $options{xmlref}->{BrowseList}->{BrowseNode};
-    if(ref($browse_nodes) eq "ARRAY") {
-      my @nodes = map {
-        $_->{BrowseName}
-      } @{ $browse_nodes };
-      $self->browse_nodes(\@nodes);
-    } elsif (ref($browse_nodes) eq "HASH") {
-      $self->browse_nodes([ $browse_nodes->{BrowseName} ]);
-    } else {
-      $self->browse_nodes([ ]);
-    }
-
-    my $similar = $options{xmlref}->{SimilarProducts};
-    if(ref($similar) eq "HASH") {
-      $self->similar_asins($similar->{Product});
-    } else {
-      $self->similar_asins([ ]);
-    }
-
-    return $self;
-}
-
-##################################################
-sub as_string {
-##################################################
-    my($self) = @_;
-
-    my $result = "\"$self->{xmlref}->{ProductName}\", ";
-
-    if($self->{xmlref}->{Manufacturer}) {
-        $result .= "$self->{xmlref}->{Manufacturer}, ";
-    }
-
-    $result .= $self->year() . ", " if $self->year();
-
-    $result .= $self->OurPrice() . ", ";
-    $result .= $self->Asin();
-    return $result;
-}
-
-##################################################
-sub factory {
-##################################################
-    my(%options) = @_;
-
-    my $xmlref = $options{xmlref};
-    die "Called factory without xmlref" unless $xmlref;
-
-    # DEBUG(sub {"factory xmlref=" . Data::Dumper::Dumper($xmlref)});
-
-    my $catalog = $xmlref->{Catalog};
-    my $obj;
-
-    if(0) {
-    } elsif($catalog eq "Book") {
-        DEBUG("Creating new Book Property");
-        $obj = Net::Amazon::Property::Book->new(xmlref => $xmlref);
-    } elsif($catalog eq "Music") {
-        DEBUG("Creating new Music Property");
-        $obj = Net::Amazon::Property::Music->new(xmlref => $xmlref);
-    } elsif($catalog eq "DVD") {
-        DEBUG("Creating new DVD Property");
-        $obj = Net::Amazon::Property::DVD->new(xmlref => $xmlref);
-    } else {
-        DEBUG("Creating new Default Property ($catalog)");
-        $obj = Net::Amazon::Property->new(xmlref => $xmlref);
-    }
-
-    return $obj;
-}
-
-##################################################
-sub init_via_xmlref {
-##################################################
-    my($self, $xmlref) = @_;
-
-    my $reviewset = Net::Amazon::Attribute::ReviewSet->new();
-
-    if(exists $xmlref->{Reviews}) {
-        $reviewset->init_via_xmlref($xmlref->{Reviews});
-    }
-
-    $self->review_set($reviewset); 
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Property - Baseclass for products on amazon.com
-
-=head1 SYNOPSIS
-
-  use Net::Amazon;
-
-  # ...
-
-  if($resp->is_success()) {
-      for my $prop ($resp->properties) {
-          print $_->ProductName(), " ",
-                $_->Manufacturer(), " ",
-                $_->OurPrice(), "\n";
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Property> is the baseclass for results returned
-from Amazon web service queries. The term 'properties' is used as 
-a generic description for an item on amazon.com.
-
-Typically, the C<properties()> method of a C<Net::Amazon::Response::*> object
-will return one or more objects of class C<Net::Amazon::Property> or
-one of its subclasses, e.g. C<Net::Amazon::Property::Book> or
-C<Net::Amazon::Property::CD>.
-
-While C<Net::Amazon::Property> objects expose accessors for all 
-fields returned in the XML response (like C<OurPrice()>, C<ListPrice()>,
-C<Manufacturer()>, C<Asin()>, C<Catalog()>, C<ProductName()>, subclasses
-might define their own accessors to more class-specific fields
-(like the iC<Net::Amazon::Property::Book>'s C<authors()> method returning
-a list of authors, while C<Net::Amazon::Property>'s C<Authors()> method
-will return a reference to a sub-hash containing a C<Author> field, just like
-the response's XML contained it).
-
-=head2 METHODS
-
-Methods vary, depending on the item returned from a query. Here's the most
-common ones. They're all accessors, meaning they can be used like C<Method()>
-to retrieve the value or like C<Method($value)> to set the value of the
-field.
-
-=over 4
-
-=item Asin()
-
-The item's ASIN number.
-
-=item ProductName()
-
-Book title, CD album name or item name
-
-=item Availability()
-
-Text string describing if the item is available. Examples:
-C<"Usually ships within 24 hours"> or
-C<"Out of Print--Limited Availability">.
-
-=item Catalog()
-
-Shows the catalog the item was found in: C<Book>, C<Music>, C<Classical>,
-C<Electronics> etc.
-
-=item Authors()
-
-Returns a sub-hash with a C<Author> key, which points to either a single
-$scalar or to a reference of an array containing author names as scalars.
-
-=item ReleaseDate()
-
-Item's release date, format is "NN Monthname, Year".
-
-=item Manufacturer()
-
-Music label, publishing company or manufacturer
-
-=item ImageUrlSmall()
-
-URL to a small (thumbnail) image of the item
-
-=item ImageUrlMedium()
-
-URL to a medium-size image of the item
-
-=item ImageUrlLarge()
-
-URL to a large image of the item
-
-=item ListPrice()
-
-List price of the item
-
-=item OurPrice()
-
-Amazon price of the item
-
-=item UsedPrice()
-
-Used price of the item
-
-=item SalesRank()
-
-Sales rank of the item (contains digits and commas, like 1,000,001)
-
-=item Media()
-
-Type of media (Paperback, etc.).
-
-=item NumMedia()
-
-Number of media the item carries (1,2 CDs etc.).
-
-=item ProductDescription()
-
-Lengthy textual description of the product.
-
-=item CollectiblePrice() 
-
-Lowest price in "Collectible" category.
-
-=item CollectibleCount()
-
-Number of offerings in "Collectible" category.
-
-=item NumberOfOfferings()
-
-Total number of offerings in all categories.
-
-=item UsedCount()
-
-Number of offerings in "Used" category.
-
-=item ThirdPartyNewPrice()
-
-Lowest price in "Third Party New" category.
-
-=item ThirdPartyNewCount()
-
-Number of offerings in "Third Party New" category.
-
-=item year()
-
-The release year extracted from ReleaseDate().
-
-=item browse_nodes()
-
-Returns a list of browse nodes (text string categories) for this item.
-
-=item similar_asins()
-
-Returns a list of ASINs of similar items for this item.
-
-=back
-
-Please check the subclasses of C<Net::Amazon::Property> for specialized 
-methods.
-
-=head1 SEE ALSO
-
-=head1 AUTHOR
-
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2003 by Mike Schilli E<lt>m@perlmeister.comE<gt>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
diff --git a/lib/Net/Amazon/Property/Book.pm b/lib/Net/Amazon/Property/Book.pm
deleted file mode 100644
index 8a01756..0000000
--- a/lib/Net/Amazon/Property/Book.pm
+++ /dev/null
@@ -1,152 +0,0 @@
-######################################################################
-package Net::Amazon::Property::Book;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Property);
-
-__PACKAGE__->make_accessor($_) for qw(title publisher binding isbn);
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    my $self = $class->SUPER::new(%options);
-    bless $self, $class; # Bless into this class
-
-    if(exists $options{xmlref}) {
-        $self->init_via_xmlref($options{xmlref});
-    }
-
-    return $self;
-}
-
-##################################################
-sub init_via_xmlref {
-##################################################
-    my($self, $xmlref) = @_;
-
-    $self->SUPER::init_via_xmlref($xmlref);
-
-    $self->authors($xmlref->{Authors}->{Author});
-    $self->title($xmlref->{ProductName});
-    $self->publisher($xmlref->{Manufacturer});
-    $self->binding($xmlref->{Media});
-    $self->isbn($xmlref->{Isbn});
-}
-
-##################################################
-sub author {
-##################################################
-    my($self, $nameref) = @_;
-
-    # Only return the first author
-    return ($self->authors($nameref))[0];
-}
-
-##################################################
-sub authors {
-##################################################
-    my($self, $nameref) = @_;
-
-    if(defined $nameref) {
-        if(ref $nameref eq "ARRAY") {
-            $self->{authors} = $nameref;
-        } else {
-            $self->{authors} = [$nameref];
-        }
-    }
-
-       # Return a list
-    return $self->{authors} ? @{$self->{authors}} : ();
-}
-
-##################################################
-sub as_string {
-##################################################
-    my($self) = @_;
-
-    return join('/', $self->authors) . ", " .
-      '"' . $self->title . '"' . ", " .
-      $self->year . ", " .
-      $self->OurPrice . ", " .
-      $self->Asin;
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Property::Book - Class for books on amazon.com
-
-=head1 SYNOPSIS
-
-  use Net::Amazon;
-
-  # ...
-
-  if($resp->is_success()) {
-      for my $prop ($resp->properties) {
-          print join("/", $prop->authors(), " ",
-                $prop->title(), " ",
-                $prop->publisher(), " ",
-                $prop->year(), "\n";
-  }
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Property::Book> is derived from 
-C<Net::Amazon::Property> and on top of the all-purpose
-methods the base class provides, it offers specialized accessors for
-book parameters.
-
-=head2 METHODS
-
-=over 4
-
-=item authors()
-
-Returns a list of the book's authors. There's also a C<author()> method
-which just returns the I<first> author.
-
-=item publisher()
-
-Returns the book's publishing company as a string.
-
-=item title()
-
-Returns the book's title as a string.
-
-=item isbn()
-
-Returns the book's ISBN number.
-
-=item new(xmlref => $xmlref)
-
-Initializes an object by passing a hash of hashes structure containing
-the XML data returned from the service. Usually, this is just used by
-C<Net::Amazon> internally to initialize objects for on backcoming
-data.
-
-=back
-
-Check out L<Net::Amazon::Property> for all-purpose accessors, like
-C<year>, C<OurPrice>, C<ListPrice>, etc.
-
-=head1 SEE ALSO
-
-=head1 AUTHOR
-
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2003 by Mike Schilli E<lt>m@perlmeister.comE<gt>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
diff --git a/lib/Net/Amazon/Property/DVD.pm b/lib/Net/Amazon/Property/DVD.pm
deleted file mode 100644
index dc7fd5a..0000000
--- a/lib/Net/Amazon/Property/DVD.pm
+++ /dev/null
@@ -1,156 +0,0 @@
-######################################################################
-package Net::Amazon::Property::DVD;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Property);
-
-__PACKAGE__->make_accessor($_) for qw(title studio theatrical_release_date
-  media nummedia upc mpaa_rating);
-__PACKAGE__->make_array_accessor($_) for qw(directors starring features);
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    my $self = $class->SUPER::new(%options);
-    bless $self, $class; # Bless into this class
-
-    if(exists $options{xmlref}) {
-        $self->init_via_xmlref($options{xmlref});
-    }
-
-    return $self;
-}
-
-##################################################
-sub director {
-##################################################
-    my($self, $nameref) = @_;
-
-    # Only return the first director
-    return ($self->directors($nameref))[0];
-}
-
-##################################################
-sub init_via_xmlref {
-##################################################
-    my($self, $xmlref) = @_;
-
-    $self->SUPER::init_via_xmlref($xmlref);
-
-    $self->title($xmlref->{ProductName});
-    $self->studio($xmlref->{Manufacturer});
-    $self->directors($xmlref->{Directors}->{Director});
-    $self->starring($xmlref->{Starring}->{Actor});
-    $self->media($xmlref->{Media});
-    $self->nummedia($xmlref->{NumMedia});
-    $self->upc($xmlref->{Upc});
-    $self->theatrical_release_date($xmlref->{TheatricalReleaseDate});
-    $self->mpaa_rating($xmlref->{MpaaRating});
-    $self->features($xmlref->{Features}->{Feature});
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Property::DVD - Class for DVDs on amazon.com
-
-=head1 SYNOPSIS
-
-  use Net::Amazon;
-
-  # ...
-
-  if($resp->is_success()) {
-      for my $prop ($resp->properties) {
-          print $_->title(), " ",
-                $_->studio(), " ",
-                $_->year(), "\n";
-  }
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Property::DVD> is derived from 
-C<Net::Amazon::Property> and on top of the all-purpose
-methods the base class provides, it offers specialized accessors for
-DVD parameters.
-
-=head2 METHODS
-
-=over 4
-
-=item title()
-
-Returns the title of the DVD.
-
-=item studio()
-
-Returns the studio.
-
-=item directors()
-
-Returns a list of directors. Note that there's also a director() method
-only returning the first director.
-
-=item starring()
-
-Returns a list of actors starring in the movie.
-
-=item upc()
-
-Returns the DVD's UPC as a string.
-
-=item media()
-
-Returns the DVD's media type as a string.
-
-=item nummedia()
-
-Returns the DVD's number of media (number of discs) as a string.
-Amazon doesn't always send this back, so if you get undef assume it
-is 1.
-
-=item theatrical_release_date()
-
-Returns the DVD's theatrical release date.
-
-=item mpaa_rating()
-
-Returns the DVD's MPAA rating.
-
-=item features()
-
-Returns the DVD's features as a list of strings. Examples: 
-"Color", "Closed-captioned", "Widescreen".
-
-=item new(xmlref => $xmlref)
-
-Initializes an object by passing a hash of hashes structure containing
-the XML data returned from the service. Usually, this is just used by
-C<Net::Amazon> internally to initialize objects for on backcoming
-data.
-
-=back
-
-Check out L<Net::Amazon::Property> for all-purpose accessors, like
-C<year>, C<OurPrice>, C<ListPrice>, etc.
-
-=head1 SEE ALSO
-
-=head1 AUTHOR
-
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2003 by Mike Schilli E<lt>m@perlmeister.comE<gt>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
diff --git a/lib/Net/Amazon/Property/Music.pm b/lib/Net/Amazon/Property/Music.pm
deleted file mode 100644
index 59807be..0000000
--- a/lib/Net/Amazon/Property/Music.pm
+++ /dev/null
@@ -1,161 +0,0 @@
-######################################################################
-package Net::Amazon::Property::Music;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Property);
-
-__PACKAGE__->make_accessor($_) for qw(album label media nummedia upc);
-__PACKAGE__->make_array_accessor($_) for qw(artists tracks);
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    my $self = $class->SUPER::new(%options);
-    bless $self, $class; # Bless into this class
-
-    if(exists $options{xmlref}) {
-        $self->init_via_xmlref($options{xmlref});
-    }
-
-    return $self;
-}
-
-##################################################
-sub artist {
-##################################################
-    my($self, $nameref) = @_;
-
-    # Only return the first artist
-    return ($self->artists($nameref))[0];
-}
-
-##################################################
-sub init_via_xmlref {
-##################################################
-    my($self, $xmlref) = @_;
-
-    $self->SUPER::init_via_xmlref($xmlref);
-
-    $self->artists($xmlref->{Artists}->{Artist});
-    $self->tracks($xmlref->{Tracks}->{Track});
-    $self->album($xmlref->{ProductName});
-    $self->label($xmlref->{Manufacturer});
-    $self->upc($xmlref->{Upc});
-    $self->media($xmlref->{Media});
-    $self->nummedia($xmlref->{NumMedia});
-}
-
-##################################################
-sub as_string {
-##################################################
-    my($self) = @_;
-
-    return join('/', $self->artists) . ", " .
-           '"' . $self->album . '"' . ", " .
-           $self->year . ", " .
-           $self->OurPrice . ", " .
-           $self->Asin;
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Property::Music - Class for pop CDs on amazon.com
-
-=head1 SYNOPSIS
-
-  use Net::Amazon;
-
-  # ...
-
-  if($resp->is_success()) {
-      for my $prop ($resp->properties) {
-          print join("/", $_->artists(), " ",
-                $_->album(), " ",
-                $_->label(), " ",
-                $_->year(), " ";
-                $_->upc(), " ";
-                $_->media(), " ";
-                $_->nummedia(), "\n";
-  }
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Property::Music> is derived from 
-C<Net::Amazon::Property> and on top of the all-purpose
-methods the base class provides, it offers specialized accessors for
-popular music CD parameters.
-
-=head2 METHODS
-
-=over 4
-
-=item artists()
-
-Returns a list of the CD's artists. There's also a C<artist()> method
-which just returns the first artist.
-
-=item tracks()
-
-Returns a list of the CD's track titles.
-
-=item label()
-
-Returns the music label as a string.
-
-=item album()
-
-Returns the CD's title as a string.
-
-=item upc()
-
-Returns the CD's UPC as a string.
-
-=item media()
-
-Returns the CD's media type as a string.
-
-=item nummedia()
-
-Returns the CD's number of media (number of discs) as a string.
-Amazon doesn't always send this back, so if you get undef assume it
-is 1.
-
-=item new(xmlref => $xmlref)
-
-Initializes an object by passing a hash of hashes structure containing
-the XML data returned from the service. Usually, this is just used by
-C<Net::Amazon> internally to initialize objects for on backcoming
-data.
-
-=back
-
-Check out L<Net::Amazon::Property> for all-purpose accessors, like
-C<year>, C<OurPrice>, C<ListPrice>, etc.
-
-=head1 SEE ALSO
-
-=head1 AUTHOR
-
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=head1 THANKS
-
-Thanks to Padraic Renaghan E<lt>padraic@renaghan.com<gt> for adding
-the upc/media/nummedia fields.
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2003 by Mike Schilli E<lt>m@perlmeister.comE<gt>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
-
diff --git a/lib/Net/Amazon/Request.pm b/lib/Net/Amazon/Request.pm
deleted file mode 100644
index 962d7bf..0000000
--- a/lib/Net/Amazon/Request.pm
+++ /dev/null
@@ -1,221 +0,0 @@
-######################################################################
-package Net::Amazon::Request;
-######################################################################
-
-use warnings;
-use strict;
-
-use constant DEFAULT_MODE          => 'books';
-use constant DEFAULT_TYPE          => 'heavy';
-use constant DEFAULT_PAGE_COUNT    => 1;
-use constant DEFAULT_FORMAT        => 'xml';
-use constant DEFAULT_SORT_CRITERIA => '+salesrank';
-
-use constant VALID_TYPES => { map { $_ => 1 } qw(heavy lite) };
-
-our $AMZN_XML_URL  = "http://xml.amazon.com/onca/xml3";
-
-##################################################
-sub amzn_xml_url {
-##################################################
-    return $AMZN_XML_URL;
-}
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    my $self = {
-        mode       => DEFAULT_MODE,
-        type       => DEFAULT_TYPE,
-        page       => DEFAULT_PAGE_COUNT,
-        f          => DEFAULT_FORMAT,
-        sort       => DEFAULT_SORT_CRITERIA,
-        %options,
-    };
-
-    die "Unknown type in ", __PACKAGE__, " constructor: ",
-        $self->{type} unless exists VALID_TYPES->{$self->{type}};
-
-    bless $self, $class;
-}
-
-##################################################
-sub params {
-##################################################
-    my($self) = @_;
-
-    return(%$self);
-}
-
-##################################################
-# Figure out the Response class to a given Request
-# class. To be used by sub classes.
-##################################################
-sub response_class {
-##################################################
-    my($self) = @_;
-
-    my $response_class = ref($self);
-    $response_class =~ s/Request/Response/;
-    return $response_class;
-}
-
-##
-## 'PRIVATE' METHODS
-##
-
-# CLASS->_convert_option( OPTIONS, ORIGINAL, TARGET [, CALLBACK] )
-#
-# Takes a reference to a hash of OPTIONS and renames the
-# ORIGINAL key name to the TARGET key name. If the optional
-# CALLBACK subroutine reference is defined, that subroutine
-# is invoked with two arguments:
-#
-#     CALLBACK->( OPTIONS, TARGET )
-#
-# The result of the CALLBACK's execution is then returned to
-# the caller. No assumptions are made about what the CALLBACK
-# should return (or even *if* is should return)--that's the
-# caller's responsibility.
-#
-# Returns 1 in the absensence of a CALLBACK.
-#
-sub _convert_option {
-    my ($class, $options, $original, $target, $callback) = @_;
-
-    if ( exists $options->{$original} ) {
-        $options->{$target} = $options->{$original};
-        delete $options->{$original};
-    }
-
-    return 1 unless ( $callback );
-
-    # The key name is explicitly passed-in so that the caller doesn't
-    # have think "Hrmm..  now which key am I working on, the original
-    # or the target key?" Confusion is bad.
-    return $callback->($options, $target);
-}
-
-# CLASS->_assert_options_defined( OPTIONS, KEYS )
-#
-# Takes a reference to a hash of OPTIONS and a list of
-# one or more KEYS. Tests to see if each key in KEYS
-# has a defined value. Calls die() upon the first
-# missing key. Otherwise, returns undef.
-#
-sub _assert_options_defined {
-    my ($class, $options, @keys) = @_;
-    
-    foreach my $key ( @keys ) {
-        die "Mandatory parameter '$key' not defined"
-            unless ( defined $options->{$key} );
-    }
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Request - Baseclass for requests to Amazon's web service
-
-=head1 SYNOPSIS
-
-    my $req = Net::Amazon::Request::XXX->new(
-                     [ type  => 'heavy', ]
-                     [ page  => $start_page, ]
-                     [ mode  => $mode, ]
-                     [ offer => 'All', ]
-                     [ sort => $sort_type, ]
-    );
-
-=head1 DESCRIPTION
-
-Don't use this class directly, use derived classes 
-(like C<Net::Amazon::Request::ASIN>, C<Net::Amazon::Request::Wishlist>
-etc.) instead to specify the type of request and its parameters.
-
-However, there's a bunch of parameters to the constructor
-that all request types have in common, here they are:
-
-=over 4
-
-=item type
-
-Defaults to C<heavy>, but can be set to C<lite> if no reviews etc.
-on a product are wanted. Some fields (e.g. C<isbn>) are not going to be 
-available in C<lite> mode, though.
-
-=item mode
-
-Defaults to C<books>, but can be set to other catalog values.
-
-=item page
-
-Defaults to C<1>, but can be set to a different number to 
-start with a different result page. Used in conjunction with the
-C<max_pages> parameter of the C<Net::Amazon> object. C<page> is the
-offset, C<max_pages> is the maximum number of pages pulled in starting
-at C<page>.
-
-=item sort
-
-Defaults to C<+salesrank>, but search results can be sorted in various
-ways, depending on the type of product returned by the search.  Search
-results may be sorted by the following criteria:
-
-=over 8
-
-=item *
-Featured Items                                                           
-
-=item *
-Bestselling                                                              
-
-=item *
-Alphabetical (A-Z and Z-A)                                               
-
-=item *
-Price (High to Low and Low to High)                                      
-
-=item *
-Publication or Release Date                                              
-
-=item *
-Manufacturer                                                             
-
-=item *
-Average Customer Review                                                  
-
-=item *
-Artist Name                                   
-
-=back
-
-Consult L<Net::Amazon::Request::Sort> for details.
-
-=item offer
-
-To receive values for the fields
-C<CollectibleCount>, C<NumberOfOfferings>, C<UsedCount>, 
-specify C<offer =E<gt> "All">.
-
-=back
-
-=head1 SEE ALSO
-
-=head1 AUTHOR
-
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2003 by Mike Schilli E<lt>m@perlmeister.comE<gt>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
diff --git a/lib/Net/Amazon/Request/ASIN.pm b/lib/Net/Amazon/Request/ASIN.pm
deleted file mode 100644
index 4d8f752..0000000
--- a/lib/Net/Amazon/Request/ASIN.pm
+++ /dev/null
@@ -1,139 +0,0 @@
-######################################################################
-package Net::Amazon::Request::ASIN;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Request);
-
-# These values are defined in the AWS SDK
-# (http://amazon.com/webservices) under
-# "Product and Catalog Data" / "ASIN and ISBN Searches"
-use constant MAX_ASINS_PER_TYPE => {
-    heavy => 10,
-    lite  => 30,
-};
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    $class->_assert_options_defined(\%options, 'asin');
-
-    $class->_convert_option(\%options,
-                            'asin',
-                            'AsinSearch',
-                            \&_process_asin_option);
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-##
-## PRIVATE FUNCTIONS
-##
-
-# _process_asin_option( OPTIONS, KEY )
-#
-# Takes a reference to a hash of OPTIONS and checks the value keyed by
-# KEY to make sure it looks legitimate.  If the value associated with
-# KEY is an array, we check to make sure that we're not asking for
-# too many asins at once.
-#
-# Returns true if all goes well. If any problems are encountered,
-# die() will be called.
-#
-sub _process_asin_option {
-    my ($options, $key) = @_;
-
-    # If the asins are supplied in the form of an array, we have to
-    # make sure that the caller isn't trying to ask for too many at a
-    # time. If we don't make this test, those excessive asins will be
-    # silently ignored by the AWS servers...resulting in potentially
-    # confusing results for the user.
-    if ( ref $options->{$key} eq 'ARRAY' ) {
-        my $type      = $options->{'type'} || __PACKAGE__->SUPER::DEFAULT_TYPE;
-        my $max_asins = MAX_ASINS_PER_TYPE->{$type};
-
-        # Dying is the right thing to do here because this is
-        # indicative of a programming error.
-        die "Only $max_asins may be requested at a time using type '$type'"
-            if ( @{$options->{$key}} > $max_asins );
-
-        $options->{$key} = join ',', @{$options->{$key}};
-    } elsif ( ref $options->{$key} ) {
-        die "The 'asin' parameter must either be a scalar or an array";
-    }
-
-    return 1;
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Request::ASIN - Class for submitting ASIN requests
-
-=head1 SYNOPSIS
-
-  use Net::Amazon;
-  use Net::Amazon::Request::ASIN;
-
-  my $ua = Net::Amazon->new(
-      token       => 'YOUR_AMZN_TOKEN'
-  );
-
-  my $req = Net::Amazon::Request::ASIN->new( 
-      asin  => '0201360683'
-  );
-
-    # Response is of type Net::Amazon::Response::ASIN
-  my $resp = $ua->request($req);
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Request::ASIN> is a class used to submit ASIN requests
-to the Amazon web service.
-
-The ASIN of the item to look is specified in the C<asin> parameter.
-
-Upon success, the responses' C<properties()> method will return one
-single C<Net::Amazon::Property::*> object.
-
-=head2 METHODS
-
-=over 4
-
-=item new( asin => $asin )
-
-Constructs a new C<Net::Amazon::Request::ASIN> object, used to query
-the Amazon web service for an item with the specified ASIN number.
-
-C<$asin> can also be a reference to an array of ASINs, like in
-
-    $ua->search(asin => ["0201360683", "0596005083"]) 
-
-in which case a search for multiple ASINs is performed, returning a list of 
-results.
-
-=back
-
-Check L<Net::Amazon::Request> for common request parameters not listed here.
-
-=head1 SEE ALSO
-
-=head1 AUTHOR
-
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2003 by Mike Schilli E<lt>m@perlmeister.comE<gt>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
diff --git a/lib/Net/Amazon/Request/Artist.pm b/lib/Net/Amazon/Request/Artist.pm
deleted file mode 100644
index 4c111f8..0000000
--- a/lib/Net/Amazon/Request/Artist.pm
+++ /dev/null
@@ -1,86 +0,0 @@
-######################################################################
-package Net::Amazon::Request::Artist;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Request);
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    if(exists $options{artist}) {
-        $options{ArtistSearch} = $options{artist};
-        delete $options{artist};
-        $options{mode} = "music";
-    } else {
-        die "Mandatory parameter 'artist' not defined";
-    }
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Request::Artist - Class for submitting Artist requests
-
-=head1 SYNOPSIS
-
-  use Net::Amazon;
-  use Net::Amazon::Request::Artist;
-
-  my $ua = Net::Amazon->new(
-      token       => 'YOUR_AMZN_TOKEN'
-  );
-
-  my $req = Net::Amazon::Request::Artist->new( 
-      artist  => 'Zwan'
-  );
-
-    # Response is of type Net::Amazon::Response::Artist
-  my $resp = $ua->request($req);
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Request::Artist> is a class used to submit Artist search
-requests to the Amazon web service.
-
-The artist to search for is specified in the C<artist> parameter.
-
-Upon success, the responses' C<properties()> method will return a list of
-C<Net::Amazon::Property::Music> objects.
-
-Check L<Net::Amazon::Request> for common request parameters not listed here.
-
-=head2 METHODS
-
-=over 4
-
-=item new( artist => $artist )
-
-Constructs a new C<Net::Amazon::Request::Artist> object, used to query
-the Amazon web service for items of a given artist.
-
-=back
-
-=head1 SEE ALSO
-
-=head1 AUTHOR
-
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2003 by Mike Schilli E<lt>m@perlmeister.comE<gt>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
diff --git a/lib/Net/Amazon/Request/Blended.pm b/lib/Net/Amazon/Request/Blended.pm
deleted file mode 100644
index 1000eec..0000000
--- a/lib/Net/Amazon/Request/Blended.pm
+++ /dev/null
@@ -1,80 +0,0 @@
-######################################################################
-package Net::Amazon::Request::Blended;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Request);
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    $class->_assert_options_defined(\%options, 'blended');
-
-    $class->_convert_option(\%options,
-                            'blended',
-                            'BlendedSearch');
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Request::Blended - request class for 'Blended Search'
-
-=head1 SYNOPSIS
-
-  use Net::Amazon;
-  use Net::Amazon::Request::Blended;
-
-  my $ua = Net::Amazon->new(
-      token       => 'YOUR_AMZN_TOKEN'
-  );
-
-  my $req = Net::Amazon::Request::Blended->new( 
-      blended => 'perl'
-  );
-
-  # Response is of type Net::Amazon::Response::Blended
-  my $resp = $ua->request($req);
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Request::Blended> is a class used to request
-I<Blended Searches> from the Amazon web service.
-
-The C<blended> parameter specifies the keyword search string
-for the blended query. C<mode> is not applicable to blended
-searches which returns books, music, etc all at once.
-
-Upon success, the response's C<properties()> method will return a list
-of C<Net::Amazon::Property::*> objects.
-
-=head2 METHODS
-
-=over 4
-
-=item new(keyword => $search_string)
-
-Constructs a new C<Net::Amazon::Request::Blended> object.
-
-See the "Amazon Web Services 2.1 API and Integration Guide" for details.
-
-=back
-
-Check L<Net::Amazon::Request> for common request parameters not listed here.
-
-=head1 SEE ALSO
-
-=head1 AUTHORS
-
-Robert Graff, E<lt>rgraff@workingdemo.comE<gt>
-
-=cut
diff --git a/lib/Net/Amazon/Request/BrowseNode.pm b/lib/Net/Amazon/Request/BrowseNode.pm
deleted file mode 100644
index 2f8d92f..0000000
--- a/lib/Net/Amazon/Request/BrowseNode.pm
+++ /dev/null
@@ -1,137 +0,0 @@
-######################################################################
-package Net::Amazon::Request::BrowseNode;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Request);
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    $class->_assert_options_defined(\%options,
-                                    qw(browsenode mode));
-
-    $class->_convert_option(\%options,
-                            'browsenode',
-                            'BrowseNodeSearch',
-                            \&_assert_node_is_numeric);
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-##
-## 'PRIVATE' FUNCTIONS
-##
-
-# _assert_node_is_numeric( OPTIONS, KEY )
-#
-# Takes a reference to a hash of OPTIONS and makes sure
-# that the browse node id keyed by KEY is numeric. 
-#
-# Returns if all is well, dies otherwise.
-#
-sub _assert_node_is_numeric {
-    my ($options, $key) = @_;
-
-    die "Browse Node ID must be numeric."
-        if ( $options->{$key} =~ /\D/ );
-}
-
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Request::BrowseNode - request class for browse node search
-
-=head1 SYNOPSIS
-
-  use Net::Amazon;
-  use Net::Amazon::Request::BrowseNode;
-
-  my $ua = Net::Amazon->new(
-      token       => 'YOUR_AMZN_TOKEN'
-  );
-
-  my $req = Net::Amazon::Request::BrowseNode->new( 
-      browsenode  => 30,
-      mode     => 'books'
-  );
-
-  # Response is of type Net::Amazon::Response::BrowseNode
-  my $resp = $ua->request($req);
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Request::BrowseNode> is a class used to submit node search
-requests to the Amazon web service.
-
-The node to search for is specified in the C<browsenode> parameter. The
-browse node ID is a number that corresponds to a general subject area 
-of Amazon.com.
-
-To find browse node IDs, the best way is to visit the "browse" area 
-of the various product lines at Amazon.com. When you find a subject area 
-that you would like to generate XML for, look at the web page URL. The 
-browse ID should appear after the string "/tg/browse/-/". Here are some 
-examples of URLs that contain browse IDs:
-
-=over 8
-
-http://www.amazon.com/exec/obidos/tg/browse/-/30 
-(In this example, the browse ID = 30)
-
-http://www.amazon.com/exec/obidos/tg/browse/-/467970 
-(In this example, the browse ID = 467970)
-
-http://www.amazon.com/exec/obidos/tg/browse/-/602314 
-(In this example, the browse ID = 60231
-
-=back
-
-Please be aware that some nodes cannot be used with a
-BrowseNodeSearch. (The vast majority of them can, but you
-may run across a few that simply will not work). It is also
-important to point out that from time to time, some browse
-nodes are deprecated or are changed without notice.
-
-The catalog to search in is specified in the C<mode> parameter,
-typical values are C<books>, C<music>, C<classical> or C<electronics>.
-
-An optional C<keywords> parameter may be added to filter the results by that keyword.
-
-Upon success, the responses' C<properties()> method will return a list of
-C<Net::Amazon::Properties::*> objects.
-
-=head2 METHODS
-
-=over 4
-
-=item new( browsenode => $nodeID, mode => $mode [, keywords => $keywords] )
-
-Constructs a new C<Net::Amazon::Request::BrowseNode> object, used to query
-the Amazon web service for items in a particular category (node) in the 
-mode (catalog) specified.
-
-=back
-
-Check L<Net::Amazon::Request> for common request parameters not listed here.
-
-=head1 AUTHOR
-
-Net::Amazon framework by Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-BrowseNode.pm by Jackie Hamilton, E<lt>kira@cgi101.comE<gt>
-
-=head1 LICENSE
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
diff --git a/lib/Net/Amazon/Request/Exchange.pm b/lib/Net/Amazon/Request/Exchange.pm
deleted file mode 100644
index df75549..0000000
--- a/lib/Net/Amazon/Request/Exchange.pm
+++ /dev/null
@@ -1,91 +0,0 @@
-######################################################################
-package Net::Amazon::Request::Exchange;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Request);
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-   if(exists $options{exchange}) {
-       $options{ExchangeSearch} = $options{exchange};
-       delete $options{exchange};
-       $options{type} = "lite";
-       $options{mode} = "";
-  } else {
-      die "Mandatory parameter 'exchange' not defined";
-  }
-
-#    if(!exists $options{exchange}) {
-#        die "Mandatory parameter 'exchange' not defined";
-#    }
-
-   my $self = $class->SUPER::new(%options);
-
-   bless $self, $class;   # reconsecrate
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Request::Exchange - Class for submitting Exchange requests
-
-=head1 SYNOPSIS
-
-  use Net::Amazon;
-  use Net::Amazon::Request::Exchange;
-
-  my $ua = Net::Amazon->new(
-      token       => 'YOUR_AMZN_TOKEN'
-  );
-
-  my $req = Net::Amazon::Request::Exchange->new( 
-      exchange  => 'Y04Y3424291Y2398445'
-  );
-
-    # Response is of type Net::Amazon::Response::Seller
-  my $resp = $ua->request($req);
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Request::Exchange> is a class used to submit Exchange search
-requests to the Amazon web service. Exchange requests send an item's 
-exchange ID and retrieve a description of the item, offered by a third
-party seller on Amazon.
-
-Upon success, the responses' C<result()> method will return a single
-C<Net::Amazon::Result::Seller::Listing> object.
-
-Check L<Net::Amazon::Request> for common request parameters not listed here.
-
-=head2 METHODS
-
-=over 4
-
-=item new( exchange => $exchange_id )
-
-Constructs a new C<Net::Amazon::Request::Exchange> object, used to query
-the Amazon web service with the given seller id.
-
-=back
-
-=head1 SEE ALSO
-
-=head1 AUTHOR
-
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2005 by Mike Schilli E<lt>m@perlmeister.comE<gt>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
diff --git a/lib/Net/Amazon/Request/Keyword.pm b/lib/Net/Amazon/Request/Keyword.pm
deleted file mode 100644
index 0b15d1d..0000000
--- a/lib/Net/Amazon/Request/Keyword.pm
+++ /dev/null
@@ -1,90 +0,0 @@
-######################################################################
-package Net::Amazon::Request::Keyword;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Request);
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    $class->_assert_options_defined(\%options, 
-                                    qw(keyword mode));
-
-    $class->_convert_option(\%options,
-                            'keyword',
-                            'KeywordSearch');
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Request::Keyword - request class for keyword search
-
-=head1 SYNOPSIS
-
-  use Net::Amazon;
-  use Net::Amazon::Request::Keyword;
-
-  my $ua = Net::Amazon->new(
-      token       => 'YOUR_AMZN_TOKEN'
-  );
-
-  my $req = Net::Amazon::Request::Keyword->new( 
-      keyword  => 'Zwan',
-      mode     => 'books'
-  );
-
-    # Response is of type Net::Amazon::Response::Keyword
-  my $resp = $ua->request($req);
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Request::Keyword> is a class used to submit keyword search
-requests to the Amazon web service.
-
-The keyword to search for is specified in the C<keyword> parameter.
-
-The catalog to search in is specified in the C<mode> parameter,
-typical values are C<books>, C<music>, C<classical> or C<electronics>.
-
-Upon success, the responses' C<properties()> method will return a list of
-C<Net::Amazon::Property::*> objects.
-
-=head2 METHODS
-
-=over 4
-
-=item new( keyword => $keyword, mode => $mode )
-
-Constructs a new C<Net::Amazon::Request::Keyword> object, used to query
-the Amazon web service for items matching a given keyword in the 
-mode (catalog) specified.
-
-=back
-
-Check L<Net::Amazon::Request> for common request parameters not listed here.
-
-=head1 SEE ALSO
-
-=head1 AUTHOR
-
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2003 by Mike Schilli E<lt>m@perlmeister.comE<gt>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
diff --git a/lib/Net/Amazon/Request/Manufacturer.pm b/lib/Net/Amazon/Request/Manufacturer.pm
deleted file mode 100644
index 0e8adb8..0000000
--- a/lib/Net/Amazon/Request/Manufacturer.pm
+++ /dev/null
@@ -1,78 +0,0 @@
-######################################
-package Net::Amazon::Request::Manufacturer;
-######################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Request);
-
-######################################
-sub new {
-######################################
-   my($class, %options) = @_;
-
-   $class->_assert_options_defined(\%options,
-                                   'manufacturer');
-
-   $class->_convert_option(\%options,
-                           'manufacturer',
-                           'ManufacturerSearch');
-
-   my $self = $class->SUPER::new(%options);
-
-   bless $self, $class;   # reconsecrate
-}
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Request::Manufacturer - Class for submitting Manufacturer requests
-
-=head1 SYNOPSIS
-
-  use Net::Amazon;
-  use Net::Amazon::Request::Manufacturer;
-
-  my $ua = Net::Amazon->new(
-      token       => 'YOUR_AMZN_TOKEN'
-  );
-
-  my $req = Net::Amazon::Request::Manufacturer->new( 
-      manufacturer  => 'Disney'
-  );
-
-    # Response is of type Net::Amazon::Response::Manufacturer
-  my $resp = $ua->request($req);
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Request::Manufacturer> is a class used to submit 
-searches for items made by a given manufacturer.
-
-The manufacturer to search for is specified in the C<manufacturer> parameter.
-
-Upon success, the responses' C<properties()> method will return one
-or more C<Net::Amazon::Property::*> objects.
-
-=head2 METHODS
-
-=over 4
-
-=item new( manufacturer => $manufacturer )
-
-Constructs a new C<Net::Amazon::Request::Manufacturer> object, used to query
-the Amazon web service for an item with the specified manufacturer name.
-
-=back
-
-Check L<Net::Amazon::Request> for common request parameters not listed here.
-
-=head1 SEE ALSO
-
-=head1 AUTHORS
-
-Bill Fitzpatrick
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=cut
diff --git a/lib/Net/Amazon/Request/Power.pm b/lib/Net/Amazon/Request/Power.pm
deleted file mode 100644
index fdfd74e..0000000
--- a/lib/Net/Amazon/Request/Power.pm
+++ /dev/null
@@ -1,95 +0,0 @@
-######################################################################
-package Net::Amazon::Request::Power;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Request);
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    $class->_assert_options_defined(\%options, 
-                                    qw(power mode));
-
-    $class->_convert_option(\%options,
-                            'power',
-                            'PowerSearch');
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Request::Power - request class for 'Power Search'
-
-=head1 SYNOPSIS
-
-  use Net::Amazon;
-  use Net::Amazon::Request::Power;
-
-  my $ua = Net::Amazon->new(
-      token       => 'YOUR_AMZN_TOKEN'
-  );
-
-  my $req = Net::Amazon::Request::Power->new( 
-      power => 'subject: perl and author: schwartz',
-      mode  => 'books',
-  );
-
-    # Response is of type Net::Amazon::Response::Power
-  my $resp = $ua->request($req);
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Request::Power> is a class used to request
-so-called I<Power Searches> from the Amazon web service.
-
-The C<power> parameter specifies the power search string, C<mode>
-defines which properties to look for.
-
-Upon success, the response's C<properties()> method will return a list
-of C<Net::Amazon::Property::*> objects.
-
-=head2 METHODS
-
-=over 4
-
-=item new(power => $search_string, mode => $property)
-
-Constructs a new C<Net::Amazon::Request::Power> object. C<$property>
-is typically C<"books">. Examples for C<$search_string> are:
-
-    author: schwartz
-
-    author: schwartz and pubdate: after 10-2002
-
-    subject: perl and (objects or object-oriented)
-
-    keywords: "high tech*" and not fiction and pubdate: during 1999
-
-    power "author: randal schwartz and publisher: Addison Wesley"
- 
-    author: randal schwartz and title: object books
-
-See the "Amazon Web Services 2.1 API and Integration Guide" for details.
-
-=back
-
-Check L<Net::Amazon::Request> for common request parameters not listed here.
-
-=head1 SEE ALSO
-
-=head1 AUTHORS
-
-Martin Streicher, E<lt>martin.streicher@apress.comE<gt>
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=cut
diff --git a/lib/Net/Amazon/Request/Seller.pm b/lib/Net/Amazon/Request/Seller.pm
deleted file mode 100644
index 54e1930..0000000
--- a/lib/Net/Amazon/Request/Seller.pm
+++ /dev/null
@@ -1,84 +0,0 @@
-######################################################################
-package Net::Amazon::Request::Seller;
-######################################################################
-use base qw(Net::Amazon::Request);
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    if(exists $options{seller}) {
-        $options{SellerSearch} = $options{seller};
-        delete $options{seller};
-    } else {
-        die "Mandatory parameter 'seller' not defined";
-    }
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Request::Seller - Class for submitting Seller requests
-
-=head1 SYNOPSIS
-
-  use Net::Amazon;
-  use Net::Amazon::Request::Seller;
-
-  my $ua = Net::Amazon->new(
-      token       => 'YOUR_AMZN_TOKEN'
-  );
-
-  my $req = Net::Amazon::Request::Seller->new( 
-      seller  => 'A2GXAGU54VOP7'
-  );
-
-    # Response is of type Net::Amazon::Response::Seller
-  my $resp = $ua->request($req);
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Request::Seller> is a class used to submit Seller search
-requests to the Amazon web service.
-
-The seller to search for is specified in the C<seller> parameter, which
-contains the seller's ID (not the seller's nickname!).
-
-Upon success, the responses' C<result()> method will return a single
-C<Net::Amazon::Result::Seller> object.
-
-Check L<Net::Amazon::Request> for common request parameters not listed here.
-
-=head2 METHODS
-
-=over 4
-
-=item new( seller => $seller_id )
-
-Constructs a new C<Net::Amazon::Request::Seller> object, used to query
-the Amazon web service with the given seller id.
-
-=back
-
-=head1 SEE ALSO
-
-=head1 AUTHOR
-
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2004 by Mike Schilli E<lt>m@perlmeister.comE<gt>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
diff --git a/lib/Net/Amazon/Request/Similar.pm b/lib/Net/Amazon/Request/Similar.pm
deleted file mode 100644
index c5b5a53..0000000
--- a/lib/Net/Amazon/Request/Similar.pm
+++ /dev/null
@@ -1,95 +0,0 @@
-######################################################################
-package Net::Amazon::Request::Similar;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Request);
-
-our $AMZN_XML_URL     = "http://xml.amazon.com/onca/xml3";
-
-##################################################
-sub amzn_xml_url {
-##################################################
-    return $AMZN_XML_URL;
-}
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    # For backwards compatibility
-    $class->_convert_option(\%options, 'asin', 'similar');
-
-    $class->_assert_options_defined(\%options, 'similar');
-
-    $class->_convert_option(\%options,
-                            'similar',
-                            'SimilaritySearch');
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Request::Similar - request class for 'Similarities Search'
-
-=head1 SYNOPSIS
-
-  use Net::Amazon;
-  use Net::Amazon::Request::Similar;
-
-  my $ua = Net::Amazon->new(
-      token       => 'YOUR_AMZN_TOKEN'
-  );
-
-  my $req = Net::Amazon::Request::Similar->new( 
-      similar => 'B00005B6TL',
-  );
-
-    # Response is of type Net::Amazon::Response::Similar
-  my $resp = $ua->request($req);
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Request::Similar> is a class used to request
-so-called I<Similarities Searches> from the Amazon web service.
-
-The C<asin> parameter specifies the ASIN of the item which you want
-to get similar items for.
-
-Upon success, the response's C<properties()> method will return a list
-of C<Net::Amazon::Property::*> objects.
-
-=head2 METHODS
-
-=over 4
-
-=item new(similar => $asin)
-
-Constructs a new C<Net::Amazon::Request::Similar> object.
-
-=back
-
-Check L<Net::Amazon::Request> for common request parameters not listed here.
-
-=head1 SEE ALSO
-
-=head1 AUTHOR
-
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2003 by Mike Schilli E<lt>m@perlmeister.comE<gt>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
diff --git a/lib/Net/Amazon/Request/Sort.pm b/lib/Net/Amazon/Request/Sort.pm
deleted file mode 100644
index 059845d..0000000
--- a/lib/Net/Amazon/Request/Sort.pm
+++ /dev/null
@@ -1,246 +0,0 @@
-=pod
-
-=head1 SORT TYPES
-
-Search results can be sorted in various ways, depending on the type of
-product returned by the search.  If a sort parameter isn't specified in
-the request, the results will be ordered as if the +salesrank value is
-specified.
-
-=head2 Sorting Books Results
-
-   +---------------------------------------------------+
-   | Sort Type               | Value                   |
-   |-------------------------+-------------------------+
-   | Featured Items          | +pmrank                 |
-   |-------------------------+-------------------------+
-   | Bestselling             | +salesrank              |
-   |-------------------------+-------------------------+
-   | Average Customer Review | +reviewrank             |
-   |-------------------------+-------------------------+
-   | Price (Low to High)     | +pricerank              |
-   |-------------------------+-------------------------+
-   | Price (High to Low)     | +inverse-pricerank      |
-   |-------------------------+-------------------------+
-   | Publication Date        | +daterank               |
-   |-------------------------+-------------------------+
-   | Alphabetical (A-Z)      | +titlerank              |
-   |-------------------------+-------------------------+
-   | Alphabetical (Z-A)      | -titlerank              |
-   +---------------------------------------------------+
-
-=head2 Sorting Software Results
-
-   +---------------------------------------------------+
-   | Sort Type               | Value                   |
-   |-------------------------+-------------------------+
-   | Featured items          | +pmrank                 |
-   |-------------------------+-------------------------+
-   | Bestselling             | +salesrank              |
-   |-------------------------+-------------------------+
-   | Alphabetical            | +titlerank              |
-   |-------------------------+-------------------------+
-   | Price (High to Low)     | +price                  |
-   |-------------------------+-------------------------+
-   | Price (Low to High)     | -price                  |
-   +---------------------------------------------------+
-
-=head2 Sorting Outdoor Living Results
-
-   +---------------------------------------------------+
-   | Sort Type               | Value                   |
-   |-------------------------+-------------------------+
-   | Featured Items          | +psrank                 |
-   |-------------------------+-------------------------+
-   | Bestselling             | +salesrank              |
-   |-------------------------+-------------------------+
-   | Alphabetical (A-Z)      | +titlerank              |
-   |-------------------------+-------------------------+
-   | Alphabetical (Z-A)      | -titlerank              |
-   |-------------------------+-------------------------+
-   | Manufacturer (A-Z)      | +manufactrank           |
-   |-------------------------+-------------------------+
-   | Manufacturer (Z-A)      | -manufactrank           |
-   |-------------------------+-------------------------+
-   | Price (Low to High)     | +price                  |
-   |-------------------------+-------------------------+
-   | Price (High to Low)     | -price                  |
-   +---------------------------------------------------+
-
-=head2 Sorting Tools Results
-
-   +---------------------------------------------------+
-   | Sort Type               | Value                   |
-   |-------------------------+-------------------------+
-   | Featured Items          | +psrank                 |
-   |-------------------------+-------------------------+
-   | Bestselling             | +salesrank              |
-   |-------------------------+-------------------------+
-   | Alphabetical (A-Z)      | +titlerank              |
-   |-------------------------+-------------------------+
-   | Alphabetical (Z-A)      | -titlerank              |
-   |-------------------------+-------------------------+
-   | Manufacturer (A-Z)      | +manufactrank           |
-   |-------------------------+-------------------------+
-   | Manufacturer (Z-A)      | -manufactrank           |
-   |-------------------------+-------------------------+
-   | Price (Low to High)     | +price                  |
-   |-------------------------+-------------------------+
-   | Price (High to Low)     | -price                  |
-   +---------------------------------------------------+
-
-=head2 Sorting Camera and Photo Results
-
-   +---------------------------------------------------+
-   | Sort Type               | Value                   |
-   |-------------------------+-------------------------+
-   | Featured Items          | +pmrank                 |
-   |-------------------------+-------------------------+
-   | Bestselling             | +salesrank              |
-   |-------------------------+-------------------------+
-   | Alphabetical (A-Z)      | +titlerank              |
-   |-------------------------+-------------------------+
-   | Alphabetical (Z-A)      | -titlerank              |
-   +---------------------------------------------------+
-
-=head2 Sorting Computers Results
-
-   +---------------------------------------------------+
-   | Sort Type               | Value                   |
-   |-------------------------+-------------------------+
-   | Featured Items          | +psrank                 |
-   |-------------------------+-------------------------+
-   | Bestselling             | +salesrank              |
-   |-------------------------+-------------------------+
-   | Alphabetical (A-Z)      | +titlerank              |
-   |-------------------------+-------------------------+
-   | Alphabetical (Z-A)      | -titlerank              |
-   +---------------------------------------------------+
-
-=head2 Sorting Video Games Results
-
-   +---------------------------------------------------+
-   | Sort Type               | Value                   |
-   |-------------------------+-------------------------+
-   | Featured Items          | +pmrank                 |
-   |-------------------------+-------------------------+
-   | Bestselling             | +salesrank              |
-   |-------------------------+-------------------------+
-   | Alphabetical            | +titlerank              |
-   |-------------------------+-------------------------+
-   | Price (Low to High)     | +price                  |
-   |-------------------------+-------------------------+
-   | Price (High to Low)     | -price                  |
-   +---------------------------------------------------+
-
-=head2 Sorting Music Results
-
-   +---------------------------------------------------+
-   | Sort Type               | Value                   |
-   |-------------------------+-------------------------+
-   | Featured Items          | +psrank                 |
-   |-------------------------+-------------------------+
-   | Bestselling             | +salesrank              |
-   |-------------------------+-------------------------+
-   | Artist Name             | +artistrank             |
-   |-------------------------+-------------------------+
-   | Original Release Date   | +orig-rel-date          |
-   |-------------------------+-------------------------+
-   | Alphabetical            | +titlerank              |
-   +---------------------------------------------------+
-
-=head2 Sorting Office Products Results
-
-   +---------------------------------------------------+
-   | Sort Type               | Value                   |
-   |-------------------------+-------------------------+
-   | Featured Items          | +pmrank                 |
-   |-------------------------+-------------------------+
-   | Bestselling             | +salesrank              |
-   |-------------------------+-------------------------+
-   | Alphabetical (A-Z)      | +titlerank              |
-   |-------------------------+-------------------------+
-   | Alphabetical (Z-A)      | -titlerank              |
-   |-------------------------+-------------------------+
-   | Price (Low to High)     | +price                  |
-   |-------------------------+-------------------------+
-   | Price (High to Low)     | -price                  |
-   |-------------------------+-------------------------+
-   | Review                  | +reviewrank             |
-   +---------------------------------------------------+
-
-=head2 Sorting Video Results
-
-   +---------------------------------------------------+
-   | Sort Type               | Value                   |
-   |-------------------------+-------------------------+
-   | Featured Items          | +psrank                 |
-   |-------------------------+-------------------------+
-   | Bestselling             | +salesrank              |
-   |-------------------------+-------------------------+
-   | Alphabetical            | +titlerank              |
-   +---------------------------------------------------+
-
-=head2 Sorting Electronics Results
-
-   +---------------------------------------------------+
-   | Type                    | Value                   |
-   |-------------------------+-------------------------+
-   | Featured Items          | +pmrank                 |
-   |-------------------------+-------------------------+
-   | Bestselling             | +salesrank              |
-   |-------------------------+-------------------------+
-   | Alphabetical            | +titlerank              |
-   |-------------------------+-------------------------+
-   | Review                  | +reviewrank             |
-   +---------------------------------------------------+
-
-=head2 Sorting DVDs Results
-
-   +---------------------------------------------------+
-   | Type                    | Value                   |
-   |-------------------------+-------------------------+
-   | Bestselling             | +salesrank              |
-   |-------------------------+-------------------------+
-   | Alphabetical            | +titlerank              |
-   +---------------------------------------------------+
-
-=head2 Sorting Kitchen Results
-
-   +---------------------------------------------------+
-   | Type                    | Value                   |
-   |-------------------------+-------------------------+
-   | Featured Items          | +pmrank                 |
-   |-------------------------+-------------------------+
-   | Bestselling             | +salesrank              |
-   |-------------------------+-------------------------+
-   | Alphabetical (A-Z)      | +titlerank              |
-   |-------------------------+-------------------------+
-   | Alphabetical (Z-A)      | -titlerank              |
-   |-------------------------+-------------------------+
-   | Manufacturer (A-Z)      | +manufactrank           |
-   |-------------------------+-------------------------+
-   | Manufacturer (Z-A)      | -manufactrank           |
-   |-------------------------+-------------------------+
-   | Price (Low to High)     | +price                  |
-   |-------------------------+-------------------------+
-   | Price (High to Low)     | -price                  |
-   +---------------------------------------------------+
-
-=head2 Sorting Toys Results
-
-   +---------------------------------------------------+
-   |  Type                   | Value                   |
-   |-------------------------+-------------------------+
-   | Featured Items          | +pmrank                 |
-   |-------------------------+-------------------------+
-   | Bestselling             | +salesrank              |
-   |-------------------------+-------------------------+
-   | Price (Low to High)     | +pricerank              |
-   |-------------------------+-------------------------+
-   | Price (High to Low)     | +inverse-pricerank      |
-   |-------------------------+-------------------------+
-   | Alphabetical (A-Z)      | +titlerank              |
-   +---------------------------------------------------+
-
-=cut
diff --git a/lib/Net/Amazon/Request/TextStream.pm b/lib/Net/Amazon/Request/TextStream.pm
deleted file mode 100644
index 62a0717..0000000
--- a/lib/Net/Amazon/Request/TextStream.pm
+++ /dev/null
@@ -1,76 +0,0 @@
-######################################################################
-package Net::Amazon::Request::TextStream;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Request);
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    $class->_assert_options_defined(\%options,
-                                    'textstream');
-
-    $class->_convert_option(\%options,
-                            'textstream',
-                            'TextStreamSearch');
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Request::TextStream - request class for text stream search
-
-=head1 SYNOPSIS
-
-  use Net::Amazon;
-  use Net::Amazon::Request::TextStream;
-
-  my $ua = Net::Amazon->new(
-      token       => 'YOUR_AMZN_TOKEN'
-  );
-
-  my $req = Net::Amazon::Request::TextStream->new( 
-      textstream => 'Here is some text that mentions the Rolling Stones.',
-  );
-
-  # Response is of type Net::Amazon::Response::TextStream
-  my $resp = $ua->request($req);
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Request::TextStream> is a class used to perform a search on
-a block of text. Amazon extracts keywords from the given block of text,
-but note that conjunctions and helper words, such as "and", "or", "the",
-etc. are not excluded, so strip them out yourself if need be.
-
-TextStream searching is only available for the US service.
-
-Upon success, the response's C<properties()> method will return a list
-of C<Net::Amazon::Property::*> objects.
-
-=head2 METHODS
-
-=over 4
-
-=item new(textstream => $text)
-
-Constructs a new C<Net::Amazon::Request::TextStream> object, used to query
-the Amazon web service with a block of text.
-
-=back
-
-Check L<Net::Amazon::Request> for common request parameters not listed here.
-
-=head1 SEE ALSO
-
-=cut
diff --git a/lib/Net/Amazon/Request/UPC.pm b/lib/Net/Amazon/Request/UPC.pm
deleted file mode 100644
index ae77645..0000000
--- a/lib/Net/Amazon/Request/UPC.pm
+++ /dev/null
@@ -1,94 +0,0 @@
-######################################################################
-package Net::Amazon::Request::UPC;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Request);
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    $class->_assert_options_defined(\%options, 'upc');
-
-    $class->_convert_option(\%options, 
-                            'upc', 
-                            'UpcSearch');
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Request::UPC - request class for UPC search
-
-=head1 SYNOPSIS
-
-  use Net::Amazon;
-  use Net::Amazon::Request::UPC;
-
-  my $ua = Net::Amazon->new(
-      token       => 'YOUR_AMZN_TOKEN'
-  );
-
-  my $req = Net::Amazon::Request::UPC->new( 
-      upc  => '724381198421',
-      mode => 'music',        
-
-  );
-
-    # Response is of type Net::Amazon::Response::UPC
-  my $resp = $ua->request($req);
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Request::UPC> is a class used to submit UPC (product barcode) 
-search requests to the Amazon web service.
-
-The UPC number to search for is specified in the C<upc> parameter.
-It currently works with the following values of the C<mode> parameter:
-C<music>, 
-C<classical>,
-C<software>,
-C<dvd>, 
-C<video>,
-C<vhs>, 
-C<electronics>,
-C<pc-hardware>, and 
-C<photo>.
-
-Upon success, the response's C<properties()> method will return a single
-C<Net::Amazon::Property::Music> object.
-
-=head2 METHODS
-
-=over 4
-
-=item new(upc => $upc)
-
-Constructs a new C<Net::Amazon::Request::UPC> object, used to query
-the Amazon web service for an item with the given UPC number.
-
-=back
-
-=head1 SEE ALSO
-
-=head1 AUTHOR
-
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2003 by Mike Schilli E<lt>m@perlmeister.comE<gt>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
diff --git a/lib/Net/Amazon/Request/Wishlist.pm b/lib/Net/Amazon/Request/Wishlist.pm
deleted file mode 100644
index 824d5d4..0000000
--- a/lib/Net/Amazon/Request/Wishlist.pm
+++ /dev/null
@@ -1,89 +0,0 @@
-######################################################################
-package Net::Amazon::Request::Wishlist;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Request);
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    # For backwards compatibility:
-    $class->_convert_option(\%options, 'id', 'wishlist');
-
-    $class->_assert_options_defined(\%options, 'wishlist');
-
-    $class->_convert_option(\%options,
-                            'wishlist',
-                            'WishlistSearch');
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Request::Wishlist - request class for wishlist search
-
-=head1 SYNOPSIS
-
-  use Net::Amazon;
-  use Net::Amazon::Request::Wishlist;
-
-  my $ua = Net::Amazon->new(
-      token       => 'YOUR_AMZN_TOKEN'
-  );
-
-  my $req = Net::Amazon::Request::Wishlist->new( 
-      wishlist => '1XL5DWOUFMFVJ',
-  );
-
-    # Response is of type Net::Amazon::Response::Wishlist
-  my $resp = $ua->request($req);
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Request::Wishlist> is a class used to request
-a specified wishlist.
-
-The wishlist ID (can be found as parameters in URLs when a customer's
-Amazon wishlist is being pulled up) is specified in the C<id> parameter.
-
-Upon success, the response's C<properties()> method will return a list
-of C<Net::Amazon::Property::*> objects.
-
-=head2 METHODS
-
-=over 4
-
-=item new(wishlist => $id)
-
-Constructs a new C<Net::Amazon::Request::Wishlist> object, used to query
-the Amazon web service for a specific wishlist, identified by the wishlist
-ID.
-
-=back
-
-Check L<Net::Amazon::Request> for common request parameters not listed here.
-
-=head1 SEE ALSO
-
-=head1 AUTHOR
-
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2003 by Mike Schilli E<lt>m@perlmeister.comE<gt>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
diff --git a/lib/Net/Amazon/Response.pm b/lib/Net/Amazon/Response.pm
deleted file mode 100644
index 6147e0e..0000000
--- a/lib/Net/Amazon/Response.pm
+++ /dev/null
@@ -1,214 +0,0 @@
-######################################################################
-package Net::Amazon::Response;
-######################################################################
-use warnings;
-use strict;
-
-use base qw(Net::Amazon);
-
-use Text::Wrap qw($columns wrap);
-use XML::Simple;
-
-our @FORCE_ARRAY_FIELDS = ();
-
-__PACKAGE__->make_accessor($_) for qw(
-  status messages items xmlref total_results);
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    my $self = {
-        status        => "",
-        messages      => [],
-        items         => [],
-        xmlref        => {},
-        total_results => undef,
-    };
-
-    bless $self, $class;
-}
-
-sub message {
-  my($self) = @_;
-
-  return join(";",@{$self->{messages}});
-}
-
-###########################################
-sub is_success {
-###########################################
-    my($self) = @_;
-
-    return $self->{status} ? 1 : "";
-}
-
-###########################################
-sub is_error {
-###########################################
-    my($self) = @_;
-
-    return !$self->is_success();
-}
-
-###########################################
-sub push_item {
-###########################################
-    my($self, $item) = @_;
-
-    push @{$self->{items}}, $item;
-}
-
-###########################################
-sub as_string {
-###########################################
-    my($self) = @_;
-
-    return Data::Dumper::Dumper($self);
-}
-
-###########################################
-sub list_as_string {
-###########################################
-    my($self, @properties) = @_;
-
-    my $full = "";
-
-        # Column with
-    $columns   = 60;
-    my $bullet = 1;
-
-    foreach my $property (@properties) {
-        $full .= "\n" if $full;
-        my $bullet_string = sprintf("[%d]%s", 
-                                    $bullet, (" " x (3-length($bullet))));
-        $full .= wrap("", "     ", $bullet_string . $property->as_string());
-        $bullet++;
-    }
-
-    return $full;
-}
-
-##################################################
-sub properties {
-##################################################
-    my($self) = @_;
-
-    my @properties = ();
-
-    if($self->is_success && ref($self->{xmlref}->{Details}) eq 'ARRAY') {
-        foreach my $xmlref (@{$self->{xmlref}->{Details}}) {
-            my $property = Net::Amazon::Property::factory(xmlref => $xmlref);
-            push @properties, $property;
-        }
-    }
-
-    if(wantarray) {
-        return (@properties);
-    }
-
-    if(@properties) {
-            # Scalar context and we've got results. Return the first one.
-        return $properties[0];
-    }
-
-        # Scalar context and we don't have anything.
-    return undef;
-}
-
-##################################################
-sub xml_parse {
-##################################################
-    my($self, $xml) = @_;
-
-    my $xs = XML::Simple->new();
-    return $xs->XMLin($xml, ForceArray => [ @FORCE_ARRAY_FIELDS ]);
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Response - Baseclass for responses from Amazon's web service
-
-=head1 SYNOPSIS
-
-    $resp = $ua->request($request);
-
-    if($resp->is_success()) { 
-        print $resp->as_string();
-    }
-
-    if($resp->is_error()) {
-        print $resp->message();
-    }
- 
-    if($resp->is_success()) { 
-        for my $property ($resp->properties) {
-            print $property->as_string(), "\n";
-        }
-    }
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Response> is the baseclass for responses coming back 
-from the useragent's C<request> method. Responses are typically
-not of type C<Net::Amazon::Response> but one of its subclasses
-C<Net::Amazon::Response::*>. However, for basic error handling and
-dumping content, C<Net::Amazon::Response>'s methods are typically used,
-because we typically don't know what type of object we're 
-actually dealing with.
-
-=head2 METHODS
-
-=over 4
-
-=item is_success()
-
-Returns true if the request was successful. This doesn't mean any objects
-have been found, it just indicates a successful roundtrip.
-
-=item is_error()
-
-Returns true if an error occurred. Use C<message()> to determine what 
-kind of error.
-
-=item properties()
-
-Returns the list of C<Net::Amazon::Property> objects which were found
-by the query.
-
-=item as_string()
-
-Dumps the content of the response.
-
-=item message()
-
-Returns the error message as a string in case an error occurred. In case
-several errors occurred, they're stringed together. Look up C<messages()>
-if you need them separated.
-
-=item messages()
-
-Returns all error messages for a response as a reference to an array
-of string messages.
-
-=back
-
-=head1 SEE ALSO
-
-=head1 AUTHOR
-
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2003 by Mike Schilli E<lt>m@perlmeister.comE<gt>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
diff --git a/lib/Net/Amazon/Response/ASIN.pm b/lib/Net/Amazon/Response/ASIN.pm
deleted file mode 100644
index 32bad76..0000000
--- a/lib/Net/Amazon/Response/ASIN.pm
+++ /dev/null
@@ -1,28 +0,0 @@
-######################################################################
-package Net::Amazon::Response::ASIN;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Response);
-
-use Net::Amazon::Property;
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-##################################################
-sub as_string {
-##################################################
-    my($self) = @_;
-
-    return $self->SUPER::list_as_string($self->properties);
-}
-
-1;
diff --git a/lib/Net/Amazon/Response/Artist.pm b/lib/Net/Amazon/Response/Artist.pm
deleted file mode 100644
index 0ee653b..0000000
--- a/lib/Net/Amazon/Response/Artist.pm
+++ /dev/null
@@ -1,29 +0,0 @@
-######################################################################
-package Net::Amazon::Response::Artist;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Response);
-
-use Net::Amazon::Property;
-use Data::Dumper;
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-##################################################
-sub as_string {
-##################################################
-    my($self) = @_;
-
-    return $self->SUPER::list_as_string($self->properties);
-}
-
-1;
diff --git a/lib/Net/Amazon/Response/Blended.pm b/lib/Net/Amazon/Response/Blended.pm
deleted file mode 100644
index 3c75ded..0000000
--- a/lib/Net/Amazon/Response/Blended.pm
+++ /dev/null
@@ -1,73 +0,0 @@
-######################################################################
-package Net::Amazon::Response::Blended;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Response);
-
-use Net::Amazon::Property;
-use XML::Simple;
-
-our @FORCE_ARRAY_FIELDS = qw(ProductLine);
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-##################################################
-sub as_string {
-##################################################
-    my($self) = @_;
-
-    return $self->SUPER::list_as_string($self->properties);
-}
-
-##################################################
-sub xmlref_add {
-##################################################
-    my($self, $xmlref) = @_;
-
-    my $nof_items_added = 0;
-
-    unless(ref($self->{xmlref}) eq "HASH" &&
-           ref($self->{xmlref}->{Details}) eq "ARRAY") {
-        $self->{xmlref}->{Details} = [];
-    }
-
-    if ($xmlref->{ProductLine} && (ref($xmlref->{ProductLine}) eq "ARRAY")) {
-        my @lines = @{$xmlref->{ProductLine}}; # Copy the lines
-            # sort the copies by relevance
-        @lines = sort { $a->{RelevanceRank} <=> $b->{RelevanceRank} } @lines;
-
-        foreach (@lines) {
-              next unless $_->{ProductInfo}->{Details};
-              my $details = $_->{ProductInfo}->{Details};
-              if (ref($details) eq "ARRAY") {
-                  push @{$self->{xmlref}->{Details}}, @$details;
-                  $nof_items_added += scalar @$details;
-              } else {
-                  push @{$self->{xmlref}->{Details}}, $details;
-                  $nof_items_added++;
-              }
-        }
-    }
-
-    return $nof_items_added;
-}
-
-##################################################
-sub xml_parse {
-##################################################
-    my($self, $xml) = @_;
-
-    my $xs = XML::Simple->new();
-    return $xs->XMLin($xml, ForceArray => [ @FORCE_ARRAY_FIELDS ]);
-}
-
-1;
diff --git a/lib/Net/Amazon/Response/BrowseNode.pm b/lib/Net/Amazon/Response/BrowseNode.pm
deleted file mode 100644
index 8f40a63..0000000
--- a/lib/Net/Amazon/Response/BrowseNode.pm
+++ /dev/null
@@ -1,29 +0,0 @@
-######################################################################
-package Net::Amazon::Response::BrowseNode;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Response);
-
-use Net::Amazon::Property;
-use Data::Dumper;
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-##################################################
-sub as_string {
-##################################################
-    my($self) = @_;
-
-    return $self->SUPER::list_as_string($self->properties);
-}
-
-1;
diff --git a/lib/Net/Amazon/Response/Exchange.pm b/lib/Net/Amazon/Response/Exchange.pm
deleted file mode 100644
index 56852fe..0000000
--- a/lib/Net/Amazon/Response/Exchange.pm
+++ /dev/null
@@ -1,81 +0,0 @@
-######################################################################
-package Net::Amazon::Response::Exchange;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Response);
-
-use Net::Amazon::Property;
-use Net::Amazon::Result::Seller::Listing;
-use Log::Log4perl qw(:easy);
-
-__PACKAGE__->make_array_accessor($_) for qw(listings);
-
-##################################################
-sub new {
-##################################################
-   my($class, %options) = @_;
-
-   my $self = $class->SUPER::new(%options);
-
-   bless $self, $class;   # reconsecrate
-}
-
-##################################################
-sub result {
-##################################################
-    my($self) = @_;
-
-    if($self->is_success()) {
-        return Net::Amazon::Result::Seller::Listing->new(
-            xmlref => $self->{xmlref}->{ListingProductDetails}->[0],
-        );
-    }
-
-    return undef;
-}
-
-##################################################
-sub as_string {
-##################################################
-   my($self) = @_;
-
-   return "TODO: as_string not defined yet in ", __PACKAGE__;
-}
-
-##################################################
-sub xmlref_add {
-##################################################
-    my($self, $xmlref) = @_;
-
-    my $nof_items_added = 0;
-
-    unless(ref($self->{xmlref}) eq "HASH" &&
-        ref($self->{xmlref}->{ListingProductDetails}) eq "ARRAY") {
-        $self->{xmlref}->{Details} = [];
-    }
-
-    if(ref($xmlref->{ListingProductDetails}) eq "ARRAY") {
-            # Is it an array of items?
-        push @{$self->{xmlref}->{ListingProductDetails}},
-             @{$xmlref->{ListingProductDetails}};
-        $nof_items_added = scalar @{$xmlref->{ListingProductDetails}};
-    } else {
-            # It is a single item
-        push @{$self->{xmlref}->{ListingProductDetails}},
-             $xmlref->{ListingProductDetails};
-        $nof_items_added = 1;
-    }
-
-    return $nof_items_added;
-}
-
-##################################################
-sub properties {
-##################################################
-    my($self) = @_;
-
-    die "properties() not defined in ", __PACKAGE__, ". Use result() instead";
-}
-
-1;
diff --git a/lib/Net/Amazon/Response/Keyword.pm b/lib/Net/Amazon/Response/Keyword.pm
deleted file mode 100644
index f6277d6..0000000
--- a/lib/Net/Amazon/Response/Keyword.pm
+++ /dev/null
@@ -1,29 +0,0 @@
-######################################################################
-package Net::Amazon::Response::Keyword;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Response);
-
-use Net::Amazon::Property;
-use Data::Dumper;
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-##################################################
-sub as_string {
-##################################################
-    my($self) = @_;
-
-    return $self->SUPER::list_as_string($self->properties);
-}
-
-1;
diff --git a/lib/Net/Amazon/Response/Manufacturer.pm b/lib/Net/Amazon/Response/Manufacturer.pm
deleted file mode 100644
index 97ceebf..0000000
--- a/lib/Net/Amazon/Response/Manufacturer.pm
+++ /dev/null
@@ -1,29 +0,0 @@
-######################################################################
-package Net::Amazon::Response::Manufacturer;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Response);
-
-use Net::Amazon::Property;
-use Data::Dumper;
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-##################################################
-sub as_string {
-##################################################
-    my($self) = @_;
-
-    return $self->SUPER::list_as_string($self->properties);
-}
-
-1;
diff --git a/lib/Net/Amazon/Response/Power.pm b/lib/Net/Amazon/Response/Power.pm
deleted file mode 100644
index 88cdd2d..0000000
--- a/lib/Net/Amazon/Response/Power.pm
+++ /dev/null
@@ -1,28 +0,0 @@
-######################################################################
-package Net::Amazon::Response::Power;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Response);
-
-use Net::Amazon::Property;
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-##################################################
-sub as_string {
-##################################################
-    my($self) = @_;
-
-    return $self->SUPER::list_as_string($self->properties);
-}
-
-1;
diff --git a/lib/Net/Amazon/Response/Seller.pm b/lib/Net/Amazon/Response/Seller.pm
deleted file mode 100644
index f33ed50..0000000
--- a/lib/Net/Amazon/Response/Seller.pm
+++ /dev/null
@@ -1,78 +0,0 @@
-#############################################
-package Net::Amazon::Response::Seller;
-#############################################
-use base qw(Net::Amazon::Response);
-
-use Net::Amazon::Result::Seller;
-use Data::Dumper;
-use Log::Log4perl qw(:easy);
-
-##############################
-sub new {
-##############################
-    my($class, %options) = @_;
-   
-    my $self = $class->SUPER::new(%options);
-    bless $self, $class;   # reconsecrate
-}
-
-##################################################
-sub result {
-##################################################
-    my($self) = @_;
-
-    if($self->is_success()) {
-        DEBUG "Calling Seller constructor with ", Dumper($self);
-        return Net::Amazon::Result::Seller->new(
-            xmlref => $self->{xmlref}->{SellerSearchDetails}->[0],
-        );
-    }
-
-    return undef;
-}
-
-##################################################
-sub properties {
-##################################################
-    my($self) = @_;
-
-    die "properties() not defined in ", __PACKAGE__, ". Use result() instead";
-}
-
-##################################################
-sub as_string {
-##################################################
-    my($self) = @_;
-
-    return $self->result()->as_string();
-}
-
-##################################################
-sub xmlref_add {
-##################################################
-    my($self, $xmlref) = @_;
-
-    my $nof_items_added = 0;
-
-    unless(ref($self->{xmlref}) eq "HASH" &&
-        ref($self->{xmlref}->{SellerSearchDetails}) eq "ARRAY") {
-        $self->{xmlref}->{Details} = [];
-    }
-
-    if(ref($xmlref->{SellerSearchDetails}) eq "ARRAY") {
-            # Is it an array of items?
-        push @{$self->{xmlref}->{SellerSearchDetails}},
-             @{$xmlref->{SellerSearchDetails}};
-        $nof_items_added = scalar @{$xmlref->{SellerSearchDetails}};
-    } else {
-            # It is a single item
-        push @{$self->{xmlref}->{SellerSearchDetails}},
-             $xmlref->{SellerSearchDetails};
-        $nof_items_added = 1;
-    }
-
-    #DEBUG("xmlref_add (after):", Data::Dumper::Dumper($self));
-    return $nof_items_added;
-} 
-
-1;
diff --git a/lib/Net/Amazon/Response/Similar.pm b/lib/Net/Amazon/Response/Similar.pm
deleted file mode 100644
index 27add88..0000000
--- a/lib/Net/Amazon/Response/Similar.pm
+++ /dev/null
@@ -1,28 +0,0 @@
-######################################################################
-package Net::Amazon::Response::Similar;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Response);
-
-use Net::Amazon::Property;
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-##################################################
-sub as_string {
-##################################################
-    my($self) = @_;
-
-    return $self->SUPER::list_as_string($self->properties);
-}
-
-1;
diff --git a/lib/Net/Amazon/Response/TextStream.pm b/lib/Net/Amazon/Response/TextStream.pm
deleted file mode 100644
index 0cee872..0000000
--- a/lib/Net/Amazon/Response/TextStream.pm
+++ /dev/null
@@ -1,28 +0,0 @@
-######################################################################
-package Net::Amazon::Response::TextStream;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Response);
-
-use Net::Amazon::Property;
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-##################################################
-sub as_string {
-##################################################
-    my($self) = @_;
-
-    return $self->SUPER::list_as_string($self->properties);
-}
-
-1;
diff --git a/lib/Net/Amazon/Response/UPC.pm b/lib/Net/Amazon/Response/UPC.pm
deleted file mode 100644
index 4fba4ad..0000000
--- a/lib/Net/Amazon/Response/UPC.pm
+++ /dev/null
@@ -1,40 +0,0 @@
-######################################################################
-package Net::Amazon::Response::UPC;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Response);
-
-use Net::Amazon::Property;
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-##################################################
-sub as_string {
-##################################################
-    my($self) = @_;
-
-    my($property) = $self->properties;
-    return $property->as_string();
-}
-
-##################################################
-sub properties {
-##################################################
-    my($self) = @_;
-
-    my $property = Net::Amazon::Property::factory(
-        xmlref => $self->{xmlref}->{Details}->[0]);
-
-    return ($property);
-}
-
-1;
diff --git a/lib/Net/Amazon/Response/Wishlist.pm b/lib/Net/Amazon/Response/Wishlist.pm
deleted file mode 100644
index 15fd999..0000000
--- a/lib/Net/Amazon/Response/Wishlist.pm
+++ /dev/null
@@ -1,29 +0,0 @@
-######################################################################
-package Net::Amazon::Response::Wishlist;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon::Response);
-
-use Net::Amazon::Property;
-use Data::Dumper;
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    my $self = $class->SUPER::new(%options);
-
-    bless $self, $class;   # reconsecrate
-}
-
-##################################################
-sub as_string {
-##################################################
-    my($self) = @_;
-
-    return $self->SUPER::list_as_string($self->properties);
-}
-
-1;
diff --git a/lib/Net/Amazon/Result/Seller.pm b/lib/Net/Amazon/Result/Seller.pm
deleted file mode 100644
index cb876a6..0000000
--- a/lib/Net/Amazon/Result/Seller.pm
+++ /dev/null
@@ -1,130 +0,0 @@
-######################################################################
-package Net::Amazon::Result::Seller;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon);
-
-use Data::Dumper;
-use Log::Log4perl qw(:easy);
-use Net::Amazon::Result::Seller::Listing;
-
-our @DEFAULT_ATTRIBUTES = qw(StoreName SellerNickname 
-                             NumberOfOpenListings StoreId);
-__PACKAGE__->make_accessor($_) for @DEFAULT_ATTRIBUTES;
-__PACKAGE__->make_array_accessor($_) for qw(listings);
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    if(!$options{xmlref}) {
-        die "Mandatory param xmlref missing";
-    }
-
-    my @listings = ();
-
-    my $self = { 
-        %options, 
-               };
-
-    bless $self, $class;
-
-        # Set default attributes
-    for my $attr (@DEFAULT_ATTRIBUTES) {
-        DEBUG "Setting attribute $attr to $options{xmlref}->{$attr}";
-        $self->$attr($options{xmlref}->{$attr});
-    }
-
-    for my $listing (@{$options{xmlref}->{ListingProductInfo}->{ListingProductDetails}}) {
-        push @listings, 
-             Net::Amazon::Result::Seller::Listing->new(
-                 xmlref => $listing);
-    }
-
-    $self->listings(\@listings);
-
-    return $self;
-}
-
-##################################################
-sub as_string {
-##################################################
-    my($self) = @_;
-
-    my $result = $self->StoreName() . 
-                 " (" .
-                 $self->SellerNickname() .
-                 "): " .
-                 $self->NumberOfOpenListings() .
-                 "";
-
-    return $result;
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Result::Seller - Class for Seller info
-
-=head1 SYNOPSIS
-
-  use Net::Amazon;
-
-  # ...
-
-  if($resp->is_success()) {
-      print $resp->result()->as_string();
-  }
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Result::Seller> is a container for results on a seller 
-search. It contains data on one particular seller (the one turned up by
-the previous search) and the listings this seller is currently running.
-
-=head2 METHODS
-
-=over 4
-
-=item StoreName()
-
-Name of the seller's store.
-
-=item SellerNickname()
-
-Seller's nickname.
-
-=item StoreId()
-
-ID of seller's store.
-
-=item NumberOfOpenListings()
-
-Number of listings the seller has currently open.
-
-=item listings()
-
-Returns an array of C<Net::Amazon::Result::Seller::Listing> objects.
-See the documentation of this class for details.
-
-=back
-
-=head1 SEE ALSO
-
-=head1 AUTHOR
-
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2004 by Mike Schilli E<lt>m@perlmeister.comE<gt>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
diff --git a/lib/Net/Amazon/Result/Seller/Listing.pm b/lib/Net/Amazon/Result/Seller/Listing.pm
deleted file mode 100644
index c09ec08..0000000
--- a/lib/Net/Amazon/Result/Seller/Listing.pm
+++ /dev/null
@@ -1,146 +0,0 @@
-######################################################################
-package Net::Amazon::Result::Seller::Listing;
-######################################################################
-use warnings;
-use strict;
-use base qw(Net::Amazon);
-
-use Data::Dumper;
-use Log::Log4perl qw(:easy);
-
-our @DEFAULT_ATTRIBUTES = qw(
-  ExchangeStartDate ExchangeConditionType
-  ExchangeAsin ExchangeSellerId ExchangeEndDate ExchangePrice
-  ExchangeSellerRating ExchangeStatus ExchangeId ExchangeTitle
-  ExchangeQuantityAllocated ExchangeQuantity ExchangeSellerCountry
-  ExchangeSellerState ExchangeSellerNickname ExchangeFeaturedCategory
-  ExchangeAvailability ExchangeOfferingType ListingId ExchangeCondition
-  ExchangeDescription
-);
-
-__PACKAGE__->make_accessor($_) for @DEFAULT_ATTRIBUTES;
-
-##################################################
-sub new {
-##################################################
-    my($class, %options) = @_;
-
-    if(!$options{xmlref}) {
-        die "Mandatory param xmlref missing";
-    }
-
-    my $self = { 
-        %options, 
-               };
-
-    bless $self, $class;
-
-    DEBUG "Calling Listing with xmlref=", Dumper($options{xmlref});
-
-        # Set default attributes
-    for my $attr (@DEFAULT_ATTRIBUTES) {
-        $self->$attr($options{xmlref}->{$attr});
-    }
-
-    return $self;
-}
-
-##################################################
-sub as_string {
-##################################################
-    my($self) = @_;
-
-    my $result = 
-                 $self->ExchangeTitle() .
-                 " (" .
-                 $self->ExchangeAsin() . 
-                 "): " .
-                 $self->ExchangePrice() .
-                 "";
-
-    return $result;
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Net::Amazon::Result::Seller::Listing - Class for a single Listing of a Seller
-
-=head1 SYNOPSIS
-
-  for($seller_search_resp->result()->seller()->listings()) {
-      print $_->as_string(), "\n";
-  }
-
-=head1 DESCRIPTION
-
-C<Net::Amazon::Result::Seller::Listing> is a container for a single listing
-owned by a third-party seller, who is represented by a
-C<Net::Amazon::Result::Seller> object.
-
-An object of this class is also returned by an C<Exchange> request, using
-C<Net::Amazon::Response::Exchange>'s C<result> method.
-
-=head2 METHODS
-
-=over 4
-
-=item ExchangeStartDate()
-
-=item ExchangeConditionType()
-
-=item ExchangeAsin()
-
-=item ExchangeSellerId()
-
-=item ExchangeEndDate()
-
-=item ExchangePrice()
-
-=item ExchangeSellerRating()
-
-=item ExchangeStatus()
-
-=item ExchangeId()
-
-=item ExchangeTitle()
-
-=item ExchangeQuantityAllocated()
-
-=item ExchangeQuantity()
-
-=item ExchangeSellerCountry()
-
-=item ExchangeSellerState()
-
-=item ExchangeSellerNickname()
-
-=item ExchangeFeaturedCategory()
-
-=item ExchangeAvailability()
-
-=item ExchangeOfferingType()
-
-=item ListingId()
-
-=item ExchangeCondition()
-
-=back
-
-=head1 SEE ALSO
-
-=head1 AUTHOR
-
-Mike Schilli, E<lt>m@perlmeister.comE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2004 by Mike Schilli E<lt>m@perlmeister.comE<gt>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself. 
-
-=cut
diff --git a/lib/Template.pm b/lib/Template.pm
deleted file mode 100644
index bd56cc5..0000000
--- a/lib/Template.pm
+++ /dev/null
@@ -1,961 +0,0 @@
-#============================================================= -*-perl-*-
-#
-# Template
-#
-# DESCRIPTION
-#   Module implementing a simple, user-oriented front-end to the Template 
-#   Toolkit.
-#
-# AUTHOR
-#   Andy Wardley   <abw@andywardley.com>
-#
-# COPYRIGHT
-#   Copyright (C) 1996-2002 Andy Wardley.  All Rights Reserved.
-#   Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
-#
-#   This module is free software; you can redistribute it and/or
-#   modify it under the same terms as Perl itself.
-#
-# REVISION
-#   $Id: Template.pm,v 2.76 2004/01/13 15:27:35 abw Exp $
-#
-#========================================================================
- 
-package Template;
-use base qw( Template::Base );
-
-require 5.005;
-
-use strict;
-use vars qw( $VERSION $AUTOLOAD $ERROR $DEBUG $BINMODE );
-use Template::Base;
-use Template::Config;
-use Template::Constants;
-use Template::Provider;  
-use Template::Service;
-use File::Basename;
-use File::Path;
-
-## This is the main version number for the Template Toolkit.
-## It is extracted by ExtUtils::MakeMaker and inserted in various places.
-$VERSION     = '2.13';
-$ERROR       = '';
-$DEBUG       = 0;
-
-# we used to default to binary mode for all win32 files but that make
-# line endings strange, so we're turning it off and letting users set
-# it explicitly as an argument to process()
-# $BINMODE     = ($^O eq 'MSWin32') ? 1 : 0;
-$BINMODE     = 0 unless defined $BINMODE;
-
-# preload all modules if we're running under mod_perl
-Template::Config->preload() if $ENV{ MOD_PERL };
-
-
-#------------------------------------------------------------------------
-# process($input, \%replace, $output)
-#
-# Main entry point for the Template Toolkit.  The Template module 
-# delegates most of the processing effort to the underlying SERVICE
-# object, an instance of the Template::Service class.  
-#------------------------------------------------------------------------
-
-sub process {
-    my ($self, $template, $vars, $outstream, @opts) = @_;
-    my ($output, $error);
-    my $options = (@opts == 1) && UNIVERSAL::isa($opts[0], 'HASH')
-        ? shift(@opts) : { @opts };
-    
-    $options->{ binmode } = $BINMODE 
-        unless defined $options->{ binmode };
-
-    # we're using this for testing in t/output.t and t/filter.t so 
-    # don't remove it if you don't want tests to fail...
-    $self->DEBUG("set binmode\n") if $DEBUG && $options->{ binmode };
-
-    $output = $self->{ SERVICE }->process($template, $vars);
-    
-    if (defined $output) {
-        $outstream ||= $self->{ OUTPUT };
-        unless (ref $outstream) {
-            my $outpath = $self->{ OUTPUT_PATH };
-            $outstream = "$outpath/$outstream" if $outpath;
-        }	
-        
-        # send processed template to output stream, checking for error
-        return ($self->error($error))
-            if ($error = &_output($outstream, \$output, $options));
-        
-        return 1;
-    }
-    else {
-        return $self->error($self->{ SERVICE }->error);
-    }
-}
-
-
-#------------------------------------------------------------------------
-# service()
-#
-# Returns a reference to the the internal SERVICE object which handles
-# all requests for this Template object
-#------------------------------------------------------------------------
-
-sub service {
-    my $self = shift;
-    return $self->{ SERVICE };
-}
-
-
-#------------------------------------------------------------------------
-# context()
-#
-# Returns a reference to the the CONTEXT object withint the SERVICE 
-# object.
-#------------------------------------------------------------------------
-
-sub context {
-    my $self = shift;
-    return $self->{ SERVICE }->{ CONTEXT };
-}
-
-
-#========================================================================
-#                     -- PRIVATE METHODS --
-#========================================================================
-
-#------------------------------------------------------------------------
-# _init(\%config)
-#------------------------------------------------------------------------
-sub _init {
-    my ($self, $config) = @_;
-
-    # convert any textual DEBUG args to numerical form
-    my $debug = $config->{ DEBUG };
-    $config->{ DEBUG } = Template::Constants::debug_flags($self, $debug)
-        || return if defined $debug && $debug !~ /^\d+$/;
-    
-    # prepare a namespace handler for any CONSTANTS definition
-    if (my $constants = $config->{ CONSTANTS }) {
-        my $ns  = $config->{ NAMESPACE } ||= { };
-        my $cns = $config->{ CONSTANTS_NAMESPACE } || 'constants';
-        $constants = Template::Config->constants($constants)
-            || return $self->error(Template::Config->error);
-        $ns->{ $cns } = $constants;
-    }
-    
-    $self->{ SERVICE } = $config->{ SERVICE }
-        || Template::Config->service($config)
-        || return $self->error(Template::Config->error);
-    
-    $self->{ OUTPUT      } = $config->{ OUTPUT } || \*STDOUT;
-    $self->{ OUTPUT_PATH } = $config->{ OUTPUT_PATH };
-
-    return $self;
-}
-
-
-#------------------------------------------------------------------------
-# _output($where, $text)
-#------------------------------------------------------------------------
-
-sub _output {
-    my ($where, $textref, $options) = @_;
-    my $reftype;
-    my $error = 0;
-    
-    # call a CODE reference
-    if (($reftype = ref($where)) eq 'CODE') {
-        &$where($$textref);
-    }
-    # print to a glob (such as \*STDOUT)
-    elsif ($reftype eq 'GLOB') {
-        print $where $$textref;
-    }   
-    # append output to a SCALAR ref
-    elsif ($reftype eq 'SCALAR') {
-        $$where .= $$textref;
-    }
-    # push onto ARRAY ref
-    elsif ($reftype eq 'ARRAY') {
-        push @$where, $$textref;
-    }
-    # call the print() method on an object that implements the method
-    # (e.g. IO::Handle, Apache::Request, etc)
-    elsif (UNIVERSAL::can($where, 'print')) {
-        $where->print($$textref);
-    }
-    # a simple string is taken as a filename
-    elsif (! $reftype) {
-        local *FP;
-        # make destination directory if it doesn't exist
-        my $dir = dirname($where);
-        eval { mkpath($dir) unless -d $dir; };
-        if ($@) {
-            # strip file name and line number from error raised by die()
-            ($error = $@) =~ s/ at \S+ line \d+\n?$//;
-        }
-        elsif (open(FP, ">$where")) { 
-            binmode FP if $options->{ binmode };
-            print FP $$textref;
-            close FP;
-        }
-        else {
-            $error  = "$where: $!";
-        }
-    }
-    # give up, we've done our best
-    else {
-        $error = "output_handler() cannot determine target type ($where)\n";
-    }
-
-    return $error;
-}
-
-
-1;
-
-__END__
-
-
-#------------------------------------------------------------------------
-# IMPORTANT NOTE
-#   This documentation is generated automatically from source
-#   templates.  Any changes you make here may be lost.
-# 
-#   The 'docsrc' documentation source bundle is available for download
-#   from http://www.template-toolkit.org/docs.html and contains all
-#   the source templates, XML files, scripts, etc., from which the
-#   documentation for the Template Toolkit is built.
-#------------------------------------------------------------------------
-
-=head1 NAME
-
-Template - Front-end module to the Template Toolkit
-
-=head1 SYNOPSIS 
-
-  use Template;
-
-  # some useful options (see below for full list)
-  my $config = {
-      INCLUDE_PATH => '/search/path',  # or list ref
-      INTERPOLATE  => 1,               # expand "$var" in plain text
-      POST_CHOMP   => 1,               # cleanup whitespace 
-      PRE_PROCESS  => 'header',        # prefix each template
-      EVAL_PERL    => 1,               # evaluate Perl code blocks
-  };
-
-  # create Template object
-  my $template = Template->new($config);
-
-  # define template variables for replacement
-  my $vars = {
-      var1  => $value,
-      var2  => \%hash,
-      var3  => \@list,
-      var4  => \&code,
-      var5  => $object,
-  };
-
-  # specify input filename, or file handle, text reference, etc.
-  my $input = 'myfile.html';
-
-  # process input template, substituting variables
-  $template->process($input, $vars)
-      || die $template->error();
-
-=head1 DESCRIPTION
-
-This documentation describes the Template module which is the direct
-Perl interface into the Template Toolkit.  It covers the use of the
-module and gives a brief summary of configuration options and template
-directives.  Please see L<Template::Manual> for the complete reference
-manual which goes into much greater depth about the features and use
-of the Template Toolkit.  The L<Template::Tutorial> is also available
-as an introductory guide to using the Template Toolkit.
-
-=head1 METHODS
-
-=head2 new(\%config)
-
-The new() constructor method (implemented by the Template::Base base
-class) instantiates a new Template object.  A reference to a hash
-array of configuration items may be passed as a parameter.
-
-    my $tt = Template->new({
-	INCLUDE_PATH => '/usr/local/templates',
-	EVAL_PERL    => 1,
-    }) || die $Template::ERROR, "\n";
-
-A reference to a new Template object is returned, or undef on error.
-In the latter case, the error message can be retrieved by calling
-error() as a class method (e.g. C<Template-E<gt>error()>) or by
-examining the $ERROR package variable directly
-(e.g. C<$Template::ERROR>).
-
-    my $tt = Template->new(\%config)
-        || die Template->error(), "\n";
-
-    my $tt = Template->new(\%config)
-        || die $Template::ERROR, "\n";
-
-For convenience, configuration items may also be specified as a list
-of items instead of a hash array reference.  These are automatically
-folded into a hash array by the constructor.
-
-    my $tt = Template->new(INCLUDE_PATH => '/tmp', POST_CHOMP => 1)
-	|| die $Template::ERROR, "\n";
-
-=head2 process($template, \%vars, $output, %options)
-
-The process() method is called to process a template.  The first
-parameter indicates the input template as one of: a filename relative
-to INCLUDE_PATH, if defined; a reference to a text string containing
-the template text; or a file handle reference (e.g. IO::Handle or
-sub-class) or GLOB (e.g. \*STDIN), from which the template can be
-read.  A reference to a hash array may be passed as the second
-parameter, containing definitions of template variables.
-
-    $text = "[% INCLUDE header %]\nHello world!\n[% INCLUDE footer %]";
-
-    # filename
-    $tt->process('welcome.tt2')
-        || die $tt->error(), "\n";
-
-    # text reference
-    $tt->process(\$text)
-        || die $tt->error(), "\n";
-
-    # GLOB
-    $tt->process(\*DATA)
-        || die $tt->error(), "\n";
-
-    __END__
-    [% INCLUDE header %]
-    This is a template defined in the __END__ section which is 
-    accessible via the DATA "file handle".
-    [% INCLUDE footer %]
-
-By default, the processed template output is printed to STDOUT.  The
-process() method then returns 1 to indicate success.  A third
-parameter may be passed to the process() method to specify a different
-output location.  This value may be one of: a plain string indicating
-a filename which will be opened (relative to OUTPUT_PATH, if defined)
-and the output written to; a file GLOB opened ready for output; a
-reference to a scalar (e.g. a text string) to which output/error is
-appended; a reference to a subroutine which is called, passing the
-output as a parameter; or any object reference which implements a
-'print' method (e.g. IO::Handle, Apache::Request, etc.) which will 
-be called, passing the generated output as a parameter.
-
-Examples:
-
-    # output filename
-    $tt->process('welcome.tt2', $vars, 'welcome.html')
-        || die $tt->error(), "\n";
-
-    # reference to output subroutine
-    sub myout {
-	my $output = shift;
-	...
-    }
-    $tt->process('welcome.tt2', $vars, \&myout)
-        || die $tt->error(), "\n";
-
-    # reference to output text string
-    my $output = '';
-    $tt->process('welcome.tt2', $vars, \$output)
-        || die $tt->error(), "\n";
-    
-    print "output: $output\n";
-
-In an Apache/mod_perl handler:
-
-    sub handler {
-	my $req = shift;
-
-        ...
-
-	# direct output to Apache::Request via $req->print($output)
-	$tt->process($file, $vars, $req) || do {
-	    $req->log_reason($tt->error());
-	    return SERVER_ERROR;
-	};
-
-	return OK;
-    }
-
-After the optional third output argument can come an optional
-reference to a hash or a list of (name, value) pairs providing further
-options for the output.  The only option currently supported is
-"binmode" which, when set to any true value will ensure that files
-created (but not any existing file handles passed) will be set to
-binary mode.
-
-    # either: hash reference of options
-    $tt->process($infile, $vars, $outfile, { binmode => 1 })
-        || die $tt->error(), "\n";
-
-    # or: list of name, value pairs
-    $tt->process($infile, $vars, $outfile, binmode => 1)
-        || die $tt->error(), "\n";
-
-The OUTPUT configuration item can be used to specify a default output 
-location other than \*STDOUT.  The OUTPUT_PATH specifies a directory
-which should be prefixed to all output locations specified as filenames.
-
-    my $tt = Template->new({
-	OUTPUT      => sub { ... },       # default
-	OUTPUT_PATH => '/tmp',
-	...
-    }) || die Template->error(), "\n";
-
-    # use default OUTPUT (sub is called)
-    $tt->process('welcome.tt2', $vars)
-        || die $tt->error(), "\n";
-
-    # write file to '/tmp/welcome.html'
-    $tt->process('welcome.tt2', $vars, 'welcome.html')
-        || die $tt->error(), "\n";
-
-The process() method returns 1 on success or undef on error.  The error
-message generated in the latter case can be retrieved by calling the
-error() method.  See also L<CONFIGURATION SUMMARY> which describes how
-error handling may be further customised.
-
-=head2 error()
-
-When called as a class method, it returns the value of the $ERROR package
-variable.  Thus, the following are equivalent.
-
-    my $tt = Template->new()
-        || die Template->error(), "\n";
-
-    my $tt = Template->new()
-        || die $Template::ERROR, "\n";
-
-When called as an object method, it returns the value of the internal
-_ERROR variable, as set by an error condition in a previous call to
-process().
-
-    $tt->process('welcome.tt2')
-        || die $tt->error(), "\n";
-
-Errors are represented in the Template Toolkit by objects of the
-Template::Exception class.  If the process() method returns a false
-value then the error() method can be called to return an object of
-this class.  The type() and info() methods can called on the object to
-retrieve the error type and information string, respectively.  The
-as_string() method can be called to return a string of the form "$type
-- $info".  This method is also overloaded onto the stringification
-operator allowing the object reference itself to be printed to return
-the formatted error string.
-
-    $tt->process('somefile') || do {
-	my $error = $tt->error();
-	print "error type: ", $error->type(), "\n";
-	print "error info: ", $error->info(), "\n";
-	print $error, "\n";
-    };
-
-=head2 service()
-
-The Template module delegates most of the effort of processing templates
-to an underlying Template::Service object.  This method returns a reference
-to that object.
-
-=head2 context()
-
-The Template::Service module uses a core Template::Context object for
-runtime processing of templates.  This method returns a reference to 
-that object and is equivalent to $template-E<gt>service-E<gt>context();
-
-=head1 CONFIGURATION SUMMARY
-
-The following list gives a short summary of each Template Toolkit 
-configuration option.  See L<Template::Manual::Config> for full details.
-
-=head2 Template Style and Parsing Options
-
-=over 4
-
-=item START_TAG, END_TAG
-
-Define tokens that indicate start and end of directives (default: '[%' and 
-'%]').
-
-=item TAG_STYLE
-
-Set START_TAG and END_TAG according to a pre-defined style (default: 
-'template', as above).
-
-=item PRE_CHOMP, POST_CHOMP
-
-Remove whitespace before/after directives (default: 0/0).
-
-=item TRIM
-
-Remove leading and trailing whitespace from template output (default: 0).
-
-=item INTERPOLATE
-
-Interpolate variables embedded like $this or ${this} (default: 0).
-
-=item ANYCASE
-
-Allow directive keywords in lower case (default: 0 - UPPER only).
-
-=back
-
-=head2 Template Files and Blocks
-
-=over 4
-
-=item INCLUDE_PATH
-
-One or more directories to search for templates.
-
-=item DELIMITER
-
-Delimiter for separating paths in INCLUDE_PATH (default: ':').
-
-=item ABSOLUTE
-
-Allow absolute file names, e.g. /foo/bar.html (default: 0).
-
-=item RELATIVE
-
-Allow relative filenames, e.g. ../foo/bar.html (default: 0).
-
-=item DEFAULT
-
-Default template to use when another not found.
-
-=item BLOCKS
-
-Hash array pre-defining template blocks.
-
-=item AUTO_RESET
-
-Enabled by default causing BLOCK definitions to be reset each time a 
-template is processed.  Disable to allow BLOCK definitions to persist.
-
-=item RECURSION
-
-Flag to permit recursion into templates (default: 0).
-
-=back
-
-=head2 Template Variables
-
-=over 4
-
-=item VARIABLES, PRE_DEFINE
-
-Hash array of variables and values to pre-define in the stash.
-
-=back
-
-=head2 Runtime Processing Options
-
-=over 4
-
-=item EVAL_PERL
-
-Flag to indicate if PERL/RAWPERL blocks should be processed (default: 0).
-
-=item PRE_PROCESS, POST_PROCESS
-
-Name of template(s) to process before/after main template.
-
-=item PROCESS
-
-Name of template(s) to process instead of main template.
-
-=item ERROR
-
-Name of error template or reference to hash array mapping error types to
-templates.
-
-=item  OUTPUT
-
-Default output location or handler.
-
-=item  OUTPUT_PATH
-
-Directory into which output files can be written.
-
-=item DEBUG
-
-Enable debugging messages.
-
-=back
-
-=head2 Caching and Compiling Options
-
-=over 4
-
-=item CACHE_SIZE
-
-Maximum number of compiled templates to cache in memory (default:
-undef - cache all)
-
-=item COMPILE_EXT
-
-Filename extension for compiled template files (default: undef - don't
-compile).
-
-=item COMPILE_DIR
-
-Root of directory in which compiled template files should be written
-(default: undef - don't compile).
-
-=back
-
-=head2 Plugins and Filters
-
-=over 4
-
-=item PLUGINS
-
-Reference to a hash array mapping plugin names to Perl packages.
-
-=item PLUGIN_BASE
-
-One or more base classes under which plugins may be found.
-
-=item LOAD_PERL
-
-Flag to indicate regular Perl modules should be loaded if a named plugin 
-can't be found  (default: 0).
-
-=item FILTERS
-
-Hash array mapping filter names to filter subroutines or factories.
-
-=back
-
-=head2 Compatibility, Customisation and Extension
-
-=over 4
-
-=item V1DOLLAR
-
-Backwards compatibility flag enabling version 1.* handling (i.e. ignore it) 
-of leading '$' on variables (default: 0 - '$' indicates interpolation).
-
-=item LOAD_TEMPLATES
-
-List of template providers.
-
-=item LOAD_PLUGINS
-
-List of plugin providers.
-
-=item LOAD_FILTERS
-
-List of filter providers.
-
-=item TOLERANT
-
-Set providers to tolerate errors as declinations (default: 0).
-
-=item SERVICE
-
-Reference to a custom service object (default: Template::Service).
-
-=item CONTEXT
-
-Reference to a custom context object (default: Template::Context).
-
-=item STASH
-
-Reference to a custom stash object (default: Template::Stash).
-
-=item PARSER
-
-Reference to a custom parser object (default: Template::Parser).
-
-=item GRAMMAR
-
-Reference to a custom grammar object (default: Template::Grammar).
-
-=back
-
-=head1 DIRECTIVE SUMMARY
-
-The following list gives a short summary of each Template Toolkit directive.
-See L<Template::Manual::Directives> for full details.
-
-=over 4
-
-=item GET
-
-Evaluate and print a variable or value.
-
-    [%   GET variable %]    # 'GET' keyword is optional
-
-    [%       variable %]
-    [%       hash.key %]
-    [%         list.n %]
-    [%     code(args) %]
-    [% obj.meth(args) %]
-    [%  "value: $var" %]
-
-=item CALL
-
-As per GET but without printing result (e.g. call code)
-
-    [%  CALL variable %]
-
-=item SET
-
-Assign a values to variables.
-
-    [% SET variable = value %]    # 'SET' also optional
-
-    [%     variable = other_variable
-    	   variable = 'literal text @ $100'
-    	   variable = "interpolated text: $var"
-    	   list     = [ val, val, val, val, ... ]
-    	   list     = [ val..val ]
-    	   hash     = { var => val, var => val, ... }
-    %]
-
-=item DEFAULT
-
-Like SET above, but variables are only set if currently unset (i.e. have no
-true value).
-
-    [% DEFAULT variable = value %]
-
-=item INSERT
-
-Insert a file without any processing performed on the contents.
-
-    [% INSERT legalese.txt %]
-
-=item INCLUDE
-
-Process another template file or block and include the output.  Variables
-are localised.
-
-    [% INCLUDE template %]
-    [% INCLUDE template  var = val, ... %]
-
-=item PROCESS
-
-As INCLUDE above, but without localising variables.
-
-    [% PROCESS template %]
-    [% PROCESS template  var = val, ... %]
-
-=item WRAPPER
-
-Process the enclosed block WRAPPER ... END block then INCLUDE the 
-named template, passing the block output in the 'content' variable.
-
-    [% WRAPPER template %]
-       content...
-    [% END %]
-
-=item BLOCK
-
-Define a named template block for subsequent INCLUDE, PROCESS, etc., 
-
-    [% BLOCK template %]
-       content
-    [% END %]
-
-=item FOREACH
-
-Repeat the enclosed FOREACH ... END block for each value in the list.
-
-    [% FOREACH variable = [ val, val, val ] %]	  # either
-    [% FOREACH variable = list %]                 # or
-    [% FOREACH list %]                            # or 
-       content...
-       [% variable %]
-    [% END %]
-
-=item WHILE
-
-Enclosed WHILE ... END block is processed while condition is true.
-
-    [% WHILE condition %]
-       content
-    [% END %]
-
-=item IF / UNLESS / ELSIF / ELSE
-
-Enclosed block is processed if the condition is true / false.
-
-    [% IF condition %]
-       content
-    [% ELSIF condition %]
-	 content
-    [% ELSE %]
-	 content
-    [% END %]
-
-    [% UNLESS condition %]
-       content
-    [% # ELSIF/ELSE as per IF, above %]
-       content
-    [% END %]
-
-=item SWITCH / CASE
-
-Multi-way switch/case statement.
-
-    [% SWITCH variable %]
-    [% CASE val1 %]
-       content
-    [% CASE [ val2, val3 ] %]
-       content
-    [% CASE %]         # or [% CASE DEFAULT %]
-       content
-    [% END %]
-
-=item MACRO
-
-Define a named macro.
-
-    [% MACRO name <directive> %]
-    [% MACRO name(arg1, arg2) <directive> %]
-    ...
-    [% name %]
-    [% name(val1, val2) %]
-
-=item FILTER
-
-Process enclosed FILTER ... END block then pipe through a filter.
-
-    [% FILTER name %]			    # either
-    [% FILTER name( params ) %]		    # or
-    [% FILTER alias = name( params ) %]	    # or
-       content
-    [% END %]
-
-=item USE
-
-Load a "plugin" module, or any regular Perl module if LOAD_PERL option is
-set.
-
-    [% USE name %]			    # either
-    [% USE name( params ) %]		    # or
-    [% USE var = name( params ) %]	    # or
-    ...
-    [% name.method %]
-    [% var.method %]
-
-=item PERL / RAWPERL
-
-Evaluate enclosed blocks as Perl code (requires EVAL_PERL option to be set).
-
-    [% PERL %]
-	 # perl code goes here
-	 $stash->set('foo', 10);
-	 print "set 'foo' to ", $stash->get('foo'), "\n";
-	 print $context->include('footer', { var => $val });
-    [% END %]
-
-    [% RAWPERL %]
-       # raw perl code goes here, no magic but fast.
-       $output .= 'some output';
-    [% END %]
-
-=item TRY / THROW / CATCH / FINAL
-
-Exception handling.
-
-    [% TRY %]
-	 content
-       [% THROW type info %]
-    [% CATCH type %]
-	 catch content
-       [% error.type %] [% error.info %]
-    [% CATCH %]	# or [% CATCH DEFAULT %]
-	 content
-    [% FINAL %]
-       this block is always processed
-    [% END %]
-
-=item NEXT
-
-Jump straight to the next item in a FOREACH/WHILE loop.
-
-    [% NEXT %]
-
-=item LAST
-
-Break out of FOREACH/WHILE loop.
-
-    [% LAST %]
-
-=item RETURN
-
-Stop processing current template and return to including templates.
-
-    [% RETURN %]
-
-=item STOP
-
-Stop processing all templates and return to caller.
-
-    [% STOP %]
-
-=item TAGS
-
-Define new tag style or characters (default: [% %]).
-
-    [% TAGS html %]
-    [% TAGS <!-- --> %]
-
-=item COMMENTS
-
-Ignored and deleted.
-
-    [% # this is a comment to the end of line
-       foo = 'bar'
-    %]
-
-    [%# placing the '#' immediately inside the directive
-        tag comments out the entire directive
-    %]
-
-=back
-
-=head1 AUTHOR
-
-Andy Wardley E<lt>abw@andywardley.comE<gt>
-
-L<http://www.andywardley.com/|http://www.andywardley.com/>
-
-
-
-
-=head1 VERSION
-
-Template Toolkit version 2.13, released on 30 January 2004.
-
-=head1 COPYRIGHT
-
-  Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
-  Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
-
-This module is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
-
-
-
-=cut
-
-# Local Variables:
-# mode: perl
-# perl-indent-level: 4
-# indent-tabs-mode: nil
-# End:
-#
-# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Base.pm b/lib/Template/Base.pm
deleted file mode 100644
index 5f19d78..0000000
--- a/lib/Template/Base.pm
+++ /dev/null
@@ -1,314 +0,0 @@
-#============================================================= -*-perl-*-
-#
-# Template::Base
-#
-# DESCRIPTION
-#   Base class module implementing common functionality for various other
-#   Template Toolkit modules.
-#
-# AUTHOR
-#   Andy Wardley   <abw@kfs.org>
-#
-# COPYRIGHT
-#   Copyright (C) 1996-2000 Andy Wardley.  All Rights Reserved.
-#   Copyright (C) 1998-2000 Canon Research Centre Europe Ltd.
-#
-#   This module is free software; you can redistribute it and/or
-#   modify it under the same terms as Perl itself.
-#
-#------------------------------------------------------------------------
-#
-#   $Id: Base.pm,v 2.69 2004/01/13 16:19:09 abw Exp $
-#
-#========================================================================
- 
-package Template::Base;
-
-require 5.004;
-
-use strict;
-use vars qw( $VERSION );
-use Template::Constants;
-
-$VERSION = sprintf("%d.%02d", q$Revision: 2.69 $ =~ /(\d+)\.(\d+)/);
-
-
-#------------------------------------------------------------------------
-# new(\%params)
-#
-# General purpose constructor method which expects a hash reference of 
-# configuration parameters, or a list of name => value pairs which are 
-# folded into a hash.  Blesses a hash into an object and calls its 
-# _init() method, passing the parameter hash reference.  Returns a new
-# object derived from Template::Base, or undef on error.
-#------------------------------------------------------------------------
-
-sub new {
-    my $class = shift;
-    my ($argnames, @args, $arg, $cfg);
-#    $class->error('');		# always clear package $ERROR var?
-
-    {	no strict qw( refs );
-	$argnames = \@{"$class\::BASEARGS"} || [ ];
-    }
-
-    # shift off all mandatory args, returning error if undefined or null
-    foreach $arg (@$argnames) {
-	return $class->error("no $arg specified")
-	    unless ($cfg = shift);
-	push(@args, $cfg);
-    }
-
-    # fold all remaining args into a hash, or use provided hash ref
-#    local $" = ', ';
-#    print STDERR "args: [@_]\n";
-    $cfg  = defined $_[0] && UNIVERSAL::isa($_[0], 'HASH') ? shift : { @_ };
-
-    my $self = bless {
-	map { ($_ => shift @args) } @$argnames,
-	_ERROR  => '',
-        DEBUG   => 0,
-    }, $class;
-
-    return $self->_init($cfg) ? $self : $class->error($self->error);
-}
-
-
-#------------------------------------------------------------------------
-# error()
-# error($msg, ...)
-# 
-# May be called as a class or object method to set or retrieve the 
-# package variable $ERROR (class method) or internal member 
-# $self->{ _ERROR } (object method).  The presence of parameters indicates
-# that the error value should be set.  Undef is then returned.  In the
-# abscence of parameters, the current error value is returned.
-#------------------------------------------------------------------------
-
-sub error {
-    my $self = shift;
-    my $errvar;
-
-    { 
-	no strict qw( refs );
-	$errvar = ref $self ? \$self->{ _ERROR } : \${"$self\::ERROR"};
-    }
-    if (@_) {
-	$$errvar = ref($_[0]) ? shift : join('', @_);
-	return undef;
-    }
-    else {
-	return $$errvar;
-    }
-}
-
-
-#------------------------------------------------------------------------
-# _init()
-#
-# Initialisation method called by the new() constructor and passing a 
-# reference to a hash array containing any configuration items specified
-# as constructor arguments.  Should return $self on success or undef on 
-# error, via a call to the error() method to set the error message.
-#------------------------------------------------------------------------
-
-sub _init {
-    my ($self, $config) = @_;
-    return $self;
-}
-
-
-sub DEBUG {
-    my $self = shift;
-    print STDERR "DEBUG: ", @_;
-}
-
-sub debug {
-    my $self = shift;
-    my $msg  = join('', @_);
-    my ($pkg, $file, $line) = caller();
-
-    unless ($msg =~ /\n$/) {
-	$msg .= ($self->{ DEBUG } & Template::Constants::DEBUG_CALLER)
-		 ? " at $file line $line\n"
-		 : "\n";
-    }
-
-    print STDERR "[$pkg] $msg";
-}
-
-
-#------------------------------------------------------------------------
-# module_version()
-#
-# Returns the current version number.
-#------------------------------------------------------------------------
-
-sub module_version {
-    my $self = shift;
-    my $class = ref $self || $self;
-    no strict 'refs';
-    return ${"${class}::VERSION"};
-}
-
-
-1;
-
-__END__
-
-
-#------------------------------------------------------------------------
-# IMPORTANT NOTE
-#   This documentation is generated automatically from source
-#   templates.  Any changes you make here may be lost.
-# 
-#   The 'docsrc' documentation source bundle is available for download
-#   from http://www.template-toolkit.org/docs.html and contains all
-#   the source templates, XML files, scripts, etc., from which the
-#   documentation for the Template Toolkit is built.
-#------------------------------------------------------------------------
-
-=head1 NAME
-
-Template::Base - Base class module implementing common functionality
-
-=head1 SYNOPSIS
-
-    package My::Module;
-    use base qw( Template::Base );
-
-    sub _init {
-	my ($self, $config) = @_;
-	$self->{ doodah } = $config->{ doodah }
-	    || return $self->error("No 'doodah' specified");
-	return $self;
-    }
-
-    package main;
-
-    my $object = My::Module->new({ doodah => 'foobar' })
-        || die My::Module->error();
-
-=head1 DESCRIPTION
-
-Base class module which implements a constructor and error reporting 
-functionality for various Template Toolkit modules.
-
-=head1 PUBLIC METHODS
-
-=head2 new(\%config)
-
-Constructor method which accepts a reference to a hash array or a list 
-of C<name =E<gt> value> parameters which are folded into a hash.  The 
-_init() method is then called, passing the configuration hash and should
-return true/false to indicate success or failure.  A new object reference
-is returned, or undef on error.  Any error message raised can be examined
-via the error() class method or directly via the package variable ERROR
-in the derived class.
-
-    my $module = My::Module->new({ ... })
-        || die My::Module->error(), "\n";
-
-    my $module = My::Module->new({ ... })
-        || die "constructor error: $My::Module::ERROR\n";
-
-=head2 error($msg, ...)
-
-May be called as an object method to get/set the internal _ERROR member
-or as a class method to get/set the $ERROR variable in the derived class's
-package.
-
-    my $module = My::Module->new({ ... })
-        || die My::Module->error(), "\n";
-
-    $module->do_something() 
-	|| die $module->error(), "\n";
-
-When called with parameters (multiple params are concatenated), this
-method will set the relevant variable and return undef.  This is most
-often used within object methods to report errors to the caller.
-
-    package My::Module;
-
-    sub foobar {
-	my $self = shift;
-
-	# some other code...
-
-	return $self->error('some kind of error...')
-	    if $some_condition;
-    }
-
-=head2 debug($msg, ...)
-
-Generates a debugging message by concatenating all arguments
-passed into a string and printing it to STDERR.  A prefix is
-added to indicate the module of the caller.
-
-    package My::Module;
-
-    sub foobar {
-	my $self = shift;
-
-	$self->debug('called foobar()');
-
-	# some other code...
-    }
-
-When the foobar() method is called, the following message
-is sent to STDERR:
-
-    [My::Module] called foobar()
-
-Objects can set an internal DEBUG value which the debug()
-method will examine.  If this value sets the relevant bits
-to indicate DEBUG_CALLER then the file and line number of
-the caller will be appened to the message.
-
-    use Template::Constants qw( :debug );
-
-    my $module = My::Module->new({
-        DEBUG => DEBUG_SERVICE | DEBUG_CONTEXT | DEBUG_CALLER,
-    });
-
-    $module->foobar();
-
-This generates an error message such as:
-
-    [My::Module] called foobar() at My/Module.pm line 6
-
-=head1 AUTHOR
-
-Andy Wardley E<lt>abw@andywardley.comE<gt>
-
-L<http://www.andywardley.com/|http://www.andywardley.com/>
-
-
-
-
-=head1 VERSION
-
-2.69, distributed as part of the
-Template Toolkit version 2.13, released on 30 January 2004.
-
-=head1 COPYRIGHT
-
-  Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
-  Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
-
-This module is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
-
-=head1 SEE ALSO
-
-L<Template|Template>
-
-=cut
-
-# Local Variables:
-# mode: perl
-# perl-indent-level: 4
-# indent-tabs-mode: nil
-# End:
-#
-# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Config.pm b/lib/Template/Config.pm
deleted file mode 100644
index 9a3f378..0000000
--- a/lib/Template/Config.pm
+++ /dev/null
@@ -1,467 +0,0 @@
-#============================================================= -*-perl-*-
-#
-# Template::Config
-#
-# DESCRIPTION
-#   Template Toolkit configuration module.
-#
-# AUTHOR
-#   Andy Wardley   <abw@kfs.org>
-#
-# COPYRIGHT
-#   Copyright (C) 1996-2000 Andy Wardley.  All Rights Reserved.
-#   Copyright (C) 1998-2000 Canon Research Centre Europe Ltd.
-#
-#   This module is free software; you can redistribute it and/or
-#   modify it under the same terms as Perl itself.
-#
-#------------------------------------------------------------------------
-#
-#   $Id: Config.pm,v 2.67 2004/01/13 16:19:10 abw Exp $
-#
-#========================================================================
- 
-package Template::Config;
-
-require 5.004;
-
-use strict;
-use base qw( Template::Base );
-use vars qw( $VERSION $DEBUG $ERROR $INSTDIR
-	     $PARSER $PROVIDER $PLUGINS $FILTERS $ITERATOR 
-             $LATEX_PATH $PDFLATEX_PATH $DVIPS_PATH
-	     $STASH $SERVICE $CONTEXT $CONSTANTS @PRELOAD );
-
-$VERSION   = sprintf("%d.%02d", q$Revision: 2.67 $ =~ /(\d+)\.(\d+)/);
-$DEBUG     = 0 unless defined $DEBUG;
-$ERROR     = '';
-$CONTEXT   = 'Template::Context';
-$FILTERS   = 'Template::Filters';
-$ITERATOR  = 'Template::Iterator';
-$PARSER    = 'Template::Parser';
-$PLUGINS   = 'Template::Plugins';
-$PROVIDER  = 'Template::Provider';
-$SERVICE   = 'Template::Service';
-$STASH     = 'Template::Stash';
-$CONSTANTS = 'Template::Namespace::Constants';
-
-@PRELOAD   = ( $CONTEXT, $FILTERS, $ITERATOR, $PARSER,
-               $PLUGINS, $PROVIDER, $SERVICE, $STASH );
-
-# the following is set at installation time by the Makefile.PL 
-$INSTDIR  = '';
-
-# LaTeX executable paths set at installation time by the Makefile.PL
-# Empty strings cause the latex(pdf|dvi|ps) filters to throw an error.
-$LATEX_PATH    = '';
-$PDFLATEX_PATH = '';
-$DVIPS_PATH    = '';
-
-#========================================================================
-#                       --- CLASS METHODS ---
-#========================================================================
-
-#------------------------------------------------------------------------
-# preload($module, $module, ...)
-#
-# Preloads all the standard TT modules that are likely to be used, along
-# with any other passed as arguments.
-#------------------------------------------------------------------------
-
-sub preload {
-    my $class = shift;
-
-    foreach my $module (@PRELOAD, @_) {
-        $class->load($module) || return;
-    };
-    return 1;
-}
-
-
-#------------------------------------------------------------------------
-# load($module)
-#
-# Load a module via require().  Any occurences of '::' in the module name
-# are be converted to '/' and '.pm' is appended.  Returns 1 on success
-# or undef on error.  Use $class->error() to examine the error string.
-#------------------------------------------------------------------------
-
-sub load {
-    my ($class, $module) = @_;
-    $module =~ s[::][/]g;
-    $module .= '.pm';
-#    print STDERR "loading $module\n"
-#	if $DEBUG;
-    eval {
-	require $module;
-    };
-    return $@ ? $class->error("failed to load $module: $@") : 1;
-}
-
-
-#------------------------------------------------------------------------
-# parser(\%params)
-#
-# Instantiate a new parser object of the class whose name is denoted by
-# the package variable $PARSER (default: Template::Parser).  Returns
-# a reference to a newly instantiated parser object or undef on error.
-# The class error() method can be called without arguments to examine
-# the error message generated by this failure.
-#------------------------------------------------------------------------
-
-sub parser {
-    my $class  = shift;
-    my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH')
-	       ? shift : { @_ };
-
-    return undef unless $class->load($PARSER);
-    return $PARSER->new($params) 
-	|| $class->error("failed to create parser: ", $PARSER->error);
-}
-
-
-#------------------------------------------------------------------------
-# provider(\%params)
-#
-# Instantiate a new template provider object (default: Template::Provider).
-# Returns an object reference or undef on error, as above.
-#------------------------------------------------------------------------
-
-sub provider {
-    my $class  = shift;
-    my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH') 
-	       ? shift : { @_ };
-
-    return undef unless $class->load($PROVIDER);
-    return $PROVIDER->new($params) 
-	|| $class->error("failed to create template provider: ",
-			 $PROVIDER->error);
-}
-
-
-#------------------------------------------------------------------------
-# plugins(\%params)
-#
-# Instantiate a new plugins provider object (default: Template::Plugins).
-# Returns an object reference or undef on error, as above.
-#------------------------------------------------------------------------
-
-sub plugins {
-    my $class  = shift;
-    my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH') 
-	       ? shift : { @_ };
-
-    return undef unless $class->load($PLUGINS);
-    return $PLUGINS->new($params)
-	|| $class->error("failed to create plugin provider: ",
-			 $PLUGINS->error);
-}
-
-
-#------------------------------------------------------------------------
-# filters(\%params)
-#
-# Instantiate a new filters provider object (default: Template::Filters).
-# Returns an object reference or undef on error, as above.
-#------------------------------------------------------------------------
-
-sub filters {
-    my $class  = shift;
-    my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH') 
-	       ? shift : { @_ };
-
-    return undef unless $class->load($FILTERS);
-    return $FILTERS->new($params)
-	|| $class->error("failed to create filter provider: ",
-			 $FILTERS->error);
-}
-
-
-#------------------------------------------------------------------------
-# iterator(\@list)
-#
-# Instantiate a new Template::Iterator object (default: Template::Iterator).
-# Returns an object reference or undef on error, as above.
-#------------------------------------------------------------------------
-
-sub iterator {
-    my $class = shift;
-    my $list  = shift;
-
-    return undef unless $class->load($ITERATOR);
-    return $ITERATOR->new($list, @_)
-	|| $class->error("failed to create iterator: ", $ITERATOR->error);
-}
-
-
-#------------------------------------------------------------------------
-# stash(\%vars)
-#
-# Instantiate a new template variable stash object (default: 
-# Template::Stash). Returns object or undef, as above.
-#------------------------------------------------------------------------
-
-sub stash {
-    my $class  = shift;
-    my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH') 
-	       ? shift : { @_ };
-
-    return undef unless $class->load($STASH);
-    return $STASH->new($params) 
-	|| $class->error("failed to create stash: ", $STASH->error);
-}
-
-
-#------------------------------------------------------------------------
-# context(\%params)
-#
-# Instantiate a new template context object (default: Template::Context). 
-# Returns object or undef, as above.
-#------------------------------------------------------------------------
-
-sub context {
-    my $class  = shift;
-    my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH') 
-	       ? shift : { @_ };
-
-    return undef unless $class->load($CONTEXT);
-    return $CONTEXT->new($params) 
-	|| $class->error("failed to create context: ", $CONTEXT->error);
-}
-
-
-#------------------------------------------------------------------------
-# service(\%params)
-#
-# Instantiate a new template context object (default: Template::Service). 
-# Returns object or undef, as above.
-#------------------------------------------------------------------------
-
-sub service {
-    my $class  = shift;
-    my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH') 
-	       ? shift : { @_ };
-
-    return undef unless $class->load($SERVICE);
-    return $SERVICE->new($params) 
-	|| $class->error("failed to create context: ", $SERVICE->error);
-}
-
-
-#------------------------------------------------------------------------
-# constants(\%params)
-#
-# Instantiate a new namespace handler for compile time constant folding
-# (default: Template::Namespace::Constants). 
-# Returns object or undef, as above.
-#------------------------------------------------------------------------
-
-sub constants {
-    my $class  = shift;
-    my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH') 
-	       ? shift : { @_ };
-
-    return undef unless $class->load($CONSTANTS);
-    return $CONSTANTS->new($params) 
-	|| $class->error("failed to create constants namespace: ", 
-			 $CONSTANTS->error);
-}
-
-
-#------------------------------------------------------------------------
-# instdir($dir)
-#
-# Returns the root installation directory appended with any local 
-# component directory passed as an argument.
-#------------------------------------------------------------------------
-
-sub instdir {
-    my ($class, $dir) = @_;
-    my $inst = $INSTDIR 
-	|| return $class->error("no installation directory");
-    $inst =~ s[/$][]g;
-    $inst .= "/$dir" if $dir;
-    return $inst;
-}
-
-#------------------------------------------------------------------------
-# latexpaths()
-#
-# Returns a reference to a three element array:
-#    [latex_path,  pdf2latex_path, dvips_path]
-# These values are determined by Makefile.PL at installation time
-# and are used by the latex(pdf|dvi|ps) filters.
-#------------------------------------------------------------------------
-
-sub latexpaths {
-    return [$LATEX_PATH, $PDFLATEX_PATH, $DVIPS_PATH];
-}
-
-#========================================================================
-# This should probably be moved somewhere else in the long term, but for
-# now it ensures that Template::TieString is available even if the 
-# Template::Directive module hasn't been loaded, as is the case when 
-# using compiled templates and Template::Parser hasn't yet been loaded
-# on demand.
-#========================================================================
-
-#------------------------------------------------------------------------
-# simple package for tying $output variable to STDOUT, used by perl()
-#------------------------------------------------------------------------
-
-package Template::TieString;
-
-sub TIEHANDLE {
-    my ($class, $textref) = @_;
-    bless $textref, $class;
-}
-sub PRINT {
-    my $self = shift;
-    $$self .= join('', @_);
-}
-
-
-
-1;
-
-__END__
-
-
-#------------------------------------------------------------------------
-# IMPORTANT NOTE
-#   This documentation is generated automatically from source
-#   templates.  Any changes you make here may be lost.
-# 
-#   The 'docsrc' documentation source bundle is available for download
-#   from http://www.template-toolkit.org/docs.html and contains all
-#   the source templates, XML files, scripts, etc., from which the
-#   documentation for the Template Toolkit is built.
-#------------------------------------------------------------------------
-
-=head1 NAME
-
-Template::Config - Factory module for instantiating other TT2 modules
-
-=head1 SYNOPSIS
-
-    use Template::Config;
-
-=head1 DESCRIPTION
-
-This module implements various methods for loading and instantiating
-other modules that comprise the Template Toolkit.  It provides a consistent
-way to create toolkit components and allows custom modules to be used in 
-place of the regular ones.
-
-Package variables such as $STASH, $SERVICE, $CONTEXT, etc., contain
-the default module/package name for each component (Template::Stash,
-Template::Service and Template::Context, respectively) and are used by
-the various factory methods (stash(), service() and context()) to load
-the appropriate module.  Changing these package variables will cause
-subsequent calls to the relevant factory method to load and instantiate
-an object from the new class.
-
-=head1 PUBLIC METHODS
-
-=head2 load($module)
-
-Load a module via require().  Any occurences of '::' in the module name
-are be converted to '/' and '.pm' is appended.  Returns 1 on success
-or undef on error.  Use $class-E<gt>error() to examine the error string.
-
-=head2 preload()
-
-This method preloads all the other Template::* modules that are likely
-to be used.  It is called by the Template module when running under 
-mod_perl ($ENV{MOD_PERL} is set).
-
-=head2 parser(\%config)
-
-Instantiate a new parser object of the class whose name is denoted by
-the package variable $PARSER (default: Template::Parser).  Returns
-a reference to a newly instantiated parser object or undef on error.
-
-=head2 provider(\%config)
-
-Instantiate a new template provider object (default: Template::Provider).
-Returns an object reference or undef on error, as above.
-
-=head2 plugins(\%config)
-
-Instantiate a new plugins provider object (default: Template::Plugins).
-Returns an object reference or undef on error, as above.
-
-=head2 filters(\%config)
-
-Instantiate a new filter provider object (default: Template::Filters).
-Returns an object reference or undef on error, as above.
-
-=head2 stash(\%vars)
-
-Instantiate a new stash object (Template::Stash or Template::Stash::XS
-depending on the default set at installation time) using the contents
-of the optional hash array passed by parameter as initial variable
-definitions.  Returns an object reference or undef on error, as above.
-
-=head2 context(\%config)
-
-Instantiate a new template context object (default: Template::Context).
-Returns an object reference or undef on error, as above.
-
-=head2 service(\%config)
-
-Instantiate a new template service object (default: Template::Service).
-Returns an object reference or undef on error, as above.
-
-=head2 instdir($dir)
-
-Returns the root directory of the Template Toolkit installation under
-which optional components are installed.  Any relative directory specified
-as an argument will be appended to the returned directory.
-
-    # e.g. returns '/usr/local/tt2'
-    my $ttroot = Template::Config->instdir()
-	|| die "$Template::Config::ERROR\n";
-
-    # e.g. returns '/usr/local/tt2/templates'
-    my $template = Template::Config->instdir('templates')
-	|| die "$Template::Config::ERROR\n";
-
-Returns undef and sets $Template::Config::ERROR appropriately if the 
-optional components of the Template Toolkit have not been installed.
-
-=head1 AUTHOR
-
-Andy Wardley E<lt>abw@andywardley.comE<gt>
-
-L<http://www.andywardley.com/|http://www.andywardley.com/>
-
-
-
-
-=head1 VERSION
-
-2.67, distributed as part of the
-Template Toolkit version 2.13, released on 30 January 2004.
-
-=head1 COPYRIGHT
-
-  Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
-  Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
-
-This module is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
-
-=head1 SEE ALSO
-
-L<Template|Template>
-
-=cut
-
-# Local Variables:
-# mode: perl
-# perl-indent-level: 4
-# indent-tabs-mode: nil
-# End:
-#
-# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Constants.pm b/lib/Template/Constants.pm
deleted file mode 100644
index b227467..0000000
--- a/lib/Template/Constants.pm
+++ /dev/null
@@ -1,287 +0,0 @@
-#============================================================= -*-Perl-*-
-#
-# Template::Constants.pm
-#
-# DESCRIPTION
-#   Definition of constants for the Template Toolkit.
-#
-# AUTHOR
-#   Andy Wardley   <abw@kfs.org>
-#
-# COPYRIGHT
-#   Copyright (C) 1996-2000 Andy Wardley.  All Rights Reserved.
-#   Copyright (C) 1998-2000 Canon Research Centre Europe Ltd.
-#
-#   This module is free software; you can redistribute it and/or
-#   modify it under the same terms as Perl itself.
-#
-#----------------------------------------------------------------------------
-#
-# $Id: Constants.pm,v 2.67 2004/01/13 16:19:10 abw Exp $
-#
-#============================================================================
- 
-package Template::Constants;
-
-require 5.004;
-require Exporter;
-
-use strict;
-use vars qw( $VERSION @ISA @EXPORT_OK %EXPORT_TAGS );
-use vars qw( $DEBUG_OPTIONS @STATUS @ERROR @CHOMP @DEBUG);
-
-@ISA     = qw( Exporter );
-$VERSION = sprintf("%d.%02d", q$Revision: 2.67 $ =~ /(\d+)\.(\d+)/);
-
-
-#========================================================================
-#                         ----- EXPORTER -----
-#========================================================================
-
-# STATUS constants returned by directives
-use constant STATUS_OK       =>   0;      # ok
-use constant STATUS_RETURN   =>   1;      # ok, block ended by RETURN
-use constant STATUS_STOP     =>   2;      # ok, stoppped by STOP 
-use constant STATUS_DONE     =>   3;      # ok, iterator done
-use constant STATUS_DECLINED =>   4;      # ok, declined to service request
-use constant STATUS_ERROR    => 255;      # error condition
-
-# ERROR constants for indicating exception types
-use constant ERROR_RETURN    =>  'return'; # return a status code
-use constant ERROR_FILE      =>  'file';   # file error: I/O, parse, recursion
-use constant ERROR_VIEW      =>  'view';   # view error
-use constant ERROR_UNDEF     =>  'undef';  # undefined variable value used
-use constant ERROR_PERL      =>  'perl';   # error in [% PERL %] block
-use constant ERROR_FILTER    =>  'filter'; # filter error
-use constant ERROR_PLUGIN    =>  'plugin'; # plugin error
-
-# CHOMP constants for PRE_CHOMP and POST_CHOMP
-use constant CHOMP_NONE      => 0; # do not remove whitespace
-use constant CHOMP_ALL       => 1; # remove whitespace
-use constant CHOMP_COLLAPSE  => 2; # collapse whitespace to a single space
-
-# DEBUG constants to enable various debugging options
-use constant DEBUG_OFF       =>    0; # do nothing
-use constant DEBUG_ON        =>    1; # basic debugging flag
-use constant DEBUG_UNDEF     =>    2; # throw undef on undefined variables
-use constant DEBUG_VARS      =>    4; # general variable debugging
-use constant DEBUG_DIRS      =>    8; # directive debugging
-use constant DEBUG_STASH     =>   16; # general stash debugging
-use constant DEBUG_CONTEXT   =>   32; # context debugging
-use constant DEBUG_PARSER    =>   64; # parser debugging
-use constant DEBUG_PROVIDER  =>  128; # provider debugging
-use constant DEBUG_PLUGINS   =>  256; # plugins debugging
-use constant DEBUG_FILTERS   =>  512; # filters debugging
-use constant DEBUG_SERVICE   => 1024; # context debugging
-use constant DEBUG_ALL       => 2047; # everything
-
-# extra debugging flags
-use constant DEBUG_CALLER    => 4096; # add caller file/line
-use constant DEBUG_FLAGS     => 4096; # bitmask to extraxt flags
-
-$DEBUG_OPTIONS  = {
-    &DEBUG_OFF      => off      => off      => &DEBUG_OFF,
-    &DEBUG_ON       => on       => on       => &DEBUG_ON,
-    &DEBUG_UNDEF    => undef    => undef    => &DEBUG_UNDEF,
-    &DEBUG_VARS     => vars     => vars     => &DEBUG_VARS,
-    &DEBUG_DIRS     => dirs     => dirs     => &DEBUG_DIRS,
-    &DEBUG_STASH    => stash    => stash    => &DEBUG_STASH,
-    &DEBUG_CONTEXT  => context  => context  => &DEBUG_CONTEXT,
-    &DEBUG_PARSER   => parser   => parser   => &DEBUG_PARSER,
-    &DEBUG_PROVIDER => provider => provider => &DEBUG_PROVIDER,
-    &DEBUG_PLUGINS  => plugins  => plugins  => &DEBUG_PLUGINS,
-    &DEBUG_FILTERS  => filters  => filters  => &DEBUG_FILTERS,
-    &DEBUG_SERVICE  => service  => service  => &DEBUG_SERVICE,
-    &DEBUG_ALL      => all      => all      => &DEBUG_ALL,
-    &DEBUG_CALLER   => caller   => caller   => &DEBUG_CALLER,
-};
-
-@STATUS  = qw( STATUS_OK STATUS_RETURN STATUS_STOP STATUS_DONE
-               STATUS_DECLINED STATUS_ERROR );
-@ERROR   = qw( ERROR_FILE ERROR_VIEW ERROR_UNDEF ERROR_PERL 
-               ERROR_RETURN ERROR_FILTER ERROR_PLUGIN );
-@CHOMP   = qw( CHOMP_NONE CHOMP_ALL CHOMP_COLLAPSE );
-@DEBUG   = qw( DEBUG_OFF DEBUG_ON DEBUG_UNDEF DEBUG_VARS 
-               DEBUG_DIRS DEBUG_STASH DEBUG_CONTEXT DEBUG_PARSER
-               DEBUG_PROVIDER DEBUG_PLUGINS DEBUG_FILTERS DEBUG_SERVICE
-               DEBUG_ALL DEBUG_CALLER DEBUG_FLAGS );
-
-@EXPORT_OK   = ( @STATUS, @ERROR, @CHOMP, @DEBUG );
-%EXPORT_TAGS = (
-    'all'      => [ @EXPORT_OK ],
-    'status'   => [ @STATUS    ],
-    'error'    => [ @ERROR     ],
-    'chomp'    => [ @CHOMP     ],
-    'debug'    => [ @DEBUG     ],
-);
-
-
-sub debug_flags {
-    my ($self, $debug) = @_;
-    my (@flags, $flag, $value);
-    $debug = $self unless defined($debug) || ref($self);
-    
-    if ($debug =~ /^\d+$/) {
-        foreach $flag (@DEBUG) {
-            next if $flag =~ /^DEBUG_(OFF|ALL|FLAGS)$/;
-
-            # don't trash the original
-            my $copy = $flag;
-            $flag =~ s/^DEBUG_//;
-            $flag = lc $flag;
-            return $self->error("no value for flag: $flag")
-                unless defined($value = $DEBUG_OPTIONS->{ $flag });
-            $flag = $value;
-
-            if ($debug & $flag) {
-                $value = $DEBUG_OPTIONS->{ $flag };
-                return $self->error("no value for flag: $flag") unless defined $value;
-                push(@flags, $value);
-            }
-        }
-        return wantarray ? @flags : join(', ', @flags);
-    }
-    else {
-        @flags = split(/\W+/, $debug);
-        $debug = 0;
-        foreach $flag (@flags) {
-            $value = $DEBUG_OPTIONS->{ $flag };
-            return $self->error("unknown debug flag: $flag") unless defined $value;
-            $debug |= $value;
-        }
-        return $debug;
-    }
-}
-
-
-1;
-
-__END__
-
-
-#------------------------------------------------------------------------
-# IMPORTANT NOTE
-#   This documentation is generated automatically from source
-#   templates.  Any changes you make here may be lost.
-# 
-#   The 'docsrc' documentation source bundle is available for download
-#   from http://www.template-toolkit.org/docs.html and contains all
-#   the source templates, XML files, scripts, etc., from which the
-#   documentation for the Template Toolkit is built.
-#------------------------------------------------------------------------
-
-=head1 NAME
-
-Template::Constants - Defines constants for the Template Toolkit
-
-=head1 SYNOPSIS
-
-    use Template::Constants qw( :status :error :all );
-
-=head1 DESCRIPTION
-
-The Template::Constants modules defines, and optionally exports into the
-caller's namespace, a number of constants used by the Template package.
-
-Constants may be used by specifying the Template::Constants package 
-explicitly:
-
-    use Template::Constants;
-
-    print Template::Constants::STATUS_DECLINED;
-
-Constants may be imported into the caller's namespace by naming them as 
-options to the C<use Template::Constants> statement:
-
-    use Template::Constants qw( STATUS_DECLINED );
-
-    print STATUS_DECLINED;
-
-Alternatively, one of the following tagset identifiers may be specified
-to import sets of constants; :status, :error, :all.
-
-    use Template::Constants qw( :status );
-
-    print STATUS_DECLINED;
-
-See L<Exporter> for more information on exporting variables.
-
-=head1 EXPORTABLE TAG SETS
-
-The following tag sets and associated constants are defined: 
-
-  :status
-    STATUS_OK                 # no problem, continue
-    STATUS_RETURN             # ended current block then continue (ok)
-    STATUS_STOP               # controlled stop (ok) 
-    STATUS_DONE               # iterator is all done (ok)
-    STATUS_DECLINED           # provider declined to service request (ok)
-    STATUS_ERROR              # general error condition (not ok)
-
-  :error
-    ERROR_RETURN              # return a status code (e.g. 'stop')
-    ERROR_FILE                # file error: I/O, parse, recursion
-    ERROR_UNDEF               # undefined variable value used
-    ERROR_PERL                # error in [% PERL %] block
-    ERROR_FILTER              # filter error
-    ERROR_PLUGIN              # plugin error
-
-  :chomp                      # for PRE_CHOMP and POST_CHOMP
-    CHOMP_NONE                # do not remove whitespace
-    CHOMP_ALL                 # remove whitespace
-    CHOMP_COLLAPSE            # collapse whitespace to a single space
-
-  :debug
-    DEBUG_OFF                 # do nothing
-    DEBUG_ON                  # basic debugging flag
-    DEBUG_UNDEF               # throw undef on undefined variables
-    DEBUG_VARS                # general variable debugging
-    DEBUG_DIRS                # directive debugging
-    DEBUG_STASH               # general stash debugging
-    DEBUG_CONTEXT             # context debugging
-    DEBUG_PARSER              # parser debugging
-    DEBUG_PROVIDER            # provider debugging
-    DEBUG_PLUGINS             # plugins debugging
-    DEBUG_FILTERS             # filters debugging
-    DEBUG_SERVICE             # context debugging
-    DEBUG_ALL                 # everything
-    DEBUG_CALLER              # add caller file/line info
-    DEBUG_FLAGS               # bitmap used internally
-
-  :all         All the above constants.
-
-=head1 AUTHOR
-
-Andy Wardley E<lt>abw@andywardley.comE<gt>
-
-L<http://www.andywardley.com/|http://www.andywardley.com/>
-
-
-
-
-=head1 VERSION
-
-2.67, distributed as part of the
-Template Toolkit version 2.13, released on 30 January 2004.
-
-=head1 COPYRIGHT
-
-  Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
-  Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
-
-This module is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
-
-=head1 SEE ALSO
-
-L<Template|Template>, L<Exporter|Exporter>
-
-=cut
-
-# Local Variables:
-# mode: perl
-# perl-indent-level: 4
-# indent-tabs-mode: nil
-# End:
-#
-# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Context.pm b/lib/Template/Context.pm
deleted file mode 100644
index cdc699e..0000000
--- a/lib/Template/Context.pm
+++ /dev/null
@@ -1,1570 +0,0 @@
-#============================================================= -*-Perl-*-
-#
-# Template::Context
-#
-# DESCRIPTION
-#   Module defining a context in which a template document is processed.
-#   This is the runtime processing interface through which templates 
-#   can access the functionality of the Template Toolkit.
-#
-# AUTHOR
-#   Andy Wardley   <abw@kfs.org>
-#
-# COPYRIGHT
-#   Copyright (C) 1996-2000 Andy Wardley.  All Rights Reserved.
-#   Copyright (C) 1998-2000 Canon Research Centre Europe Ltd.
-#
-#   This module is free software; you can redistribute it and/or
-#   modify it under the same terms as Perl itself.
-# 
-# REVISION
-#   $Id: Context.pm,v 2.89 2004/01/30 18:37:47 abw Exp $
-#
-#============================================================================
-
-package Template::Context;
-
-require 5.004;
-
-use strict;
-use vars qw( $VERSION $DEBUG $AUTOLOAD $DEBUG_FORMAT );
-use base qw( Template::Base );
-
-use Template::Base;
-use Template::Config;
-use Template::Constants;
-use Template::Exception;
-
-$VERSION = sprintf("%d.%02d", q$Revision: 2.89 $ =~ /(\d+)\.(\d+)/);
-$DEBUG_FORMAT = "\n## \$file line \$line : [% \$text %] ##\n";
-
-
-#========================================================================
-#                     -----  PUBLIC METHODS -----
-#========================================================================
-
-#------------------------------------------------------------------------
-# template($name) 
-#
-# General purpose method to fetch a template and return it in compiled 
-# form.  In the usual case, the $name parameter will be a simple string
-# containing the name of a template (e.g. 'header').  It may also be 
-# a reference to Template::Document object (or sub-class) or a Perl 
-# sub-routine.  These are considered to be compiled templates and are
-# returned intact.  Finally, it may be a reference to any other kind 
-# of valid input source accepted by Template::Provider (e.g. scalar
-# ref, glob, IO handle, etc).
-#
-# Templates may be cached at one of 3 different levels.  The internal
-# BLOCKS member is a local cache which holds references to all
-# template blocks used or imported via PROCESS since the context's
-# reset() method was last called.  This is checked first and if the
-# template is not found, the method then walks down the BLOCKSTACK
-# list.  This contains references to the block definition tables in
-# any enclosing Template::Documents that we're visiting (e.g. we've
-# been called via an INCLUDE and we want to access a BLOCK defined in
-# the template that INCLUDE'd us).  If nothing is defined, then we
-# iterate through the LOAD_TEMPLATES providers list as a 'chain of 
-# responsibility' (see Design Patterns) asking each object to fetch() 
-# the template if it can.
-#
-# Returns the compiled template.  On error, undef is returned and 
-# the internal ERROR value (read via error()) is set to contain an
-# error message of the form "$name: $error".
-#------------------------------------------------------------------------
-
-sub template {
-    my ($self, $name) = @_;
-    my ($prefix, $blocks, $defblocks, $provider, $template, $error);
-    my ($shortname, $blockname, $providers);
-
-    $self->debug("template($name)") if $self->{ DEBUG };
-
-    # references to Template::Document (or sub-class) objects objects, or
-    # CODE references are assumed to be pre-compiled templates and are
-    # returned intact
-    return $name
-        if UNIVERSAL::isa($name, 'Template::Document')
-            || ref($name) eq 'CODE';
-
-    $shortname = $name;
-
-    unless (ref $name) {
-        
-        $self->debug("looking for block [$name]") if $self->{ DEBUG };
-
-        # we first look in the BLOCKS hash for a BLOCK that may have 
-        # been imported from a template (via PROCESS)
-        return $template
-            if ($template = $self->{ BLOCKS }->{ $name });
-        
-        # then we iterate through the BLKSTACK list to see if any of the
-        # Template::Documents we're visiting define this BLOCK
-        foreach $blocks (@{ $self->{ BLKSTACK } }) {
-            return $template
-                if $blocks && ($template = $blocks->{ $name });
-        }
-        
-        # now it's time to ask the providers, so we look to see if any 
-        # prefix is specified to indicate the desired provider set.
-        if ($^O eq 'MSWin32') {
-            # let C:/foo through
-            $prefix = $1 if $shortname =~ s/^(\w{2,})://o;
-        }
-        else {
-            $prefix = $1 if $shortname =~ s/^(\w+)://;
-        }
-        
-        if (defined $prefix) {
-            $providers = $self->{ PREFIX_MAP }->{ $prefix } 
-            || return $self->throw( Template::Constants::ERROR_FILE,
-                                    "no providers for template prefix '$prefix'");
-        }
-    }
-    $providers = $self->{ PREFIX_MAP }->{ default }
-        || $self->{ LOAD_TEMPLATES }
-            unless $providers;
-
-
-    # Finally we try the regular template providers which will 
-    # handle references to files, text, etc., as well as templates
-    # reference by name.  If
-
-    $blockname = '';
-    while ($shortname) {
-        $self->debug("asking providers for [$shortname] [$blockname]") 
-            if $self->{ DEBUG };
-
-        foreach my $provider (@$providers) {
-            ($template, $error) = $provider->fetch($shortname, $prefix);
-            if ($error) {
-                if ($error == Template::Constants::STATUS_ERROR) {
-                    # $template contains exception object
-                    if (UNIVERSAL::isa($template, 'Template::Exception')
-                        && $template->type() eq Template::Constants::ERROR_FILE) {
-                        $self->throw($template);
-                    }
-                    else {
-                        $self->throw( Template::Constants::ERROR_FILE, $template );
-                    }
-                }
-                # DECLINE is ok, carry on
-            }
-            elsif (length $blockname) {
-                return $template 
-                    if $template = $template->blocks->{ $blockname };
-            }
-            else {
-                return $template;
-            }
-        }
-        
-        last if ref $shortname || ! $self->{ EXPOSE_BLOCKS };
-        $shortname =~ s{/([^/]+)$}{} || last;
-        $blockname = length $blockname ? "$1/$blockname" : $1;
-    }
-        
-    $self->throw(Template::Constants::ERROR_FILE, "$name: not found");
-}
-
-
-#------------------------------------------------------------------------
-# plugin($name, \@args)
-#
-# Calls on each of the LOAD_PLUGINS providers in turn to fetch() (i.e. load
-# and instantiate) a plugin of the specified name.  Additional parameters 
-# passed are propagated to the new() constructor for the plugin.  
-# Returns a reference to a new plugin object or other reference.  On 
-# error, undef is returned and the appropriate error message is set for
-# subsequent retrieval via error().
-#------------------------------------------------------------------------
-
-sub plugin {
-    my ($self, $name, $args) = @_;
-    my ($provider, $plugin, $error);
-    
-    $self->debug("plugin($name, ", defined $args ? @$args : '[ ]', ')')
-        if $self->{ DEBUG };
-    
-    # request the named plugin from each of the LOAD_PLUGINS providers in turn
-    foreach my $provider (@{ $self->{ LOAD_PLUGINS } }) {
-        ($plugin, $error) = $provider->fetch($name, $args, $self);
-        return $plugin unless $error;
-        if ($error == Template::Constants::STATUS_ERROR) {
-            $self->throw($plugin) if ref $plugin;
-            $self->throw(Template::Constants::ERROR_PLUGIN, $plugin);
-        }
-    }
-    
-    $self->throw(Template::Constants::ERROR_PLUGIN, "$name: plugin not found");
-}
-
-
-#------------------------------------------------------------------------
-# filter($name, \@args, $alias)
-#
-# Similar to plugin() above, but querying the LOAD_FILTERS providers to 
-# return filter instances.  An alias may be provided which is used to
-# save the returned filter in a local cache.
-#------------------------------------------------------------------------
-
-sub filter {
-    my ($self, $name, $args, $alias) = @_;
-    my ($provider, $filter, $error);
-    
-    $self->debug("filter($name, ", 
-                 defined $args  ? @$args : '[ ]', 
-                 defined $alias ? $alias : '<no alias>', ')')
-        if $self->{ DEBUG };
-    
-    # use any cached version of the filter if no params provided
-    return $filter 
-        if ! $args && ! ref $name
-            && ($filter = $self->{ FILTER_CACHE }->{ $name });
-    
-    # request the named filter from each of the FILTERS providers in turn
-    foreach my $provider (@{ $self->{ LOAD_FILTERS } }) {
-        ($filter, $error) = $provider->fetch($name, $args, $self);
-        last unless $error;
-        if ($error == Template::Constants::STATUS_ERROR) {
-            $self->throw($filter) if ref $filter;
-            $self->throw(Template::Constants::ERROR_FILTER, $filter);
-        }
-        # return $self->error($filter)
-        #    if $error == &Template::Constants::STATUS_ERROR;
-    }
-    
-    return $self->error("$name: filter not found")
-        unless $filter;
-    
-    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-    # commented out by abw on 19 Nov 2001 to fix problem with xmlstyle
-    # plugin which may re-define a filter by calling define_filter()
-    # multiple times.  With the automatic aliasing/caching below, any
-    # new filter definition isn't seen.  Don't think this will cause
-    # any problems as filters explicitly supplied with aliases will
-    # still work as expected.
-    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-    # alias defaults to name if undefined
-    # $alias = $name
-    #     unless defined($alias) or ref($name) or $args;
-
-    # cache FILTER if alias is valid
-    $self->{ FILTER_CACHE }->{ $alias } = $filter
-        if $alias;
-
-    return $filter;
-}
-
-
-#------------------------------------------------------------------------
-# view(\%config)
-# 
-# Create a new Template::View bound to this context.
-#------------------------------------------------------------------------
-
-sub view {
-    my $self = shift;
-    require Template::View;
-    return Template::View->new($self, @_)
-        || $self->throw(&Template::Constants::ERROR_VIEW, 
-                        $Template::View::ERROR);
-}
-
-
-#------------------------------------------------------------------------
-# process($template, \%params)         [% PROCESS template var=val ... %]
-# process($template, \%params, $local) [% INCLUDE template var=val ... %]
-#
-# Processes the template named or referenced by the first parameter.
-# The optional second parameter may reference a hash array of variable
-# definitions.  These are set before the template is processed by
-# calling update() on the stash.  Note that, unless the third parameter
-# is true, the context is not localised and these, and any other
-# variables set in the template will retain their new values after this
-# method returns.  The third parameter is in place so that this method
-# can handle INCLUDE calls: the stash will be localized.
-#
-# Returns the output of processing the template.  Errors are thrown
-# as Template::Exception objects via die().  
-#------------------------------------------------------------------------
-
-sub process {
-    my ($self, $template, $params, $localize) = @_;
-    my ($trim, $blocks) = @$self{ qw( TRIM BLOCKS ) };
-    my (@compiled, $name, $compiled);
-    my ($stash, $component, $tblocks, $error, $tmpout);
-    my $output = '';
-    
-    $template = [ $template ] unless ref $template eq 'ARRAY';
-    
-    $self->debug("process([ ", join(', '), @$template, ' ], ', 
-                 defined $params ? $params : '<no params>', ', ', 
-                 $localize ? '<localized>' : '<unlocalized>', ')')
-        if $self->{ DEBUG };
-    
-    # fetch compiled template for each name specified
-    foreach $name (@$template) {
-        push(@compiled, $self->template($name));
-    }
-
-    if ($localize) {
-        # localise the variable stash with any parameters passed
-        $stash = $self->{ STASH } = $self->{ STASH }->clone($params);
-    } else {
-        # update stash with any new parameters passed
-        $self->{ STASH }->update($params);
-        $stash = $self->{ STASH };
-    }
-
-    eval {
-        # save current component
-        eval { $component = $stash->get('component') };
-
-        foreach $name (@$template) {
-            $compiled = shift @compiled;
-            my $element = ref $compiled eq 'CODE' 
-                ? { (name => (ref $name ? '' : $name), modtime => time()) }
-	        : $compiled;
-
-            if (UNIVERSAL::isa($component, 'Template::Document')) {
-                $element->{ caller } = $component->{ name };
-                $element->{ callers } = $component->{ callers } || [];
-                push(@{$element->{ callers }}, $element->{ caller });
-            }
-
-            $stash->set('component', $element);
-            
-            unless ($localize) {
-                # merge any local blocks defined in the Template::Document
-                # into our local BLOCKS cache
-                @$blocks{ keys %$tblocks } = values %$tblocks
-                    if UNIVERSAL::isa($compiled, 'Template::Document')
-                    && ($tblocks = $compiled->blocks());
-            }
-            
-            if (ref $compiled eq 'CODE') {
-                $tmpout = &$compiled($self);
-            }
-            elsif (ref $compiled) {
-                $tmpout = $compiled->process($self);
-            }
-            else {
-                $self->throw('file', 
-                             "invalid template reference: $compiled");
-            }
-            
-            if ($trim) {
-                for ($tmpout) {
-                    s/^\s+//;
-                    s/\s+$//;
-                }
-            }
-            $output .= $tmpout;
-        }
-        $stash->set('component', $component);
-    };
-    $error = $@;
-    
-    if ($localize) {
-        # ensure stash is delocalised before dying
-        $self->{ STASH } = $self->{ STASH }->declone();
-    }
-    
-    $self->throw(ref $error 
-                 ? $error : (Template::Constants::ERROR_FILE, $error))
-        if $error;
-    
-    return $output;
-}
-
-
-#------------------------------------------------------------------------
-# include($template, \%params)    [% INCLUDE template   var = val, ... %]
-#
-# Similar to process() above but processing the template in a local 
-# context.  Any variables passed by reference to a hash as the second
-# parameter will be set before the template is processed and then 
-# revert to their original values before the method returns.  Similarly,
-# any changes made to non-global variables within the template will 
-# persist only until the template is processed.
-#
-# Returns the output of processing the template.  Errors are thrown
-# as Template::Exception objects via die().  
-#------------------------------------------------------------------------
-
-sub include {
-    my ($self, $template, $params) = @_;
-    return $self->process($template, $params, 'localize me!');
-}
-
-#------------------------------------------------------------------------
-# insert($file)
-#
-# Insert the contents of a file without parsing.
-#------------------------------------------------------------------------
-
-sub insert {
-    my ($self, $file) = @_;
-    my ($prefix, $providers, $text, $error);
-    my $output = '';
-
-    my $files = ref $file eq 'ARRAY' ? $file : [ $file ];
-
-    $self->debug("insert([ ", join(', '), @$files, " ])") 
-        if $self->{ DEBUG };
-
-
-    FILE: foreach $file (@$files) {
-	my $name = $file;
-
-	if ($^O eq 'MSWin32') {
-	    # let C:/foo through
-	    $prefix = $1 if $name =~ s/^(\w{2,})://o;
-	}
-	else {
-	    $prefix = $1 if $name =~ s/^(\w+)://;
-	}
-
-	if (defined $prefix) {
-	    $providers = $self->{ PREFIX_MAP }->{ $prefix } 
-	    || return $self->throw(Template::Constants::ERROR_FILE,
-				   "no providers for file prefix '$prefix'");
-	}
-	else {
-	    $providers = $self->{ PREFIX_MAP }->{ default }
-	    || $self->{ LOAD_TEMPLATES };
-	}
-
-	foreach my $provider (@$providers) {
-	    ($text, $error) = $provider->load($name, $prefix);
-	    next FILE unless $error;
-	    if ($error == Template::Constants::STATUS_ERROR) {
-		$self->throw($text) if ref $text;
-		$self->throw(Template::Constants::ERROR_FILE, $text);
-	    }
-	}
-	$self->throw(Template::Constants::ERROR_FILE, "$file: not found");
-    }
-    continue {
-	$output .= $text;
-    }
-    return $output;
-}
-
-
-#------------------------------------------------------------------------
-# throw($type, $info, \$output)          [% THROW errtype "Error info" %]
-#
-# Throws a Template::Exception object by calling die().  This method
-# may be passed a reference to an existing Template::Exception object;
-# a single value containing an error message which is used to
-# instantiate a Template::Exception of type 'undef'; or a pair of
-# values representing the exception type and info from which a
-# Template::Exception object is instantiated.  e.g.
-#
-#   $context->throw($exception);
-#   $context->throw("I'm sorry Dave, I can't do that");
-#   $context->throw('denied', "I'm sorry Dave, I can't do that");
-#
-# An optional third parameter can be supplied in the last case which 
-# is a reference to the current output buffer containing the results
-# of processing the template up to the point at which the exception 
-# was thrown.  The RETURN and STOP directives, for example, use this 
-# to propagate output back to the user, but it can safely be ignored
-# in most cases.
-# 
-# This method rides on a one-way ticket to die() oblivion.  It does not 
-# return in any real sense of the word, but should get caught by a 
-# surrounding eval { } block (e.g. a BLOCK or TRY) and handled 
-# accordingly, or returned to the caller as an uncaught exception.
-#------------------------------------------------------------------------
-
-sub throw {
-    my ($self, $error, $info, $output) = @_;
-    local $" = ', ';
-
-    # die! die! die!
-    if (UNIVERSAL::isa($error, 'Template::Exception')) {
-	die $error;
-    }
-    elsif (defined $info) {
-	die (Template::Exception->new($error, $info, $output));
-    }
-    else {
-	$error ||= '';
-	die (Template::Exception->new('undef', $error, $output));
-    }
-
-    # not reached
-}
-
-
-#------------------------------------------------------------------------
-# catch($error, \$output)
-#
-# Called by various directives after catching an error thrown via die()
-# from within an eval { } block.  The first parameter contains the errror
-# which may be a sanitized reference to a Template::Exception object
-# (such as that raised by the throw() method above, a plugin object, 
-# and so on) or an error message thrown via die from somewhere in user
-# code.  The latter are coerced into 'undef' Template::Exception objects.
-# Like throw() above, a reference to a scalar may be passed as an
-# additional parameter to represent the current output buffer
-# localised within the eval block.  As exceptions are thrown upwards
-# and outwards from nested blocks, the catch() method reconstructs the
-# correct output buffer from these fragments, storing it in the
-# exception object for passing further onwards and upwards.
-#
-# Returns a reference to a Template::Exception object..
-#------------------------------------------------------------------------
-
-sub catch {
-    my ($self, $error, $output) = @_;
-
-    if (UNIVERSAL::isa($error, 'Template::Exception')) {
-	$error->text($output) if $output;
-	return $error;
-    }
-    else {
-	return Template::Exception->new('undef', $error, $output);
-    }
-}
-
-
-#------------------------------------------------------------------------
-# localise(\%params)
-# delocalise()
-#
-# The localise() method creates a local copy of the current stash,
-# allowing the existing state of variables to be saved and later 
-# restored via delocalise().
-#
-# A reference to a hash array may be passed containing local variable 
-# definitions which should be added to the cloned namespace.  These 
-# values persist until delocalisation.
-#------------------------------------------------------------------------
-
-sub localise {
-    my $self = shift;
-    $self->{ STASH } = $self->{ STASH }->clone(@_);
-}
-
-sub delocalise {
-    my $self = shift;
-    $self->{ STASH } = $self->{ STASH }->declone();
-}
-
-
-#------------------------------------------------------------------------
-# visit($document, $blocks)
-#
-# Each Template::Document calls the visit() method on the context
-# before processing itself.  It passes a reference to the hash array
-# of named BLOCKs defined within the document, allowing them to be 
-# added to the internal BLKSTACK list which is subsequently used by
-# template() to resolve templates.
-# from a provider.
-#------------------------------------------------------------------------
-
-sub visit {
-    my ($self, $document, $blocks) = @_;
-    unshift(@{ $self->{ BLKSTACK } }, $blocks)
-}
-
-
-#------------------------------------------------------------------------
-# leave()
-#
-# The leave() method is called when the document has finished
-# processing itself.  This removes the entry from the BLKSTACK list
-# that was added visit() above.  For persistance of BLOCK definitions,
-# the process() method (i.e. the PROCESS directive) does some extra
-# magic to copy BLOCKs into a shared hash.
-#------------------------------------------------------------------------
-
-sub leave {
-    my $self = shift;
-    shift(@{ $self->{ BLKSTACK } });
-}
-
-
-#------------------------------------------------------------------------
-# define_block($name, $block)
-#
-# Adds a new BLOCK definition to the local BLOCKS cache.  $block may
-# be specified as a reference to a sub-routine or Template::Document
-# object or as text which is compiled into a template.  Returns a true
-# value (the $block reference or compiled block reference) if
-# succesful or undef on failure.  Call error() to retrieve the
-# relevent error message (i.e. compilation failure).
-#------------------------------------------------------------------------
-
-sub define_block {
-    my ($self, $name, $block) = @_;
-    $block = $self->template(\$block)
-	|| return undef
-	    unless ref $block;
-    $self->{ BLOCKS }->{ $name } = $block;
-}
-
-
-#------------------------------------------------------------------------
-# define_filter($name, $filter, $is_dynamic)
-#
-# Adds a new FILTER definition to the local FILTER_CACHE.
-#------------------------------------------------------------------------
-
-sub define_filter {
-    my ($self, $name, $filter, $is_dynamic) = @_;
-    my ($result, $error);
-    $filter = [ $filter, 1 ] if $is_dynamic;
-
-    foreach my $provider (@{ $self->{ LOAD_FILTERS } }) {
-	($result, $error) = $provider->store($name, $filter);
-	return 1 unless $error;
-	$self->throw(&Template::Constants::ERROR_FILTER, $result)
-	    if $error == &Template::Constants::STATUS_ERROR;
-    }
-    $self->throw(&Template::Constants::ERROR_FILTER, 
-		 "FILTER providers declined to store filter $name");
-}
-
-
-#------------------------------------------------------------------------
-# reset()
-# 
-# Reset the state of the internal BLOCKS hash to clear any BLOCK 
-# definitions imported via the PROCESS directive.  Any original 
-# BLOCKS definitions passed to the constructor will be restored.
-#------------------------------------------------------------------------
-
-sub reset {
-    my ($self, $blocks) = @_;
-    $self->{ BLKSTACK } = [ ];
-    $self->{ BLOCKS   } = { %{ $self->{ INIT_BLOCKS } } };
-}
-
-
-#------------------------------------------------------------------------
-# stash()
-#
-# Simple accessor methods to return the STASH values.  This is likely
-# to be called quite often so we provide a direct method rather than
-# relying on the slower AUTOLOAD.
-#------------------------------------------------------------------------
-
-sub stash {
-    return $_[0]->{ STASH };
-}
-
-
-#------------------------------------------------------------------------
-# define_vmethod($type, $name, \&sub)
-#
-# Passes $type, $name, and &sub on to stash->define_vmethod().
-#------------------------------------------------------------------------
-sub define_vmethod {
-    my $self = shift;
-    $self->stash->define_vmethod(@_);
-}
-
-
-#------------------------------------------------------------------------
-# debugging($command, @args, \%params)
-#
-# Method for controlling the debugging status of the context.  The first
-# argument can be 'on' or 'off' to enable/disable debugging, 'format'
-# to define the format of the debug message, or 'msg' to generate a 
-# debugging message reporting the file, line, message text, etc., 
-# according to the current debug format.
-#------------------------------------------------------------------------
-
-sub debugging {
-    my $self = shift;
-    my $hash = ref $_[-1] eq 'HASH' ? pop : { };
-    my @args = @_;
-
-#    print "*** debug(@args)\n";
-    if (@args) {
-	if ($args[0] =~ /^on|1$/i) {
-	    $self->{ DEBUG_DIRS } = 1;
-	    shift(@args);
-	}
-	elsif ($args[0] =~ /^off|0$/i) {
-	    $self->{ DEBUG_DIRS } = 0;
-	    shift(@args);
-	}
-    }
-
-    if (@args) {
-	if ($args[0] =~ /^msg$/i) {
-            return unless $self->{ DEBUG_DIRS };
-	    my $format = $self->{ DEBUG_FORMAT };
-	    $format = $DEBUG_FORMAT unless defined $format;
-	    $format =~ s/\$(\w+)/$hash->{ $1 }/ge;
-	    return $format;
-	}
-	elsif ($args[0] =~ /^format$/i) {
-	    $self->{ DEBUG_FORMAT } = $args[1];
-	}
-	# else ignore
-    }
-
-    return '';
-}
-
-
-#------------------------------------------------------------------------
-# AUTOLOAD
-#
-# Provides pseudo-methods for read-only access to various internal 
-# members.  For example, templates(), plugins(), filters(),
-# eval_perl(), load_perl(), etc.  These aren't called very often, or
-# may never be called at all.
-#------------------------------------------------------------------------
-
-sub AUTOLOAD {
-    my $self   = shift;
-    my $method = $AUTOLOAD;
-    my $result;
-
-    $method =~ s/.*:://;
-    return if $method eq 'DESTROY';
-
-    warn "no such context method/member: $method\n"
-	unless defined ($result = $self->{ uc $method });
-
-    return $result;
-}
-
-
-#------------------------------------------------------------------------
-# DESTROY
-#
-# Stash may contain references back to the Context via macro closures,
-# etc.  This breaks the circular references. 
-#------------------------------------------------------------------------
-
-sub DESTROY {
-    my $self = shift;
-    undef $self->{ STASH };
-}
-
-
-
-#========================================================================
-#                     -- PRIVATE METHODS --
-#========================================================================
-
-#------------------------------------------------------------------------
-# _init(\%config)
-#
-# Initialisation method called by Template::Base::new()
-#------------------------------------------------------------------------
-
-sub _init {
-    my ($self, $config) = @_;
-    my ($name, $item, $method, $block, $blocks);
-    my @itemlut = ( 
-	LOAD_TEMPLATES => 'provider',
-	LOAD_PLUGINS   => 'plugins',
-	LOAD_FILTERS   => 'filters' 
-    );
-
-    # LOAD_TEMPLATE, LOAD_PLUGINS, LOAD_FILTERS - lists of providers
-    while (($name, $method) = splice(@itemlut, 0, 2)) {
-	$item = $config->{ $name } 
-	     || Template::Config->$method($config)
-	     || return $self->error($Template::Config::ERROR);
-	$self->{ $name } = ref $item eq 'ARRAY' ? $item : [ $item ];
-    }
-
-    my $providers  = $self->{ LOAD_TEMPLATES };
-    my $prefix_map = $self->{ PREFIX_MAP } = $config->{ PREFIX_MAP } || { };
-    while (my ($key, $val) = each %$prefix_map) {
-	$prefix_map->{ $key } = [ ref $val ? $val :
-				  map { $providers->[$_] } 
-				  split(/\D+/, $val) ]
-	    unless ref $val eq 'ARRAY';
-#	print(STDERR "prefix $key => $val => [", 
-#	      join(', ', @{ $prefix_map->{ $key } }), "]\n");
-    }
-
-    # STASH
-    $self->{ STASH } = $config->{ STASH } || do {
-      	my $predefs  = $config->{ VARIABLES } 
-		    || $config->{ PRE_DEFINE } 
-		    || { };
-
-	# hack to get stash to know about debug mode
-	$predefs->{ _DEBUG } = ( ($config->{ DEBUG } || 0)
-                               & &Template::Constants::DEBUG_UNDEF ) ? 1 : 0
-            unless defined $predefs->{ _DEBUG };
-                                
-	Template::Config->stash($predefs)
-	    || return $self->error($Template::Config::ERROR);
-    };
-
-    # compile any template BLOCKS specified as text
-    $blocks = $config->{ BLOCKS } || { };
-    $self->{ INIT_BLOCKS } = $self->{ BLOCKS } = { 
-	map {
-	    $block = $blocks->{ $_ };
-	    $block = $self->template(\$block)
-		|| return undef
-		    unless ref $block;
-	    ($_ => $block);
-	} 
-	keys %$blocks
-    };
-
-    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-    # RECURSION - flag indicating is recursion into templates is supported
-    # EVAL_PERL - flag indicating if PERL blocks should be processed
-    # TRIM      - flag to remove leading and trailing whitespace from output
-    # BLKSTACK  - list of hashes of BLOCKs defined in current template(s)
-    # CONFIG    - original configuration hash
-    # EXPOSE_BLOCKS - make blocks visible as pseudo-files
-    # DEBUG_FORMAT  - format for generating template runtime debugging messages
-    # DEBUG         - format for generating template runtime debugging messages
-
-    $self->{ RECURSION } = $config->{ RECURSION } || 0;
-    $self->{ EVAL_PERL } = $config->{ EVAL_PERL } || 0;
-    $self->{ TRIM      } = $config->{ TRIM } || 0;
-    $self->{ BLKSTACK  } = [ ];
-    $self->{ CONFIG    } = $config;
-    $self->{ EXPOSE_BLOCKS } = defined $config->{ EXPOSE_BLOCKS }
-                                     ? $config->{ EXPOSE_BLOCKS } 
-                                     : 0;
-
-    $self->{ DEBUG_FORMAT  } =  $config->{ DEBUG_FORMAT };
-    $self->{ DEBUG_DIRS    } = ($config->{ DEBUG } || 0) 
-                               & Template::Constants::DEBUG_DIRS;
-    $self->{ DEBUG } = defined $config->{ DEBUG } 
-        ? $config->{ DEBUG } & ( Template::Constants::DEBUG_CONTEXT
-                               | Template::Constants::DEBUG_FLAGS )
-        : $DEBUG;
-
-    return $self;
-}
-
-
-#------------------------------------------------------------------------
-# _dump()
-#
-# Debug method which returns a string representing the internal state
-# of the context object.
-#------------------------------------------------------------------------
-
-sub _dump {
-    my $self = shift;
-    my $output = "[Template::Context] {\n";
-    my $format = "    %-16s => %s\n";
-    my $key;
-
-    foreach $key (qw( RECURSION EVAL_PERL TRIM )) {
-	$output .= sprintf($format, $key, $self->{ $key });
-    }
-    foreach my $pname (qw( LOAD_TEMPLATES LOAD_PLUGINS LOAD_FILTERS )) {
-	my $provtext = "[\n";
-	foreach my $prov (@{ $self->{ $pname } }) {
-	    $provtext .= $prov->_dump();
-#	    $provtext .= ",\n";
-	}
-	$provtext =~ s/\n/\n        /g;
-	$provtext =~ s/\s+$//;
-	$provtext .= ",\n    ]";
-	$output .= sprintf($format, $pname, $provtext);
-    }
-    $output .= sprintf($format, STASH => $self->{ STASH }->_dump());
-    $output .= '}';
-    return $output;
-}
-
-
-1;
-
-__END__
-
-
-#------------------------------------------------------------------------
-# IMPORTANT NOTE
-#   This documentation is generated automatically from source
-#   templates.  Any changes you make here may be lost.
-# 
-#   The 'docsrc' documentation source bundle is available for download
-#   from http://www.template-toolkit.org/docs.html and contains all
-#   the source templates, XML files, scripts, etc., from which the
-#   documentation for the Template Toolkit is built.
-#------------------------------------------------------------------------
-
-=head1 NAME
-
-Template::Context - Runtime context in which templates are processed
-
-=head1 SYNOPSIS
-
-    use Template::Context;
-
-    # constructor
-    $context = Template::Context->new(\%config)
-	|| die $Template::Context::ERROR;
-
-    # fetch (load and compile) a template
-    $template = $context->template($template_name);
-
-    # fetch (load and instantiate) a plugin object
-    $plugin = $context->plugin($name, \@args);
-
-    # fetch (return or create) a filter subroutine
-    $filter = $context->filter($name, \@args, $alias);
-
-    # process/include a template, errors are thrown via die()
-    $output = $context->process($template, \%vars);
-    $output = $context->include($template, \%vars);
-
-    # raise an exception via die()
-    $context->throw($error_type, $error_message, \$output_buffer);
-
-    # catch an exception, clean it up and fix output buffer
-    $exception = $context->catch($exception, \$output_buffer);
-
-    # save/restore the stash to effect variable localisation
-    $new_stash = $context->localise(\%vars);
-    $old_stash = $context->delocalise();
-
-    # add new BLOCK or FILTER definitions
-    $context->define_block($name, $block);
-    $context->define_filter($name, \&filtersub, $is_dynamic);
-
-    # reset context, clearing any imported BLOCK definitions
-    $context->reset();
-
-    # methods for accessing internal items
-    $stash     = $context->stash();
-    $tflag     = $context->trim();
-    $epflag    = $context->eval_perl();
-    $providers = $context->templates();
-    $providers = $context->plugins();
-    $providers = $context->filters();
-    ...
-
-=head1 DESCRIPTION
-
-The Template::Context module defines an object class for representing
-a runtime context in which templates are processed.  It provides an
-interface to the fundamental operations of the Template Toolkit
-processing engine through which compiled templates (i.e. Perl code
-constructed from the template source) can process templates, load
-plugins and filters, raise exceptions and so on.
-
-A default Template::Context object is created by the Template module.
-Any Template::Context options may be passed to the Template new()
-constructor method and will be forwarded to the Template::Context
-constructor.
-
-    use Template;
-    
-    my $template = Template->new({
-	TRIM      => 1,
-	EVAL_PERL => 1,
-	BLOCKS    => {
-	    header => 'This is the header',
-	    footer => 'This is the footer',
-	},
-    });
-
-Similarly, the Template::Context constructor will forward all configuration
-parameters onto other default objects (e.g. Template::Provider, Template::Plugins,
-Template::Filters, etc.) that it may need to instantiate.
-
-    $context = Template::Context->new({
-	INCLUDE_PATH => '/home/abw/templates', # provider option
-	TAG_STYLE    => 'html',                # parser option
-    });
-
-A Template::Context object (or subclass/derivative) can be explicitly
-instantiated and passed to the Template new() constructor method as 
-the CONTEXT item.
-
-    use Template;
-    use Template::Context;
-
-    my $context  = Template::Context->new({ TRIM => 1 });
-    my $template = Template->new({ CONTEXT => $context });
-
-The Template module uses the Template::Config context() factory method
-to create a default context object when required.  The
-$Template::Config::CONTEXT package variable may be set to specify an
-alternate context module.  This will be loaded automatically and its
-new() constructor method called by the context() factory method when
-a default context object is required.
-
-    use Template;
-
-    $Template::Config::CONTEXT = 'MyOrg::Template::Context';
-
-    my $template = Template->new({
-	EVAL_PERL   => 1,
-	EXTRA_MAGIC => 'red hot',  # your extra config items
-	...
-    });
-
-=head1 METHODS
-
-=head2 new(\%params) 
-
-The new() constructor method is called to instantiate a Template::Context
-object.  Configuration parameters may be specified as a HASH reference or
-as a list of (name =E<gt> value) pairs.
-
-    my $context = Template::Context->new({
-	INCLUDE_PATH => 'header',
-	POST_PROCESS => 'footer',
-    });
-
-    my $context = Template::Context->new( EVAL_PERL => 1 );
-
-The new() method returns a Template::Context object (or sub-class) or
-undef on error.  In the latter case, a relevant error message can be
-retrieved by the error() class method or directly from the
-$Template::Context::ERROR package variable.
-
-    my $context = Template::Context->new(\%config)
-	|| die Template::Context->error();
-
-    my $context = Template::Context->new(\%config)
-	|| die $Template::Context::ERROR;
-
-The following configuration items may be specified.
-
-=over 4
-
-
-=item VARIABLES, PRE_DEFINE
-
-The VARIABLES option (or PRE_DEFINE - they're equivalent) can be used
-to specify a hash array of template variables that should be used to
-pre-initialise the stash when it is created.  These items are ignored
-if the STASH item is defined.
-
-    my $context = Template::Context->new({
-	VARIABLES => {
-	    title   => 'A Demo Page',
-	    author  => 'Joe Random Hacker',
-	    version => 3.14,
-	},
-    };
-
-or
-
-    my $context = Template::Context->new({
-	PRE_DEFINE => {
-	    title   => 'A Demo Page',
-	    author  => 'Joe Random Hacker',
-	    version => 3.14,
-	},
-    };
-
-
-
-
-
-=item BLOCKS
-
-The BLOCKS option can be used to pre-define a default set of template 
-blocks.  These should be specified as a reference to a hash array 
-mapping template names to template text, subroutines or Template::Document
-objects.
-
-    my $context = Template::Context->new({
-	BLOCKS => {
-	    header  => 'The Header.  [% title %]',
-	    footer  => sub { return $some_output_text },
-	    another => Template::Document->new({ ... }),
-	},
-    }); 
-
-
-
-
-
-=item TRIM
-
-The TRIM option can be set to have any leading and trailing whitespace 
-automatically removed from the output of all template files and BLOCKs.
-
-By example, the following BLOCK definition
-
-    [% BLOCK foo %]
-    Line 1 of foo
-    [% END %]
-
-will be processed is as "\nLine 1 of foo\n".  When INCLUDEd, the surrounding
-newlines will also be introduced.
-
-    before 
-    [% INCLUDE foo %]
-    after
-
-output:
-    before
-
-    Line 1 of foo
-
-    after
-
-With the TRIM option set to any true value, the leading and trailing
-newlines (which count as whitespace) will be removed from the output 
-of the BLOCK.
-
-    before
-    Line 1 of foo
-    after
-
-The TRIM option is disabled (0) by default.
-
-
-
-
-
-
-=item EVAL_PERL
-
-This flag is used to indicate if PERL and/or RAWPERL blocks should be
-evaluated.  By default, it is disabled and any PERL or RAWPERL blocks
-encountered will raise exceptions of type 'perl' with the message
-'EVAL_PERL not set'.  Note however that any RAWPERL blocks should
-always contain valid Perl code, regardless of the EVAL_PERL flag.  The
-parser will fail to compile templates that contain invalid Perl code
-in RAWPERL blocks and will throw a 'file' exception.
-
-When using compiled templates (see 
-L<COMPILE_EXT|Template::Manual::Config/Caching_and_Compiling_Options> and 
-L<COMPILE_DIR|Template::Manual::Config/Caching_and_Compiling_Options>),
-the EVAL_PERL has an affect when the template is compiled, and again
-when the templates is subsequently processed, possibly in a different
-context to the one that compiled it.
-
-If the EVAL_PERL is set when a template is compiled, then all PERL and
-RAWPERL blocks will be included in the compiled template.  If the 
-EVAL_PERL option isn't set, then Perl code will be generated which 
-B<always> throws a 'perl' exception with the message 'EVAL_PERL not
-set' B<whenever> the compiled template code is run.
-
-Thus, you must have EVAL_PERL set if you want your compiled templates
-to include PERL and RAWPERL blocks.
-
-At some point in the future, using a different invocation of the
-Template Toolkit, you may come to process such a pre-compiled
-template.  Assuming the EVAL_PERL option was set at the time the
-template was compiled, then the output of any RAWPERL blocks will be
-included in the compiled template and will get executed when the
-template is processed.  This will happen regardless of the runtime
-EVAL_PERL status.
-
-Regular PERL blocks are a little more cautious, however.  If the 
-EVAL_PERL flag isn't set for the I<current> context, that is, the 
-one which is trying to process it, then it will throw the familiar 'perl'
-exception with the message, 'EVAL_PERL not set'.
-
-Thus you can compile templates to include PERL blocks, but optionally
-disable them when you process them later.  Note however that it is 
-possible for a PERL block to contain a Perl "BEGIN { # some code }"
-block which will always get run regardless of the runtime EVAL_PERL
-status.  Thus, if you set EVAL_PERL when compiling templates, it is
-assumed that you trust the templates to Do The Right Thing.  Otherwise
-you must accept the fact that there's no bulletproof way to prevent 
-any included code from trampling around in the living room of the 
-runtime environment, making a real nuisance of itself if it really
-wants to.  If you don't like the idea of such uninvited guests causing
-a bother, then you can accept the default and keep EVAL_PERL disabled.
-
-
-
-
-
-
-
-=item RECURSION
-
-The template processor will raise a file exception if it detects
-direct or indirect recursion into a template.  Setting this option to 
-any true value will allow templates to include each other recursively.
-
-
-
-=item LOAD_TEMPLATES
-
-The LOAD_TEMPLATE option can be used to provide a reference to a list
-of Template::Provider objects or sub-classes thereof which will take
-responsibility for loading and compiling templates.
-
-    my $context = Template::Context->new({
-	LOAD_TEMPLATES => [
-    	    MyOrg::Template::Provider->new({ ... }),
-    	    Template::Provider->new({ ... }),
-	],
-    });
-
-When a PROCESS, INCLUDE or WRAPPER directive is encountered, the named
-template may refer to a locally defined BLOCK or a file relative to
-the INCLUDE_PATH (or an absolute or relative path if the appropriate
-ABSOLUTE or RELATIVE options are set).  If a BLOCK definition can't be
-found (see the Template::Context template() method for a discussion of
-BLOCK locality) then each of the LOAD_TEMPLATES provider objects is
-queried in turn via the fetch() method to see if it can supply the
-required template.  Each provider can return a compiled template, an
-error, or decline to service the request in which case the
-responsibility is passed to the next provider.  If none of the
-providers can service the request then a 'not found' error is
-returned.  The same basic provider mechanism is also used for the 
-INSERT directive but it bypasses any BLOCK definitions and doesn't
-attempt is to parse or process the contents of the template file.
-
-This is an implementation of the 'Chain of Responsibility'
-design pattern as described in 
-"Design Patterns", Erich Gamma, Richard Helm, Ralph Johnson, John 
-Vlissides), Addision-Wesley, ISBN 0-201-63361-2, page 223
-.
-
-If LOAD_TEMPLATES is undefined, a single default provider will be
-instantiated using the current configuration parameters.  For example,
-the Template::Provider INCLUDE_PATH option can be specified in the Template::Context configuration and will be correctly passed to the provider's
-constructor method.
-
-    my $context = Template::Context->new({
-	INCLUDE_PATH => '/here:/there',
-    });
-
-
-
-
-
-=item LOAD_PLUGINS
-
-The LOAD_PLUGINS options can be used to specify a list of provider
-objects (i.e. they implement the fetch() method) which are responsible
-for loading and instantiating template plugin objects.  The
-Template::Content plugin() method queries each provider in turn in a
-"Chain of Responsibility" as per the template() and filter() methods.
-
-    my $context = Template::Context->new({
-	LOAD_PLUGINS => [
-    	    MyOrg::Template::Plugins->new({ ... }),
-    	    Template::Plugins->new({ ... }),
-	],
-    });
-
-By default, a single Template::Plugins object is created using the 
-current configuration hash.  Configuration items destined for the 
-Template::Plugins constructor may be added to the Template::Context 
-constructor.
-
-    my $context = Template::Context->new({
-	PLUGIN_BASE => 'MyOrg::Template::Plugins',
-	LOAD_PERL   => 1,
-    });
-
-
-
-
-
-=item LOAD_FILTERS
-
-The LOAD_FILTERS option can be used to specify a list of provider
-objects (i.e. they implement the fetch() method) which are responsible
-for returning and/or creating filter subroutines.  The
-Template::Context filter() method queries each provider in turn in a
-"Chain of Responsibility" as per the template() and plugin() methods.
-
-    my $context = Template::Context->new({
-	LOAD_FILTERS => [
-    	    MyTemplate::Filters->new(),
-    	    Template::Filters->new(),
-	],
-    });
-
-By default, a single Template::Filters object is created for the
-LOAD_FILTERS list.
-
-
-
-=item STASH
-
-A reference to a Template::Stash object or sub-class which will take
-responsibility for managing template variables.  
-
-    my $stash = MyOrg::Template::Stash->new({ ... });
-    my $context = Template::Context->new({
-	STASH => $stash,
-    });
-
-If unspecified, a default stash object is created using the VARIABLES
-configuration item to initialise the stash variables.  These may also
-be specified as the PRE_DEFINE option for backwards compatibility with 
-version 1.
-
-    my $context = Template::Context->new({
-	VARIABLES => {
-	    id    => 'abw',
-	    name  => 'Andy Wardley',
-	},
-    };
-
-
-
-=item DEBUG
-
-The DEBUG option can be used to enable various debugging features
-of the Template::Context module.  
-
-    use Template::Constants qw( :debug );
-
-    my $template = Template->new({
-	DEBUG => DEBUG_CONTEXT | DEBUG_DIRS,
-    });
-
-The DEBUG value can include any of the following.  Multiple values
-should be combined using the logical OR operator, '|'.
-
-=over 4
-
-=item DEBUG_CONTEXT
-
-Enables general debugging messages for the
-L<Template::Context|Template::Context> module.
-
-=item DEBUG_DIRS
-
-This option causes the Template Toolkit to generate comments
-indicating the source file, line and original text of each directive
-in the template.  These comments are embedded in the template output
-using the format defined in the DEBUG_FORMAT configuration item, or a
-simple default format if unspecified.
-
-For example, the following template fragment:
-
-    
-    Hello World
-
-would generate this output:
-
-    ## input text line 1 :  ##
-    Hello 
-    ## input text line 2 : World ##
-    World
-
-
-=back
-
-
-
-
-
-=back
-
-=head2 template($name) 
-
-Returns a compiled template by querying each of the LOAD_TEMPLATES providers
-(instances of Template::Provider, or sub-class) in turn.  
-
-    $template = $context->template('header');
-
-On error, a Template::Exception object of type 'file' is thrown via
-die().  This can be caught by enclosing the call to template() in an
-eval block and examining $@.
-
-    eval {
-	$template = $context->template('header');
-    };
-    if ($@) {
-	print "failed to fetch template: $@\n";
-    }
-
-=head2 plugin($name, \@args)
-
-Instantiates a plugin object by querying each of the LOAD_PLUGINS
-providers.  The default LOAD_PLUGINS provider is a Template::Plugins
-object which attempts to load plugin modules, according the various
-configuration items such as PLUGIN_BASE, LOAD_PERL, etc., and then
-instantiate an object via new().  A reference to a list of constructor
-arguments may be passed as the second parameter.  These are forwarded
-to the plugin constructor.
-
-Returns a reference to a plugin (which is generally an object, but
-doesn't have to be).  Errors are thrown as Template::Exception objects
-of type 'plugin'.
-
-    $plugin = $context->plugin('DBI', 'dbi:msql:mydbname');
-
-=head2 filter($name, \@args, $alias)
-
-Instantiates a filter subroutine by querying the LOAD_FILTERS providers.
-The default LOAD_FILTERS providers is a Template::Filters object.
-Additional arguments may be passed by list reference along with an
-optional alias under which the filter will be cached for subsequent
-use.  The filter is cached under its own $name if $alias is undefined.
-Subsequent calls to filter($name) will return the cached entry, if
-defined.  Specifying arguments bypasses the caching mechanism and
-always creates a new filter.  Errors are thrown as Template::Exception
-objects of typre 'filter'.
-
-    # static filter (no args)
-    $filter = $context->filter('html');
-
-    # dynamic filter (args) aliased to 'padright'
-    $filter = $context->filter('format', '%60s', 'padright');
-
-    # retrieve previous filter via 'padright' alias
-    $filter = $context->filter('padright');
-
-=head2 process($template, \%vars)
-
-Processes a template named or referenced by the first parameter and returns
-the output generated.  An optional reference to a hash array may be passed
-as the second parameter, containing variable definitions which will be set
-before the template is processed.  The template is processed in the current
-context, with no localisation of variables performed.   Errors are thrown
-as Template::Exception objects via die().  
-
-    $output = $context->process('header', { title => 'Hello World' });
-
-=head2 include($template, \%vars)
-
-Similar to process() above, but using localised variables.  Changes made to
-any variables will only persist until the include() method completes.
-
-    $output = $context->include('header', { title => 'Hello World' });
-
-=head2 throw($error_type, $error_message, \$output)
-
-Raises an exception in the form of a Template::Exception object by
-calling die().  This method may be passed a reference to an existing
-Template::Exception object; a single value containing an error message
-which is used to instantiate a Template::Exception of type 'undef'; or
-a pair of values representing the exception type and info from which a
-Template::Exception object is instantiated.  e.g.
-
-    $context->throw($exception);
-    $context->throw("I'm sorry Dave, I can't do that");
-    $context->throw('denied', "I'm sorry Dave, I can't do that");
-
-The optional third parameter may be a reference to the current output
-buffer.  This is then stored in the exception object when created,
-allowing the catcher to examine and use the output up to the point at
-which the exception was raised.
-
-    $output .= 'blah blah blah';
-    $output .= 'more rhubarb';
-    $context->throw('yack', 'Too much yacking', \$output);
-
-=head2 catch($exception, \$output)
-
-Catches an exception thrown, either as a reference to a
-Template::Exception object or some other value.  In the latter case,
-the error string is promoted to a Template::Exception object of
-'undef' type.  This method also accepts a reference to the current
-output buffer which is passed to the Template::Exception constructor,
-or is appended to the output buffer stored in an existing
-Template::Exception object, if unique (i.e. not the same reference).
-By this process, the correct state of the output buffer can be
-reconstructed for simple or nested throws.
-
-=head2 define_block($name, $block)
-
-Adds a new block definition to the internal BLOCKS cache.  The first 
-argument should contain the name of the block and the second a reference
-to a Template::Document object or template sub-routine, or template text
-which is automatically compiled into a template sub-routine.  Returns
-a true value (the sub-routine or Template::Document reference) on 
-success or undef on failure.  The relevant error message can be 
-retrieved by calling the error() method.
-
-=head2 define_filter($name, \&filter, $is_dynamic)
-
-Adds a new filter definition by calling the store() method on each of
-the LOAD_FILTERS providers until accepted (in the usual case, this is
-accepted straight away by the one and only Template::Filters
-provider).  The first argument should contain the name of the filter
-and the second a reference to a filter subroutine.  The optional 
-third argument can be set to any true value to indicate that the 
-subroutine is a dynamic filter factory.  Returns a true value or
-throws a 'filter' exception on error.
-
-=head2 localise(\%vars)
-
-Clones the stash to create a context with localised variables.  Returns a 
-reference to the newly cloned stash object which is also stored
-internally.
-
-    $stash = $context->localise();
-
-=head2 delocalise()
-
-Restore the stash to its state prior to localisation.
-
-    $stash = $context->delocalise();
-
-=head2 visit(\%blocks)
-
-This method is called by Template::Document objects immediately before
-they process their content.  It is called to register any local BLOCK
-definitions with the context object so that they may be subsequently
-delivered on request.
-
-=head2 leave()
-
-Compliment to visit(), above.  Called by Template::Document objects 
-immediately after they process their content.
-
-=head2 reset()
-
-Clears the local BLOCKS cache of any BLOCK definitions.  Any initial set of
-BLOCKS specified as a configuration item to the constructor will be reinstated.
-
-=head2 AUTOLOAD
-
-An AUTOLOAD method provides access to context configuration items.
-
-    $stash     = $context->stash();
-    $tflag     = $context->trim();
-    $epflag    = $context->eval_perl();
-    ...
-
-=head1 AUTHOR
-
-Andy Wardley E<lt>abw@andywardley.comE<gt>
-
-L<http://www.andywardley.com/|http://www.andywardley.com/>
-
-
-
-
-=head1 VERSION
-
-2.89, distributed as part of the
-Template Toolkit version 2.13, released on 30 January 2004.
-
-=head1 COPYRIGHT
-
-  Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
-  Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
-
-This module is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
-
-=head1 SEE ALSO
-
-L<Template|Template>, L<Template::Document|Template::Document>, L<Template::Exception|Template::Exception>, L<Template::Filters|Template::Filters>, L<Template::Plugins|Template::Plugins>, L<Template::Provider|Template::Provider>, L<Template::Service|Template::Service>, L<Template::Stash|Template::Stash>
-
-=cut
-
-# Local Variables:
-# mode: perl
-# perl-indent-level: 4
-# indent-tabs-mode: nil
-# End:
-#
-# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Directive.pm b/lib/Template/Directive.pm
deleted file mode 100644
index c3f86a9..0000000
--- a/lib/Template/Directive.pm
+++ /dev/null
@@ -1,1004 +0,0 @@
-#================================================================= -*-Perl-*- 
-#
-# Template::Directive
-#
-# DESCRIPTION
-#   Factory module for constructing templates from Perl code.
-#
-# AUTHOR
-#   Andy Wardley   <abw@kfs.org>
-#
-# WARNING
-#   Much of this module is hairy, even furry in places.  It needs
-#   a lot of tidying up and may even be moved into a different place 
-#   altogether.  The generator code is often inefficient, particulary in 
-#   being very anal about pretty-printing the Perl code all neatly, but 
-#   at the moment, that's still high priority for the sake of easier
-#   debugging.
-#
-# COPYRIGHT
-#   Copyright (C) 1996-2000 Andy Wardley.  All Rights Reserved.
-#   Copyright (C) 1998-2000 Canon Research Centre Europe Ltd.
-#
-#   This module is free software; you can redistribute it and/or
-#   modify it under the same terms as Perl itself.
-#
-#----------------------------------------------------------------------------
-#
-# $Id: Directive.pm,v 2.18 2003/10/08 09:34:41 abw Exp $
-#
-#============================================================================
-
-package Template::Directive;
-
-require 5.004;
-
-use strict;
-use Template::Base;
-use Template::Constants;
-use Template::Exception;
-
-use base qw( Template::Base );
-use vars qw( $VERSION $DEBUG $PRETTY $WHILE_MAX $OUTPUT );
-
-$VERSION = sprintf("%d.%02d", q$Revision: 2.18 $ =~ /(\d+)\.(\d+)/);
-
-$WHILE_MAX = 1000 unless defined $WHILE_MAX;
-$PRETTY    = 0 unless defined $PRETTY;
-$OUTPUT    = '$output .= ';
-
-
-sub _init {
-    my ($self, $config) = @_;
-    $self->{ NAMESPACE } = $config->{ NAMESPACE };
-    return $self;
-}
-
-
-sub pad {
-    my ($text, $pad) = @_;
-    $pad = ' ' x ($pad * 4);
-    $text =~ s/^(?!#line)/$pad/gm;
-    $text;
-}
-
-#========================================================================
-# FACTORY METHODS
-#
-# These methods are called by the parser to construct directive instances.
-#========================================================================
-
-#------------------------------------------------------------------------
-# template($block)
-#------------------------------------------------------------------------
-
-sub template {
-    my ($class, $block) = @_;
-    $block = pad($block, 2) if $PRETTY;
-
-    return "sub { return '' }" unless $block =~ /\S/;
-
-    return <<EOF;
-sub {
-    my \$context = shift || die "template sub called without context\\n";
-    my \$stash   = \$context->stash;
-    my \$output  = '';
-    my \$error;
-    
-    eval { BLOCK: {
-$block
-    } };
-    if (\$@) {
-        \$error = \$context->catch(\$@, \\\$output);
-        die \$error unless \$error->type eq 'return';
-    }
-
-    return \$output;
-}
-EOF
-}
-
-
-#------------------------------------------------------------------------
-# anon_block($block)                            [% BLOCK %] ... [% END %]
-#------------------------------------------------------------------------
-
-sub anon_block {
-    my ($class, $block) = @_;
-    $block = pad($block, 2) if $PRETTY;
-
-    return <<EOF;
-
-# BLOCK
-$OUTPUT do {
-    my \$output  = '';
-    my \$error;
-    
-    eval { BLOCK: {
-$block
-    } };
-    if (\$@) {
-        \$error = \$context->catch(\$@, \\\$output);
-        die \$error unless \$error->type eq 'return';
-    }
-
-    \$output;
-};
-EOF
-}
-
-
-#------------------------------------------------------------------------
-# block($blocktext)
-#------------------------------------------------------------------------
-
-sub block {
-    my ($class, $block) = @_;
-    return join("\n", @{ $block || [] });
-}
-
-
-#------------------------------------------------------------------------
-# textblock($text)
-#------------------------------------------------------------------------
-
-sub textblock {
-    my ($class, $text) = @_;
-    return "$OUTPUT " . &text($class, $text) . ';';
-}
-
-
-#------------------------------------------------------------------------
-# text($text)
-#------------------------------------------------------------------------
-
-sub text {
-    my ($class, $text) = @_;
-    for ($text) {
-        s/(["\$\@\\])/\\$1/g;
-        s/\n/\\n/g;
-    }
-    return '"' . $text . '"';
-}
-
-
-#------------------------------------------------------------------------
-# quoted(\@items)                                               "foo$bar"
-#------------------------------------------------------------------------
-
-sub quoted {
-    my ($class, $items) = @_;
-    return '' unless @$items;
-    return ("('' . " . $items->[0] . ')') if scalar @$items == 1;
-    return '(' . join(' . ', @$items) . ')';
-#    my $r = '(' . join(' . ', @$items) . ' . "")';
-#    print STDERR "[$r]\n";
-#    return $r;
-}
-
-
-#------------------------------------------------------------------------
-# ident(\@ident)                                             foo.bar(baz)
-#------------------------------------------------------------------------
-
-sub ident {
-    my ($class, $ident) = @_;
-    return "''" unless @$ident;
-    my $ns;
-
-    # does the first element of the identifier have a NAMESPACE
-    # handler defined?
-    if (ref $class && @$ident > 2 && ($ns = $class->{ NAMESPACE })) {
-	my $key = $ident->[0];
-	$key =~ s/^'(.+)'$/$1/s;
-	if ($ns = $ns->{ $key }) {
-	    return $ns->ident($ident);
-	}
-    }
-	
-    if (scalar @$ident <= 2 && ! $ident->[1]) {
-        $ident = $ident->[0];
-    }
-    else {
-        $ident = '[' . join(', ', @$ident) . ']';
-    }
-    return "\$stash->get($ident)";
-}
-
-#------------------------------------------------------------------------
-# identref(\@ident)                                         \foo.bar(baz)
-#------------------------------------------------------------------------
-
-sub identref {
-    my ($class, $ident) = @_;
-    return "''" unless @$ident;
-    if (scalar @$ident <= 2 && ! $ident->[1]) {
-        $ident = $ident->[0];
-    }
-    else {
-        $ident = '[' . join(', ', @$ident) . ']';
-    }
-    return "\$stash->getref($ident)";
-}
-
-
-#------------------------------------------------------------------------
-# assign(\@ident, $value, $default)                             foo = bar
-#------------------------------------------------------------------------
-
-sub assign {
-    my ($class, $var, $val, $default) = @_;
-
-    if (ref $var) {
-        if (scalar @$var == 2 && ! $var->[1]) {
-            $var = $var->[0];
-        }
-        else {
-            $var = '[' . join(', ', @$var) . ']';
-        }
-    }
-    $val .= ', 1' if $default;
-    return "\$stash->set($var, $val)";
-}
-
-
-#------------------------------------------------------------------------
-# args(\@args)                                        foo, bar, baz = qux
-#------------------------------------------------------------------------
-
-sub args {
-    my ($class, $args) = @_;
-    my $hash = shift @$args;
-    push(@$args, '{ ' . join(', ', @$hash) . ' }')
-        if @$hash;
-
-    return '0' unless @$args;
-    return '[ ' . join(', ', @$args) . ' ]';
-}
-
-#------------------------------------------------------------------------
-# filenames(\@names)
-#------------------------------------------------------------------------
-
-sub filenames {
-    my ($class, $names) = @_;
-    if (@$names > 1) {
-        $names = '[ ' . join(', ', @$names) . ' ]';
-    }
-    else {
-        $names = shift @$names;
-    }
-    return $names;
-}
-
-
-#------------------------------------------------------------------------
-# get($expr)                                                    [% foo %]
-#------------------------------------------------------------------------
-
-sub get {
-    my ($class, $expr) = @_;  
-    return "$OUTPUT $expr;";
-}
-
-
-#------------------------------------------------------------------------
-# call($expr)                                              [% CALL bar %]
-#------------------------------------------------------------------------
-
-sub call {
-    my ($class, $expr) = @_;  
-    $expr .= ';';
-    return $expr;
-}
-
-
-#------------------------------------------------------------------------
-# set(\@setlist)                               [% foo = bar, baz = qux %]
-#------------------------------------------------------------------------
-
-sub set {
-    my ($class, $setlist) = @_;
-    my $output;
-    while (my ($var, $val) = splice(@$setlist, 0, 2)) {
-        $output .= &assign($class, $var, $val) . ";\n";
-    }
-    chomp $output;
-    return $output;
-}
-
-
-#------------------------------------------------------------------------
-# default(\@setlist)                   [% DEFAULT foo = bar, baz = qux %]
-#------------------------------------------------------------------------
-
-sub default {
-    my ($class, $setlist) = @_;  
-    my $output;
-    while (my ($var, $val) = splice(@$setlist, 0, 2)) {
-        $output .= &assign($class, $var, $val, 1) . ";\n";
-    }
-    chomp $output;
-    return $output;
-}
-
-
-#------------------------------------------------------------------------
-# insert(\@nameargs)                                    [% INSERT file %] 
-#         # => [ [ $file, ... ], \@args ]
-#------------------------------------------------------------------------
-
-sub insert {
-    my ($class, $nameargs) = @_;
-    my ($file, $args) = @$nameargs;
-    $file = $class->filenames($file);
-    return "$OUTPUT \$context->insert($file);"; 
-}
-
-
-#------------------------------------------------------------------------
-# include(\@nameargs)                    [% INCLUDE template foo = bar %] 
-#          # => [ [ $file, ... ], \@args ]    
-#------------------------------------------------------------------------
-
-sub include {
-    my ($class, $nameargs) = @_;
-    my ($file, $args) = @$nameargs;
-    my $hash = shift @$args;
-    $file = $class->filenames($file);
-    $file .= @$hash ? ', { ' . join(', ', @$hash) . ' }' : '';
-    return "$OUTPUT \$context->include($file);"; 
-}
-
-
-#------------------------------------------------------------------------
-# process(\@nameargs)                    [% PROCESS template foo = bar %] 
-#         # => [ [ $file, ... ], \@args ]
-#------------------------------------------------------------------------
-
-sub process {
-    my ($class, $nameargs) = @_;
-    my ($file, $args) = @$nameargs;
-    my $hash = shift @$args;
-    $file = $class->filenames($file);
-    $file .= @$hash ? ', { ' . join(', ', @$hash) . ' }' : '';
-    return "$OUTPUT \$context->process($file);"; 
-}
-
-
-#------------------------------------------------------------------------
-# if($expr, $block, $else)                             [% IF foo < bar %]
-#                                                         ...
-#                                                      [% ELSE %]
-#                                                         ...
-#                                                      [% END %]
-#------------------------------------------------------------------------
-
-sub if {
-    my ($class, $expr, $block, $else) = @_;
-    my @else = $else ? @$else : ();
-    $else = pop @else;
-    $block = pad($block, 1) if $PRETTY;
-
-    my $output = "if ($expr) {\n$block\n}\n";
-
-    foreach my $elsif (@else) {
-        ($expr, $block) = @$elsif;
-        $block = pad($block, 1) if $PRETTY;
-        $output .= "elsif ($expr) {\n$block\n}\n";
-    }
-    if (defined $else) {
-        $else = pad($else, 1) if $PRETTY;
-        $output .= "else {\n$else\n}\n";
-    }
-
-    return $output;
-}
-
-
-#------------------------------------------------------------------------
-# foreach($target, $list, $args, $block)    [% FOREACH x = [ foo bar ] %]
-#                                              ...
-#                                           [% END %]
-#------------------------------------------------------------------------
-
-sub foreach {
-    my ($class, $target, $list, $args, $block) = @_;
-    $args  = shift @$args;
-    $args  = @$args ? ', { ' . join(', ', @$args) . ' }' : '';
-
-    my ($loop_save, $loop_set, $loop_restore, $setiter);
-    if ($target) {
-        $loop_save    = 'eval { $oldloop = ' . &ident($class, ["'loop'"]) . ' }';
-        $loop_set     = "\$stash->{'$target'} = \$value";
-        $loop_restore = "\$stash->set('loop', \$oldloop)";
-    }
-    else {
-        $loop_save    = '$stash = $context->localise()';
-#       $loop_set     = "\$stash->set('import', \$value) "
-#                       . "if ref \$value eq 'HASH'";
-        $loop_set     = "\$stash->get(['import', [\$value]]) "
-                        . "if ref \$value eq 'HASH'";
-        $loop_restore = '$stash = $context->delocalise()';
-    }
-    $block = pad($block, 3) if $PRETTY;
-
-    return <<EOF;
-
-# FOREACH 
-do {
-    my (\$value, \$error, \$oldloop);
-    my \$list = $list;
-    
-    unless (UNIVERSAL::isa(\$list, 'Template::Iterator')) {
-        \$list = Template::Config->iterator(\$list)
-            || die \$Template::Config::ERROR, "\\n"; 
-    }
-
-    (\$value, \$error) = \$list->get_first();
-    $loop_save;
-    \$stash->set('loop', \$list);
-    eval {
-LOOP:   while (! \$error) {
-            $loop_set;
-$block;
-            (\$value, \$error) = \$list->get_next();
-        }
-    };
-    $loop_restore;
-    die \$@ if \$@;
-    \$error = 0 if \$error && \$error eq Template::Constants::STATUS_DONE;
-    die \$error if \$error;
-};
-EOF
-}
-
-#------------------------------------------------------------------------
-# next()                                                       [% NEXT %]
-#
-# Next iteration of a FOREACH loop (experimental)
-#------------------------------------------------------------------------
-
-sub next {
-    return <<EOF;
-(\$value, \$error) = \$list->get_next();
-next LOOP;
-EOF
-}
-
-
-#------------------------------------------------------------------------
-# wrapper(\@nameargs, $block)            [% WRAPPER template foo = bar %] 
-#          # => [ [$file,...], \@args ]    
-#------------------------------------------------------------------------
-
-sub wrapper {
-    my ($class, $nameargs, $block) = @_;
-    my ($file, $args) = @$nameargs;
-    my $hash = shift @$args;
-
-    local $" = ', ';
-#    print STDERR "wrapper([@$file], { @$hash })\n";
-
-    return $class->multi_wrapper($file, $hash, $block)
-        if @$file > 1;
-    $file = shift @$file;
-
-    $block = pad($block, 1) if $PRETTY;
-    push(@$hash, "'content'", '$output');
-    $file .= @$hash ? ', { ' . join(', ', @$hash) . ' }' : '';
-
-    return <<EOF;
-
-# WRAPPER
-$OUTPUT do {
-    my \$output = '';
-$block
-    \$context->include($file); 
-};
-EOF
-}
-
-
-sub multi_wrapper {
-    my ($class, $file, $hash, $block) = @_;
-    $block = pad($block, 1) if $PRETTY;
-
-    push(@$hash, "'content'", '$output');
-    $hash = @$hash ? ', { ' . join(', ', @$hash) . ' }' : '';
-
-    $file = join(', ', reverse @$file);
-#    print STDERR "multi wrapper: $file\n";
-
-    return <<EOF;
-
-# WRAPPER
-$OUTPUT do {
-    my \$output = '';
-$block
-    foreach ($file) {
-        \$output = \$context->include(\$_$hash); 
-    }
-    \$output;
-};
-EOF
-}
-
-
-#------------------------------------------------------------------------
-# while($expr, $block)                                 [% WHILE x < 10 %]
-#                                                         ...
-#                                                      [% END %]
-#------------------------------------------------------------------------
-
-sub while {
-    my ($class, $expr, $block) = @_;
-    $block = pad($block, 2) if $PRETTY;
-
-    return <<EOF;
-
-# WHILE
-do {
-    my \$failsafe = $WHILE_MAX;
-LOOP:
-    while (--\$failsafe && ($expr)) {
-$block
-    }
-    die "WHILE loop terminated (> $WHILE_MAX iterations)\\n"
-        unless \$failsafe;
-};
-EOF
-}
-
-
-#------------------------------------------------------------------------
-# switch($expr, \@case)                                    [% SWITCH %]
-#                                                          [% CASE foo %]
-#                                                             ...
-#                                                          [% END %]
-#------------------------------------------------------------------------
-
-sub switch {
-    my ($class, $expr, $case) = @_;
-    my @case = @$case;
-    my ($match, $block, $default);
-    my $caseblock = '';
-
-    $default = pop @case;
-
-    foreach $case (@case) {
-        $match = $case->[0];
-        $block = $case->[1];
-        $block = pad($block, 1) if $PRETTY;
-        $caseblock .= <<EOF;
-\$match = $match;
-\$match = [ \$match ] unless ref \$match eq 'ARRAY';
-if (grep(/^\$result\$/, \@\$match)) {
-$block
-    last SWITCH;
-}
-EOF
-    }
-
-    $caseblock .= $default
-        if defined $default;
-    $caseblock = pad($caseblock, 2) if $PRETTY;
-
-return <<EOF;
-
-# SWITCH
-do {
-    my \$result = $expr;
-    my \$match;
-    SWITCH: {
-$caseblock
-    }
-};
-EOF
-}
-
-
-#------------------------------------------------------------------------
-# try($block, \@catch)                                        [% TRY %]
-#                                                                ...
-#                                                             [% CATCH %] 
-#                                                                ...
-#                                                             [% END %]
-#------------------------------------------------------------------------
-
-sub try {
-    my ($class, $block, $catch) = @_;
-    my @catch = @$catch;
-    my ($match, $mblock, $default, $final, $n);
-    my $catchblock = '';
-    my $handlers = [];
-
-    $block = pad($block, 2) if $PRETTY;
-    $final = pop @catch;
-    $final = "# FINAL\n" . ($final ? "$final\n" : '')
-           . 'die $error if $error;' . "\n" . '$output;';
-    $final = pad($final, 1) if $PRETTY;
-
-    $n = 0;
-    foreach $catch (@catch) {
-        $match = $catch->[0] || do {
-            $default ||= $catch->[1];
-            next;
-        };
-        $mblock = $catch->[1];
-        $mblock = pad($mblock, 1) if $PRETTY;
-        push(@$handlers, "'$match'");
-        $catchblock .= $n++ 
-            ? "elsif (\$handler eq '$match') {\n$mblock\n}\n" 
-               : "if (\$handler eq '$match') {\n$mblock\n}\n";
-    }
-    $catchblock .= "\$error = 0;";
-    $catchblock = pad($catchblock, 3) if $PRETTY;
-    if ($default) {
-        $default = pad($default, 1) if $PRETTY;
-        $default = "else {\n    # DEFAULT\n$default\n    \$error = '';\n}";
-    }
-    else {
-        $default = '# NO DEFAULT';
-    }
-    $default = pad($default, 2) if $PRETTY;
-
-    $handlers = join(', ', @$handlers);
-return <<EOF;
-
-# TRY
-$OUTPUT do {
-    my \$output = '';
-    my (\$error, \$handler);
-    eval {
-$block
-    };
-    if (\$@) {
-        \$error = \$context->catch(\$@, \\\$output);
-        die \$error if \$error->type =~ /^return|stop\$/;
-        \$stash->set('error', \$error);
-        \$stash->set('e', \$error);
-        if (defined (\$handler = \$error->select_handler($handlers))) {
-$catchblock
-        }
-$default
-    }
-$final
-};
-EOF
-}
-
-
-#------------------------------------------------------------------------
-# throw(\@nameargs)                           [% THROW foo "bar error" %]
-#       # => [ [$type], \@args ]
-#------------------------------------------------------------------------
-
-sub throw {
-    my ($class, $nameargs) = @_;
-    my ($type, $args) = @$nameargs;
-    my $hash = shift(@$args);
-    my $info = shift(@$args);
-    $type = shift @$type;           # uses same parser production as INCLUDE
-                                    # etc., which allow multiple names
-                                    # e.g. INCLUDE foo+bar+baz
-
-    if (! $info) {
-        $args = "$type, undef";
-    }
-    elsif (@$hash || @$args) {
-        local $" = ', ';
-        my $i = 0;
-        $args = "$type, { args => [ " 
-              . join(', ', $info, @$args) 
-              . ' ], '
-              . join(', ', 
-                     (map { "'" . $i++ . "' => $_" } ($info, @$args)),
-                     @$hash)
-              . ' }';
-    }
-    else {
-        $args = "$type, $info";
-    }
-    
-    return "\$context->throw($args, \\\$output);";
-}
-
-
-#------------------------------------------------------------------------
-# clear()                                                     [% CLEAR %]
-#
-# NOTE: this is redundant, being hard-coded (for now) into Parser.yp
-#------------------------------------------------------------------------
-
-sub clear {
-    return "\$output = '';";
-}
-
-#------------------------------------------------------------------------
-# break()                                                     [% BREAK %]
-#
-# NOTE: this is redundant, being hard-coded (for now) into Parser.yp
-#------------------------------------------------------------------------
-
-sub break {
-    return 'last LOOP;';
-}
-
-#------------------------------------------------------------------------
-# return()                                                   [% RETURN %]
-#------------------------------------------------------------------------
-
-sub return {
-    return "\$context->throw('return', '', \\\$output);";
-}
-
-#------------------------------------------------------------------------
-# stop()                                                       [% STOP %]
-#------------------------------------------------------------------------
-
-sub stop {
-    return "\$context->throw('stop', '', \\\$output);";
-}
-
-
-#------------------------------------------------------------------------
-# use(\@lnameargs)                         [% USE alias = plugin(args) %]
-#     # => [ [$file, ...], \@args, $alias ]
-#------------------------------------------------------------------------
-
-sub use {
-    my ($class, $lnameargs) = @_;
-    my ($file, $args, $alias) = @$lnameargs;
-    $file = shift @$file;       # same production rule as INCLUDE
-    $alias ||= $file;
-    $args = &args($class, $args);
-    $file .= ", $args" if $args;
-#    my $set = &assign($class, $alias, '$plugin'); 
-    return "# USE\n"
-         . "\$stash->set($alias,\n"
-         . "            \$context->plugin($file));";
-}
-
-#------------------------------------------------------------------------
-# view(\@nameargs, $block)                           [% VIEW name args %]
-#     # => [ [$file, ... ], \@args ]
-#------------------------------------------------------------------------
-
-sub view {
-    my ($class, $nameargs, $block, $defblocks) = @_;
-    my ($name, $args) = @$nameargs;
-    my $hash = shift @$args;
-    $name = shift @$name;       # same production rule as INCLUDE
-    $block = pad($block, 1) if $PRETTY;
-
-    if (%$defblocks) {
-        $defblocks = join(",\n", map { "'$_' => $defblocks->{ $_ }" }
-                                keys %$defblocks);
-        $defblocks = pad($defblocks, 1) if $PRETTY;
-        $defblocks = "{\n$defblocks\n}";
-        push(@$hash, "'blocks'", $defblocks);
-    }
-    $hash = @$hash ? '{ ' . join(', ', @$hash) . ' }' : '';
-
-    return <<EOF;
-# VIEW
-do {
-    my \$output = '';
-    my \$oldv = \$stash->get('view');
-    my \$view = \$context->view($hash);
-    \$stash->set($name, \$view);
-    \$stash->set('view', \$view);
-
-$block
-
-    \$stash->set('view', \$oldv);
-    \$view->seal();
-    \$output;
-};
-EOF
-}
-
-
-#------------------------------------------------------------------------
-# perl($block)
-#------------------------------------------------------------------------
-
-sub perl {
-    my ($class, $block) = @_;
-    $block = pad($block, 1) if $PRETTY;
-
-    return <<EOF;
-
-# PERL
-\$context->throw('perl', 'EVAL_PERL not set')
-    unless \$context->eval_perl();
-
-$OUTPUT do {
-    my \$output = "package Template::Perl;\\n";
-
-$block
-
-    local(\$Template::Perl::context) = \$context;
-    local(\$Template::Perl::stash)   = \$stash;
-
-    my \$result = '';
-    tie *Template::Perl::PERLOUT, 'Template::TieString', \\\$result;
-    my \$save_stdout = select *Template::Perl::PERLOUT;
-
-    eval \$output;
-    select \$save_stdout;
-    \$context->throw(\$@) if \$@;
-    \$result;
-};
-EOF
-}
-
-
-#------------------------------------------------------------------------
-# no_perl()
-#------------------------------------------------------------------------
-
-sub no_perl {
-    my $class = shift;
-    return "\$context->throw('perl', 'EVAL_PERL not set');";
-}
-
-
-#------------------------------------------------------------------------
-# rawperl($block)
-#
-# NOTE: perhaps test context EVAL_PERL switch at compile time rather than
-# runtime?
-#------------------------------------------------------------------------
-
-sub rawperl {
-    my ($class, $block, $line) = @_;
-    for ($block) {
-        s/^\n+//;
-        s/\n+$//;
-    }
-    $block = pad($block, 1) if $PRETTY;
-    $line = $line ? " (starting line $line)" : '';
-
-    return <<EOF;
-# RAWPERL
-#line 1 "RAWPERL block$line"
-$block
-EOF
-}
-
-
-
-#------------------------------------------------------------------------
-# filter()
-#------------------------------------------------------------------------
-
-sub filter {
-    my ($class, $lnameargs, $block) = @_;
-    my ($name, $args, $alias) = @$lnameargs;
-    $name = shift @$name;
-    $args = &args($class, $args);
-    $args = $args ? "$args, $alias" : ", undef, $alias"
-        if $alias;
-    $name .= ", $args" if $args;
-    $block = pad($block, 1) if $PRETTY;
- 
-    return <<EOF;
-
-# FILTER
-$OUTPUT do {
-    my \$output = '';
-    my \$filter = \$context->filter($name)
-              || \$context->throw(\$context->error);
-
-$block
-    
-    &\$filter(\$output);
-};
-EOF
-}
-
-
-#------------------------------------------------------------------------
-# capture($name, $block)
-#------------------------------------------------------------------------
-
-sub capture {
-    my ($class, $name, $block) = @_;
-
-    if (ref $name) {
-        if (scalar @$name == 2 && ! $name->[1]) {
-            $name = $name->[0];
-        }
-        else {
-            $name = '[' . join(', ', @$name) . ']';
-        }
-    }
-    $block = pad($block, 1) if $PRETTY;
-
-    return <<EOF;
-
-# CAPTURE
-\$stash->set($name, do {
-    my \$output = '';
-$block
-    \$output;
-});
-EOF
-
-}
-
-
-#------------------------------------------------------------------------
-# macro($name, $block, \@args)
-#------------------------------------------------------------------------
-
-sub macro {
-    my ($class, $ident, $block, $args) = @_;
-    $block = pad($block, 2) if $PRETTY;
-
-    if ($args) {
-        my $nargs = scalar @$args;
-        $args = join(', ', map { "'$_'" } @$args);
-        $args = $nargs > 1 
-            ? "\@args{ $args } = splice(\@_, 0, $nargs)"
-            : "\$args{ $args } = shift";
-
-        return <<EOF;
-
-# MACRO
-\$stash->set('$ident', sub {
-    my \$output = '';
-    my (%args, \$params);
-    $args;
-    \$params = shift;
-    \$params = { } unless ref(\$params) eq 'HASH';
-    \$params = { \%args, %\$params };
-
-    my \$stash = \$context->localise(\$params);
-    eval {
-$block
-    };
-    \$stash = \$context->delocalise();
-    die \$@ if \$@;
-    return \$output;
-});
-EOF
-
-    }
-    else {
-        return <<EOF;
-
-# MACRO
-\$stash->set('$ident', sub {
-    my \$params = \$_[0] if ref(\$_[0]) eq 'HASH';
-    my \$output = '';
-
-    my \$stash = \$context->localise(\$params);
-    eval {
-$block
-    };
-    \$stash = \$context->delocalise();
-    die \$@ if \$@;
-    return \$output;
-});
-EOF
-    }
-}
-
-
-sub debug {
-    my ($class, $nameargs) = @_;
-    my ($file, $args) = @$nameargs;
-    my $hash = shift @$args;
-    $args  = join(', ', @$file, @$args);
-    $args .= @$hash ? ', { ' . join(', ', @$hash) . ' }' : '';
-    return "$OUTPUT \$context->debugging($args); ## DEBUG ##"; 
-}
-
-
-1;
-
-__END__
-
diff --git a/lib/Template/Document.pm b/lib/Template/Document.pm
deleted file mode 100644
index ce3beb2..0000000
--- a/lib/Template/Document.pm
+++ /dev/null
@@ -1,492 +0,0 @@
-##============================================================= -*-Perl-*-
-#
-# Template::Document
-#
-# DESCRIPTION
-#   Module defining a class of objects which encapsulate compiled
-#   templates, storing additional block definitions and metadata 
-#   as well as the compiled Perl sub-routine representing the main
-#   template content.
-#
-# AUTHOR
-#   Andy Wardley   <abw@kfs.org>
-#
-# COPYRIGHT
-#   Copyright (C) 1996-2000 Andy Wardley.  All Rights Reserved.
-#   Copyright (C) 1998-2000 Canon Research Centre Europe Ltd.
-#
-#   This module is free software; you can redistribute it and/or
-#   modify it under the same terms as Perl itself.
-# 
-#----------------------------------------------------------------------------
-#
-# $Id: Document.pm,v 2.71 2004/01/13 16:19:10 abw Exp $
-#
-#============================================================================
-
-package Template::Document;
-
-require 5.004;
-
-use strict;
-use vars qw( $VERSION $ERROR $COMPERR $DEBUG $AUTOLOAD );
-use base qw( Template::Base );
-use Template::Constants;
-
-$VERSION = sprintf("%d.%02d", q$Revision: 2.71 $ =~ /(\d+)\.(\d+)/);
-
-
-#========================================================================
-#                     -----  PUBLIC METHODS -----
-#========================================================================
-
-#------------------------------------------------------------------------
-# new(\%document)
-#
-# Creates a new self-contained Template::Document object which 
-# encapsulates a compiled Perl sub-routine, $block, any additional 
-# BLOCKs defined within the document ($defblocks, also Perl sub-routines)
-# and additional $metadata about the document.
-#------------------------------------------------------------------------
-
-sub new {
-    my ($class, $doc) = @_;
-    my ($block, $defblocks, $metadata) = @$doc{ qw( BLOCK DEFBLOCKS METADATA ) };
-    $defblocks ||= { };
-    $metadata  ||= { };
-
-    # evaluate Perl code in $block to create sub-routine reference if necessary
-    unless (ref $block) {
-        local $SIG{__WARN__} = \&catch_warnings;
-        $COMPERR = '';
-
-        # DON'T LOOK NOW! - blindly untainting can make you go blind!
-        $block =~ /(.*)/s;
-        $block = $1;
-        
-        $block = eval $block;
-        return $class->error($@)
-            unless defined $block;
-    }
-
-    # same for any additional BLOCK definitions
-    @$defblocks{ keys %$defblocks } = 
-        # MORE BLIND UNTAINTING - turn away if you're squeamish
-        map { 
-            ref($_) 
-                ? $_ 
-                : ( /(.*)/s && eval($1) or return $class->error($@) )
-            } values %$defblocks;
-    
-    bless {
-        %$metadata,
-        _BLOCK     => $block,
-        _DEFBLOCKS => $defblocks,
-        _HOT       => 0,
-    }, $class;
-}
-
-
-#------------------------------------------------------------------------
-# block()
-#
-# Returns a reference to the internal sub-routine reference, _BLOCK, 
-# that constitutes the main document template.
-#------------------------------------------------------------------------
-
-sub block {
-    return $_[0]->{ _BLOCK };
-}
-
-
-#------------------------------------------------------------------------
-# blocks()
-#
-# Returns a reference to a hash array containing any BLOCK definitions 
-# from the template.  The hash keys are the BLOCK nameand the values
-# are references to Template::Document objects.  Returns 0 (# an empty hash)
-# if no blocks are defined.
-#------------------------------------------------------------------------
-
-sub blocks {
-    return $_[0]->{ _DEFBLOCKS };
-}
-
-
-#------------------------------------------------------------------------
-# process($context)
-#
-# Process the document in a particular context.  Checks for recursion,
-# registers the document with the context via visit(), processes itself,
-# and then unwinds with a large gin and tonic.
-#------------------------------------------------------------------------
-
-sub process {
-    my ($self, $context) = @_;
-    my $defblocks = $self->{ _DEFBLOCKS };
-    my $output;
-
-
-    # check we're not already visiting this template
-    return $context->throw(Template::Constants::ERROR_FILE, 
-                           "recursion into '$self->{ name }'")
-        if $self->{ _HOT } && ! $context->{ RECURSION };   ## RETURN ##
-
-    $context->visit($self, $defblocks);
-
-    $self->{ _HOT } = 1;
-    eval {
-        my $block = $self->{ _BLOCK };
-        $output = &$block($context);
-    };
-    $self->{ _HOT } = 0;
-
-    $context->leave();
-
-    die $context->catch($@)
-        if $@;
-	
-    return $output;
-}
-
-
-#------------------------------------------------------------------------
-# AUTOLOAD
-#
-# Provides pseudo-methods for read-only access to various internal 
-# members. 
-#------------------------------------------------------------------------
-
-sub AUTOLOAD {
-    my $self   = shift;
-    my $method = $AUTOLOAD;
-
-    $method =~ s/.*:://;
-    return if $method eq 'DESTROY';
-#    my ($pkg, $file, $line) = caller();
-#    print STDERR "called $self->AUTOLOAD($method) from $file line $line\n";
-    return $self->{ $method };
-}
-
-
-#========================================================================
-#                     -----  PRIVATE METHODS -----
-#========================================================================
-
-
-#------------------------------------------------------------------------
-# _dump()
-#
-# Debug method which returns a string representing the internal state
-# of the object.
-#------------------------------------------------------------------------
-
-sub _dump {
-    my $self = shift;
-    my $dblks;
-    my $output = "$self : $self->{ name }\n";
-
-    $output .= "BLOCK: $self->{ _BLOCK }\nDEFBLOCKS:\n";
-
-    if ($dblks = $self->{ _DEFBLOCKS }) {
-	foreach my $b (keys %$dblks) {
-	    $output .= "    $b: $dblks->{ $b }\n";
-	}
-    }
-
-    return $output;
-}
-
-
-#========================================================================
-#                      ----- CLASS METHODS -----
-#========================================================================
-
-#------------------------------------------------------------------------
-# as_perl($content)
-#
-# This method expects a reference to a hash passed as the first argument
-# containing 3 items:
-#     METADATA   # a hash of template metadata
-#     BLOCK      # string containing Perl sub definition for main block
-#     DEFBLOCKS  # hash containing further subs for addional BLOCK defs
-# It returns a string containing Perl code which, when evaluated and 
-# executed, will instantiate a new Template::Document object with the 
-# above data.  On error, it returns undef with an appropriate error
-# message set in $ERROR.
-#------------------------------------------------------------------------
-
-sub as_perl {
-    my ($class, $content) = @_;
-    my ($block, $defblocks, $metadata) = @$content{ qw( BLOCK DEFBLOCKS METADATA ) };
-
-    $block =~ s/\n/\n    /g;
-    $block =~ s/\s+$//;
-
-    $defblocks = join('', map {
-	my $code = $defblocks->{ $_ };
-	$code =~ s/\n/\n        /g;
-	$code =~ s/\s*$//;
-	"        '$_' => $code,\n";
-    } keys %$defblocks);
-    $defblocks =~ s/\s+$//;
-
-    $metadata = join('', map { 
-	my $x = $metadata->{ $_ }; 
-	$x =~ s/(['\\])/\\$1/g; 
-	"        '$_' => '$x',\n";
-    } keys %$metadata);
-    $metadata =~ s/\s+$//;
-
-    return <<EOF
-#------------------------------------------------------------------------
-# Compiled template generated by the Template Toolkit version $Template::VERSION
-#------------------------------------------------------------------------
-
-$class->new({
-    METADATA => {
-$metadata
-    },
-    BLOCK => $block,
-    DEFBLOCKS => {
-$defblocks
-    },
-});
-EOF
-}
-
-
-#------------------------------------------------------------------------
-# write_perl_file($filename, \%content)
-#
-# This method calls as_perl() to generate the Perl code to represent a
-# compiled template with the content passed as the second argument.
-# It then writes this to the file denoted by the first argument.
-#
-# Returns 1 on success.  On error, sets the $ERROR package variable
-# to contain an error message and returns undef.
-#------------------------------------------------------------------------
-
-sub write_perl_file {
-    my ($class, $file, $content) = @_;
-    my ($fh, $tmpfile);
-    
-    return $class->error("invalid filename: $file")
-	unless $file =~ /^(.+)$/s;
-
-    eval {
-        require File::Temp;
-        require File::Basename;
-        ($fh, $tmpfile) = File::Temp::tempfile( 
-            DIR => File::Basename::dirname($file) 
-        );
-	print $fh $class->as_perl($content) || die $!;
-	close($fh);
-    };
-    return $class->error($@) if $@;
-    return rename($tmpfile, $file)
-	|| $class->error($!);
-}
-
-
-#------------------------------------------------------------------------
-# catch_warnings($msg)
-#
-# Installed as
-#------------------------------------------------------------------------
-
-sub catch_warnings {
-    $COMPERR .= join('', @_); 
-}
-
-    
-1;
-
-__END__
-
-
-#------------------------------------------------------------------------
-# IMPORTANT NOTE
-#   This documentation is generated automatically from source
-#   templates.  Any changes you make here may be lost.
-# 
-#   The 'docsrc' documentation source bundle is available for download
-#   from http://www.template-toolkit.org/docs.html and contains all
-#   the source templates, XML files, scripts, etc., from which the
-#   documentation for the Template Toolkit is built.
-#------------------------------------------------------------------------
-
-=head1 NAME
-
-Template::Document - Compiled template document object
-
-=head1 SYNOPSIS
-
-    use Template::Document;
-
-    $doc = Template::Document->new({
-	BLOCK => sub { # some perl code; return $some_text },
-	DEFBLOCKS => {
-	    header => sub { # more perl code; return $some_text },
-	    footer => sub { # blah blah blah; return $some_text },
-	},
-	METADATA => {
-	    author  => 'Andy Wardley',
-	    version => 3.14,
-	}
-    }) || die $Template::Document::ERROR;
-
-    print $doc->process($context);
-
-=head1 DESCRIPTION
-
-This module defines an object class whose instances represent compiled
-template documents.  The Template::Parser module creates a
-Template::Document instance to encapsulate a template as it is compiled
-into Perl code.
-
-The constructor method, new(), expects a reference to a hash array
-containing the BLOCK, DEFBLOCKS and METADATA items.  The BLOCK item
-should contain a reference to a Perl subroutine or a textual
-representation of Perl code, as generated by the Template::Parser
-module, which is then evaluated into a subroutine reference using
-eval().  The DEFLOCKS item should reference a hash array containing
-further named BLOCKs which may be defined in the template.  The keys
-represent BLOCK names and the values should be subroutine references
-or text strings of Perl code as per the main BLOCK item.  The METADATA
-item should reference a hash array of metadata items relevant to the
-document.
-
-The process() method can then be called on the instantiated
-Template::Document object, passing a reference to a Template::Content
-object as the first parameter.  This will install any locally defined
-blocks (DEFBLOCKS) in the the contexts() BLOCKS cache (via a call to
-visit()) so that they may be subsequently resolved by the context.  The 
-main BLOCK subroutine is then executed, passing the context reference
-on as a parameter.  The text returned from the template subroutine is
-then returned by the process() method, after calling the context leave()
-method to permit cleanup and de-registration of named BLOCKS previously
-installed.
-
-An AUTOLOAD method provides access to the METADATA items for the document.
-The Template::Service module installs a reference to the main 
-Template::Document object in the stash as the 'template' variable.
-This allows metadata items to be accessed from within templates, 
-including PRE_PROCESS templates.
-
-header:
-
-    <html>
-    <head>
-    <title>[% template.title %]
-    </head>
-    ...
-
-Template::Document objects are usually created by the Template::Parser
-but can be manually instantiated or sub-classed to provide custom
-template components.
-
-=head1 METHODS
-
-=head2 new(\%config)
-
-Constructor method which accept a reference to a hash array containing the
-structure as shown in this example:
-
-    $doc = Template::Document->new({
-	BLOCK => sub { # some perl code; return $some_text },
-	DEFBLOCKS => {
-	    header => sub { # more perl code; return $some_text },
-	    footer => sub { # blah blah blah; return $some_text },
-	},
-	METADATA => {
-	    author  => 'Andy Wardley',
-	    version => 3.14,
-	}
-    }) || die $Template::Document::ERROR;
-
-BLOCK and DEFBLOCKS items may be expressed as references to Perl subroutines
-or as text strings containing Perl subroutine definitions, as is generated
-by the Template::Parser module.  These are evaluated into subroutine references
-using eval().
-
-Returns a new Template::Document object or undef on error.  The error() class
-method can be called, or the $ERROR package variable inspected to retrieve
-the relevant error message.
-
-=head2 process($context)
-
-Main processing routine for the compiled template document.  A reference to 
-a Template::Context object should be passed as the first parameter.  The 
-method installs any locally defined blocks via a call to the context 
-visit() method, processes it's own template, passing the context reference
-by parameter and then calls leave() in the context to allow cleanup.
-
-    print $doc->process($context);
-
-Returns a text string representing the generated output for the template.
-Errors are thrown via die().
-
-=head2 block()
-
-Returns a reference to the main BLOCK subroutine.
-
-=head2 blocks()
-
-Returns a reference to the hash array of named DEFBLOCKS subroutines.
-
-=head2 AUTOLOAD
-
-An autoload method returns METADATA items.
-
-    print $doc->author();
-
-=head1 PACKAGE SUB-ROUTINES
-
-=head2 write_perl_file(\%config)
-
-This package subroutine is provided to effect persistance of compiled
-templates.  If the COMPILE_EXT option (to indicate a file extension
-for saving compiled templates) then the Template::Parser module calls
-this subroutine before calling the new() constructor.  At this stage,
-the parser has a representation of the template as text strings
-containing Perl code.  We can write that to a file, enclosed in a
-small wrapper which will allow us to susequently require() the file
-and have Perl parse and compile it into a Template::Document.  Thus we
-have persistance of compiled templates.
-
-=head1 AUTHOR
-
-Andy Wardley E<lt>abw@andywardley.comE<gt>
-
-L<http://www.andywardley.com/|http://www.andywardley.com/>
-
-
-
-
-=head1 VERSION
-
-2.71, distributed as part of the
-Template Toolkit version 2.13, released on 30 January 2004.
-
-=head1 COPYRIGHT
-
-  Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
-  Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
-
-This module is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
-
-=head1 SEE ALSO
-
-L<Template|Template>, L<Template::Parser|Template::Parser>
-
-=cut
-
-# Local Variables:
-# mode: perl
-# perl-indent-level: 4
-# indent-tabs-mode: nil
-# End:
-#
-# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Exception.pm b/lib/Template/Exception.pm
deleted file mode 100644
index 9a95af7..0000000
--- a/lib/Template/Exception.pm
+++ /dev/null
@@ -1,254 +0,0 @@
-#============================================================= -*-Perl-*-
-#
-# Template::Exception
-#
-# DESCRIPTION
-#   Module implementing a generic exception class used for error handling
-#   in the Template Toolkit.
-#
-# AUTHOR
-#   Andy Wardley   <abw@kfs.org>
-#
-# COPYRIGHT
-#   Copyright (C) 1996-2000 Andy Wardley.  All Rights Reserved.
-#   Copyright (C) 1998-2000 Canon Research Centre Europe Ltd.
-#
-#   This module is free software; you can redistribute it and/or
-#   modify it under the same terms as Perl itself.
-#
-#------------------------------------------------------------------------
-#
-# $Id: Exception.pm,v 2.64 2004/01/13 16:19:10 abw Exp $
-#
-#========================================================================
-
-
-package Template::Exception;
-
-require 5.005;
-
-use strict;
-use vars qw( $VERSION );
-
-use constant TYPE  => 0;
-use constant INFO  => 1;
-use constant TEXT  => 2;
-use overload q|""| => "as_string", fallback => 1;
-
-
-$VERSION = sprintf("%d.%02d", q$Revision: 2.64 $ =~ /(\d+)\.(\d+)/);
-
-
-#------------------------------------------------------------------------
-# new($type, $info, \$text)
-#
-# Constructor method used to instantiate a new Template::Exception
-# object.  The first parameter should contain the exception type.  This
-# can be any arbitrary string of the caller's choice to represent a 
-# specific exception.  The second parameter should contain any 
-# information (i.e. error message or data reference) relevant to the 
-# specific exception event.  The third optional parameter may be a 
-# reference to a scalar containing output text from the template 
-# block up to the point where the exception was thrown.
-#------------------------------------------------------------------------
-
-sub new {
-    my ($class, $type, $info, $textref) = @_;
-    bless [ $type, $info, $textref ], $class;
-}
-
-
-#------------------------------------------------------------------------
-# type()
-# info()
-# type_info()
-#
-# Accessor methods to return the internal TYPE and INFO fields.
-#------------------------------------------------------------------------
-
-sub type {
-    $_[0]->[ TYPE ];
-}
-
-sub info {
-    $_[0]->[ INFO ];
-}
-
-sub type_info {
-    my $self = shift;
-    @$self[ TYPE, INFO ];
-}
-
-#------------------------------------------------------------------------
-# text()
-# text(\$pretext)
-#
-# Method to return the text referenced by the TEXT member.  A text 
-# reference may be passed as a parameter to supercede the existing 
-# member.  The existing text is added to the *end* of the new text
-# before being stored.  This facility is provided for template blocks
-# to gracefully de-nest when an exception occurs and allows them to 
-# reconstruct their output in the correct order. 
-#------------------------------------------------------------------------
-
-sub text {
-    my ($self, $newtextref) = @_;
-    my $textref = $self->[ TEXT ];
-    
-    if ($newtextref) {
-	$$newtextref .= $$textref if $textref && $textref ne $newtextref;
-	$self->[ TEXT ] = $newtextref;
-	return '';
-	
-    }
-    elsif ($textref) {
-	return $$textref;
-    }
-    else {
-	return '';
-    }
-}
-
-
-#------------------------------------------------------------------------
-# as_string()
-#
-# Accessor method to return a string indicating the exception type and
-# information.
-#------------------------------------------------------------------------
-
-sub as_string {
-    my $self = shift;
-    return $self->[ TYPE ] . ' error - ' . $self->[ INFO ];
-}
-
-
-#------------------------------------------------------------------------
-# select_handler(@types)
-# 
-# Selects the most appropriate handler for the exception TYPE, from 
-# the list of types passed in as parameters.  The method returns the
-# item which is an exact match for TYPE or the closest, more 
-# generic handler (e.g. foo being more generic than foo.bar, etc.)
-#------------------------------------------------------------------------
-
-sub select_handler {
-    my ($self, @options) = @_;
-    my $type = $self->[ TYPE ];
-    my %hlut;
-    @hlut{ @options } = (1) x @options;
-
-    while ($type) {
-	return $type if $hlut{ $type };
-
-	# strip .element from the end of the exception type to find a 
-	# more generic handler
-	$type =~ s/\.?[^\.]*$//;
-    }
-    return undef;
-}
-    
-1;
-
-__END__
-
-
-#------------------------------------------------------------------------
-# IMPORTANT NOTE
-#   This documentation is generated automatically from source
-#   templates.  Any changes you make here may be lost.
-# 
-#   The 'docsrc' documentation source bundle is available for download
-#   from http://www.template-toolkit.org/docs.html and contains all
-#   the source templates, XML files, scripts, etc., from which the
-#   documentation for the Template Toolkit is built.
-#------------------------------------------------------------------------
-
-=head1 NAME
-
-Template::Exception - Exception handling class module
-
-=head1 SYNOPSIS
-
-    use Template::Exception;
-
-    my $exception = Template::Exception->new($type, $info);
-    $type = $exception->type;
-    $info = $exception->info;
-    ($type, $info) = $exception->type_info;
-
-    print $exception->as_string();
-
-    $handler = $exception->select_handler(\@candidates);
-
-=head1 DESCRIPTION
-
-The Template::Exception module defines an object class for
-representing exceptions within the template processing life cycle.
-Exceptions can be raised by modules within the Template Toolkit, or
-can be generated and returned by user code bound to template
-variables.
-
-
-Exceptions can be raised in a template using the THROW directive,
-
-    [% THROW user.login 'no user id: please login' %]
-
-or by calling the throw() method on the current Template::Context object,
-
-    $context->throw('user.passwd', 'Incorrect Password');
-    $context->throw('Incorrect Password');    # type 'undef'
-
-or from Perl code by calling die() with a Template::Exception object,
-
-    die (Template::Exception->new('user.denied', 'Invalid User ID'));
-
-or by simply calling die() with an error string.  This is
-automagically caught and converted to an  exception of 'undef'
-type which can then be handled in the usual way.
-
-    die "I'm sorry Dave, I can't do that";
-
-
-
-Each exception is defined by its type and a information component
-(e.g. error message).  The type can be any identifying string and may
-contain dotted components (e.g. 'foo', 'foo.bar', 'foo.bar.baz').
-Exception types are considered to be hierarchical such that 'foo.bar'
-would be a specific type of the more general 'foo' type.
-
-=head1 AUTHOR
-
-Andy Wardley E<lt>abw@andywardley.comE<gt>
-
-L<http://www.andywardley.com/|http://www.andywardley.com/>
-
-
-
-
-=head1 VERSION
-
-2.64, distributed as part of the
-Template Toolkit version 2.13, released on 30 January 2004.
-
-=head1 COPYRIGHT
-
-  Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
-  Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
-
-This module is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
-
-=head1 SEE ALSO
-
-L<Template|Template>, L<Template::Context|Template::Context>
-
-=cut
-
-# Local Variables:
-# mode: perl
-# perl-indent-level: 4
-# indent-tabs-mode: nil
-# End:
-#
-# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/FAQ.pod b/lib/Template/FAQ.pod
deleted file mode 100644
index 0807ace..0000000
--- a/lib/Template/FAQ.pod
+++ /dev/null
@@ -1,329 +0,0 @@
-#============================================================= -*-perl-*-
-#
-# Template::FAQ
-#
-# DESCRIPTION
-#   This is the Frequently Asked Questions list for the Template
-#   Toolkit. More accurately, it's a very thin placeholder for where
-#   the FAQ will soon be.
-#
-# AUTHOR
-#   Andy Wardley  <abw@andywardley.com>
-#
-# COPYRIGHT
-#   Copyright (C) 1996-2001 Andy Wardley.  All Rights Reserved.
-#   Copyright (C) 1998-2001 Canon Research Centre Europe Ltd.
-#
-#   This module is free software; you can redistribute it and/or
-#   modify it under the same terms as Perl itself.
-#
-# REVISION
-#   2.69
-#
-#========================================================================
-
-
-#------------------------------------------------------------------------
-# IMPORTANT NOTE
-#   This documentation is generated automatically from source
-#   templates.  Any changes you make here may be lost.
-# 
-#   The 'docsrc' documentation source bundle is available for download
-#   from http://www.template-toolkit.org/docs.html and contains all
-#   the source templates, XML files, scripts, etc., from which the
-#   documentation for the Template Toolkit is built.
-#------------------------------------------------------------------------
-
-=head1 NAME
-
-Template::FAQ - Frequently Asked Questions about the Template Toolkit
-
-=head1 DESCRIPTION
-
-This is the Frequently Asked Questions list for the Template Toolkit.
-More accurately, it's a very thin placeholder for where the FAQ will
-soon be.
-
-
-=head1 Template Toolkit Language
-
-=head2 Why doesn't [% a = b IF c %] work as expected?
-
-Because the parser interprets it as 
-
-    [% a = (b IF c) %]
-
-Do this instead:
-
-    [% SET a = b IF c %]
-
-=head2 If I'm using TT to write out a TT template, is there a good way to escape [% and %]?
-
-You can do this:
- 
-  [% stag = "[\%"
-     etag = "%\]"
-  %]
- 
-and then:
- 
-  [% stag; 'hello'; etag %]
-
-Or something like:
-
-  [% TAGS [- -] %]
-  [- INCLUDE foo -]   # is a directive
-  [% INCLUDE foo %]   # not a directive, just plain text, passed through
-
-=head2 How do I iterate over a hash?
-
-This is covered in the L<Template::Manual::VMethods|VMethods> section
-of the manual page.  A list of all the keys that are in the hash can
-be obtained with the 'keys' virtual method.  You can then iterate
-over that list and by looking up each key in turn get the value.
-
-    [% FOREACH key = product.keys %]
-       [% key %] => [% product.$key %]
-    [% END %]
-
-=head1 Plugins
-
-=head2 How do I get the Table plugin to order data across rather than down?
-
-Order the data into rows:
-
-     Steve     Karen     Jeff
-     Brooklyn  Nantucket Fairfax
-     NY        MA        VA
- 
-    [% USE table(data, rows=3) %]
- 
-Then ask for each column
- 
-    [% FOREACH column = table.cols %]
- 
-And then print each item in the column going across the output rows
- 
-    [% FOREACH item = column %]
-	<td>[% item %]</td>
-    [% END %]
-
-=head2 Accessing Cookies
-
-Jeff Boes E<lt>jboes@nexcerpt.comE<gt> asks:
-
-    Does anyone have a quick-n-dirty approach to accessing 
-    cookies from templates? 
-
-Jonas Liljegren answers:
-
-    [% USE CGI %]
-    
-    <p>The value is [% CGI.cookie('cookie_name') | html %]
-
-
-=head1 Extending the Template Toolkit
-
-=head2 Can I serve templates from a database?
-
-Short answer: yes, Chris Nandor has done this for Slash.  You need to 
-subclass Template::Provider.  See the mailing list archives for further
-info.
-
-=head2 Can I fetch templates via http?
-
-To do the job properly, you should sublcass Template::Provider to 
-Template::Provider::HTTP and use a PREFIX_MAP option to bind the 
-'http' template prefix to that particular provider (you may want to 
-go digging around in the F<Changes> file around version 2.01 for 
-more info on PREFIX_MAP - it may not be properly documented anywhere
-else...yet!).  e.g. (untested due to lack of existing HTTP Provider
-- patches welcome!).
-
-    use Template::Provider::HTTP;
-
-    my $file = Template::Provider( INCLUDE_PATH => [...] );
-    my $http = Template::Provider::HTTP->new(...);
-    my $tt2  = Template->new({
-	LOAD_TEMPLATES => [ $file, $http ],
-	PREFIX_MAP => {
-	    file    => '0',	# file:foo.html
-	    http    => '1',	# http:foo.html
-	    default => '0',	# foo.html => file:foo.html
-	}
-    });
-
-Now a template specified as:
-
-    [% INCLUDE foo %]
-
-will be served by the 'file' provider (the default).  Otherwise you 
-can explicitly add a prefix:
-
-    [% INCLUDE file:foo.html %]
-    [% INCLUDE http:foo.html %]
-    [% INCLUDE http://www.xyz.com/tt2/header.tt2 %]
-
-This same principal can be used to create a DBI template provider.  e.g.
-
-    [% INCLUDE dbi:foo.html %]
-
-But similarly, alas, we don't yet have a DBI provider as part of the 
-Template Toolkit.  There has been some talk on the mailing list about
-efforts to develop DBI and/or HTTP providers but as yet no-one has 
-stepped forward to take up the challenge...
-
-In the mean time, Craig's post from the mailing list has some useful
-pointers on how to acheive this using existing modules:
-
-    To: Adam Theo <adamtheo@theoretic.com> 
-    From: Craig Barratt <craig@arraycomm.com>
-    Date: Fri, 18 May 2001 17:06:59 -0700
-      
-    > i was wondering if there is anyway to fetch a file using http:// or
-    > ftp:// and include that?
-      
-    Here's one way.  Set the LOAD_PERL option:
-      
-    	use Template;
-     
-    	my $template = Template->new({  
-    	    LOAD_PERL => 1
-    	});  
-    	$template->process("example.tt", { stdout => *STDOUT })
-    				     || die $template->error();
-     
-    and then use LWP::UserAgent and HTTP::Request:
-     
-    	[% 
-    	    USE ua = LWP.UserAgent; 
-    	    ua.proxy("http", "http://your_proxy/");
-    	    USE req = HTTP.Request("GET", "http://www.cpan.org");
-    	    ua.request(req).content;
-    	-%]
-     
-    For FTP use Net::FTP:
-     
-    	[%   
-    	    USE ftp = Net.FTP("ftp.cpan.org");
-    	    x = ftp.login("anonymous", "me@here.there");
-    	    x = ftp.cwd("/");
-    	    x = ftp.get("welcome.msg", stdout);
-    	    x = ftp.quit;
-    	-%]
-     
-    Normally ftp.get would write the file into the current directory.
-    Instead we pass stdout as a second argument so that it is written
-    to stdout.  We set stdout to STDOUT in the variables we pass to
-    process. 
-     
-    Craig
-
-=head1 Miscellaneous
-
-=head2 How can I configure variables on a per-request basis?
-
-One easy way to acheive this is to define a single PRE_PROCESS template which
-loads in other configuration files based on variables defined or other 
-conditions.
-
-For example, my setup usually looks something like this:
-
-    PRE_PROCESS => 'config/main'
-
-config/main:
-
-    [%  DEFAULT  style   = 'text'
-                 section =  template.section or 'home';
-
-        PROCESS  config/site
-              +  config/urls
-              +  config/macros
-              + "config/style/$style"
-              + "config/section/$section"
-              + ...
-    %]
-
-This allows me to set a single 'style' variable to control which config
-file gets pre-processed to set my various style options (colours, img paths,
-etc).  For example:
-
-config/style/basic:
-
-    [%  style = {
-	    name = style    # save existing 'style' var as 'style.name'
-
-	    # define various other style variables....
-            col = {
-		back => '#ffffff'
-		text => '#000000'
-		# ...etc...
-	    }
-
-	    logo = {
-		# ...etc...
-	    }
-
-	    # ...etc...
-	}
-    %]
-
-Each source template can declare which section it's in via a META
-directive:
-
-  [% META
-       title   = 'General Information'
-       section = 'info'
-  %]
-
-  ...
-
-This controls which section configuration file gets loaded to set various
-other variables for defining the section title, menu, etc.
-
-config/section/info:
-
-    [%  section = {
-	    name   = section  # save 'section' var as 'section.name'
-	    title  = 'Information'
-	    menu   = [ ... ]
-	    # ...etc...
-	}
-    %]
-
-This illustrates the basic principal but you can extend it to perform
-pretty much any kind of per-document initialisation that you require.
-
-=head1 AUTHOR
-
-Andy Wardley E<lt>abw@andywardley.comE<gt>
-
-L<http://www.andywardley.com/|http://www.andywardley.com/>
-
-
-
-
-=head1 VERSION
-
-2.69, distributed as part of the
-Template Toolkit version 2.13, released on 30 January 2004.
-
-=head1 COPYRIGHT
-
-  Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
-  Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
-
-This module is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
-
-
-
-=cut
-
-# Local Variables:
-# mode: perl
-# perl-indent-level: 4
-# indent-tabs-mode: nil
-# End:
-#
-# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Filters.pm b/lib/Template/Filters.pm
deleted file mode 100644
index a9c4846..0000000
--- a/lib/Template/Filters.pm
+++ /dev/null
@@ -1,1448 +0,0 @@
-#============================================================= -*-Perl-*-
-#
-# Template::Filters
-#
-# DESCRIPTION
-#   Defines filter plugins as used by the FILTER directive.
-#
-# AUTHORS
-#   Andy Wardley <abw@kfs.org>, with a number of filters contributed
-#   by Leslie Michael Orchard <deus_x@nijacode.com>
-#
-# COPYRIGHT
-#   Copyright (C) 1996-2000 Andy Wardley.  All Rights Reserved.
-#   Copyright (C) 1998-2000 Canon Research Centre Europe Ltd.
-#
-#   This module is free software; you can redistribute it and/or
-#   modify it under the same terms as Perl itself.
-#
-#----------------------------------------------------------------------------
-#
-# $Id: Filters.pm,v 2.77 2004/01/13 16:19:10 abw Exp $
-#
-#============================================================================
-
-package Template::Filters;
-
-require 5.004;
-
-use strict;
-use base qw( Template::Base );
-use vars qw( $VERSION $DEBUG $FILTERS $URI_ESCAPES $PLUGIN_FILTER );
-use Template::Constants;
-
-$VERSION = sprintf("%d.%02d", q$Revision: 2.77 $ =~ /(\d+)\.(\d+)/);
-
-
-#------------------------------------------------------------------------
-# standard filters, defined in one of the following forms:
-#   name =>   \&static_filter
-#   name => [ \&subref, $is_dynamic ]
-# If the $is_dynamic flag is set then the sub-routine reference 
-# is called to create a new filter each time it is requested;  if
-# not set, then it is a single, static sub-routine which is returned
-# for every filter request for that name.
-#------------------------------------------------------------------------
-
-$FILTERS = {
-    # static filters 
-    'html'            => \&html_filter,
-    'html_para'       => \&html_paragraph,
-    'html_break'      => \&html_para_break,
-    'html_para_break' => \&html_para_break,
-    'html_line_break' => \&html_line_break,
-    'uri'             => \&uri_filter,
-    'upper'           => sub { uc $_[0] },
-    'lower'           => sub { lc $_[0] },
-    'ucfirst'         => sub { ucfirst $_[0] },
-    'lcfirst'         => sub { lcfirst $_[0] },
-    'stderr'          => sub { print STDERR @_; return '' },
-    'trim'            => sub { for ($_[0]) { s/^\s+//; s/\s+$// }; $_[0] },
-    'null'            => sub { return '' },
-    'collapse'        => sub { for ($_[0]) { s/^\s+//; s/\s+$//; s/\s+/ /g };
-                               $_[0] },
-
-    # dynamic filters
-    'html_entity' => [ \&html_entity_filter_factory, 1 ],
-    'indent'      => [ \&indent_filter_factory,      1 ],
-    'format'      => [ \&format_filter_factory,      1 ],
-    'truncate'    => [ \&truncate_filter_factory,    1 ],
-    'repeat'      => [ \&repeat_filter_factory,      1 ],
-    'replace'     => [ \&replace_filter_factory,     1 ],
-    'remove'      => [ \&remove_filter_factory,      1 ],
-    'eval'        => [ \&eval_filter_factory,        1 ],
-    'evaltt'      => [ \&eval_filter_factory,        1 ],  # alias
-    'perl'        => [ \&perl_filter_factory,        1 ],
-    'evalperl'    => [ \&perl_filter_factory,        1 ],  # alias
-    'redirect'    => [ \&redirect_filter_factory,    1 ],
-    'file'        => [ \&redirect_filter_factory,    1 ],  # alias
-    'stdout'      => [ \&stdout_filter_factory,      1 ],
-    'latex'       => [ \&latex_filter_factory,       1 ],
-};
-
-# name of module implementing plugin filters
-$PLUGIN_FILTER = 'Template::Plugin::Filter';
-
-
-#========================================================================
-#                         -- PUBLIC METHODS --
-#========================================================================
-
-#------------------------------------------------------------------------
-# fetch($name, \@args, $context)
-#
-# Attempts to instantiate or return a reference to a filter sub-routine 
-# named by the first parameter, $name, with additional constructor 
-# arguments passed by reference to a list as the second parameter, 
-# $args.  A reference to the calling Template::Context object is 
-# passed as the third paramter.
-#
-# Returns a reference to a filter sub-routine or a pair of values
-# (undef, STATUS_DECLINED) or ($error, STATUS_ERROR) to decline to
-# deliver the filter or to indicate an error.
-#------------------------------------------------------------------------
-
-sub fetch {
-    my ($self, $name, $args, $context) = @_;
-    my ($factory, $is_dynamic, $filter, $error);
-
-    $self->debug("fetch($name, ", 
-                 defined $args ? ('[ ', join(', ', @$args), ' ]') : '<no args>', ', ',
-                 defined $context ? $context : '<no context>', 
-                 ')') if $self->{ DEBUG };
-
-    # allow $name to be specified as a reference to 
-    # a plugin filter object;  any other ref is 
-    # assumed to be a coderef and hence already a filter;
-    # non-refs are assumed to be regular name lookups
-
-    if (ref $name) {
-        if (UNIVERSAL::isa($name, $PLUGIN_FILTER)) {
-            $factory = $name->factory()
-                || return $self->error($name->error());
-        }
-        else {
-            return $name;
-        }
-    }
-    else {
-        return (undef, Template::Constants::STATUS_DECLINED)
-            unless ($factory = $self->{ FILTERS }->{ $name }
-                    || $FILTERS->{ $name });
-    }
-
-    # factory can be an [ $code, $dynamic ] or just $code
-    if (ref $factory eq 'ARRAY') {
-        ($factory, $is_dynamic) = @$factory;
-    }
-    else {
-        $is_dynamic = 0;
-    }
-
-    if (ref $factory eq 'CODE') {
-        if ($is_dynamic) {
-            # if the dynamic flag is set then the sub-routine is a 
-            # factory which should be called to create the actual 
-            # filter...
-            eval {
-                ($filter, $error) = &$factory($context, $args ? @$args : ());
-            };
-            $error ||= $@;
-            $error = "invalid FILTER for '$name' (not a CODE ref)"
-                unless $error || ref($filter) eq 'CODE';
-        }
-        else {
-            # ...otherwise, it's a static filter sub-routine
-            $filter = $factory;
-        }
-    }
-    else {
-        $error = "invalid FILTER entry for '$name' (not a CODE ref)";
-    }
-
-    if ($error) {
-        return $self->{ TOLERANT } 
-               ? (undef,  Template::Constants::STATUS_DECLINED) 
-               : ($error, Template::Constants::STATUS_ERROR) ;
-    }
-    else {
-        return $filter;
-    }
-}
-
-
-#------------------------------------------------------------------------
-# store($name, \&filter)
-#
-# Stores a new filter in the internal FILTERS hash.  The first parameter
-# is the filter name, the second a reference to a subroutine or 
-# array, as per the standard $FILTERS entries.
-#------------------------------------------------------------------------
-
-sub store {
-    my ($self, $name, $filter) = @_;
-
-    $self->debug("store($name, $filter)") if $self->{ DEBUG };
-
-    $self->{ FILTERS }->{ $name } = $filter;
-    return 1;
-}
-
-
-#========================================================================
-#                        -- PRIVATE METHODS --
-#========================================================================
-
-#------------------------------------------------------------------------
-# _init(\%config)
-#
-# Private initialisation method.
-#------------------------------------------------------------------------
-
-sub _init {
-    my ($self, $params) = @_;
-
-    $self->{ FILTERS  } = $params->{ FILTERS } || { };
-    $self->{ TOLERANT } = $params->{ TOLERANT }  || 0;
-    $self->{ DEBUG    } = ( $params->{ DEBUG } || 0 )
-                          & Template::Constants::DEBUG_FILTERS;
-
-
-    return $self;
-}
-
-
-
-#------------------------------------------------------------------------
-# _dump()
-# 
-# Debug method
-#------------------------------------------------------------------------
-
-sub _dump {
-    my $self = shift;
-    my $output = "[Template::Filters] {\n";
-    my $format = "    %-16s => %s\n";
-    my $key;
-
-    foreach $key (qw( TOLERANT )) {
-        my $val = $self->{ $key };
-        $val = '<undef>' unless defined $val;
-        $output .= sprintf($format, $key, $val);
-    }
-
-    my $filters = $self->{ FILTERS };
-    $filters = join('', map { 
-        sprintf("    $format", $_, $filters->{ $_ });
-    } keys %$filters);
-    $filters = "{\n$filters    }";
-    
-    $output .= sprintf($format, 'FILTERS (local)' => $filters);
-
-    $filters = $FILTERS;
-    $filters = join('', map { 
-        my $f = $filters->{ $_ };
-        my ($ref, $dynamic) = ref $f eq 'ARRAY' ? @$f : ($f, 0);
-        sprintf("    $format", $_, $dynamic ? 'dynamic' : 'static');
-    } sort keys %$filters);
-    $filters = "{\n$filters    }";
-    
-    $output .= sprintf($format, 'FILTERS (global)' => $filters);
-
-    $output .= '}';
-    return $output;
-}
-
-
-#========================================================================
-#                         -- STATIC FILTER SUBS --
-#========================================================================
-
-#------------------------------------------------------------------------
-# uri_filter()                                           [% FILTER uri %]
-#
-# URI escape a string.  This code is borrowed from Gisle Aas' URI::Escape
-# module.  For something so simple, I can't see any validation in making
-# the user install the URI modules just for this, so we cut and paste.
-#
-# URI::Escape is Copyright 1995-2000 Gisle Aas.
-#------------------------------------------------------------------------
-
-sub uri_filter {
-    my $text = shift;
-
-    # construct and cache a lookup table for escapes (faster than
-    # doing a sprintf() for every character in every string each 
-    # time)
-    $URI_ESCAPES ||= {
-        map { ( chr($_), sprintf("%%%02X", $_) ) } (0..255),
-    };
-    
-    $text =~ s/([^;\/?:@&=+\$,A-Za-z0-9\-_.!~*'()])/$URI_ESCAPES->{$1}/g;
-    $text;
-}
-
-
-#------------------------------------------------------------------------
-# html_filter()                                         [% FILTER html %]
-#
-# Convert any '<', '>' or '&' characters to the HTML equivalents, '<',
-# '>' and '&', respectively. 
-#------------------------------------------------------------------------
-
-sub html_filter {
-    my $text = shift;
-    for ($text) {
-        s/&/&/g;
-        s/</</g;
-        s/>/>/g;
-        s/"/"/g;
-    }
-    return $text;
-}
-
-
-#------------------------------------------------------------------------
-# html_paragraph()                                 [% FILTER html_para %]
-#
-# Wrap each paragraph of text (delimited by two or more newlines) in the
-# <p>...</p> HTML tags.
-#------------------------------------------------------------------------
-
-sub html_paragraph  {
-    my $text = shift;
-    return "<p>\n" 
-           . join("\n</p>\n\n<p>\n", split(/(?:\r?\n){2,}/, $text))
-           . "</p>\n";
-}
-
-
-#------------------------------------------------------------------------
-# html_para_break()                          [% FILTER html_para_break %]
-#                                               
-# Join each paragraph of text (delimited by two or more newlines) with
-# <br><br> HTML tags.
-#------------------------------------------------------------------------
-
-sub html_para_break  {
-    my $text = shift;
-    $text =~ s|(\r?\n){2,}|$1<br />$1<br />$1|g;
-    return $text;
-}
-
-#------------------------------------------------------------------------
-# html_line_break()                          [% FILTER html_line_break %]
-#
-# replaces any newlines with <br> HTML tags.
-#------------------------------------------------------------------------
-
-sub html_line_break  {
-    my $text = shift;
-    $text =~ s|(\r?\n)|<br />$1|g;
-    return $text;
-}
-
-#========================================================================
-#                    -- DYNAMIC FILTER FACTORIES --
-#========================================================================
-
-#------------------------------------------------------------------------
-# html_entity_filter_factory(\%options)                 [% FILTER html %]
-#
-# Dynamic version of the static html filter which attempts to locate the
-# Apache::Util or HTML::Entities modules to perform full entity encoding
-# of the text passed.  Returns an exception if one or other of the 
-# modules can't be located.
-#------------------------------------------------------------------------
-
-sub html_entity_filter_factory {
-    my $context = shift;
-
-    # if Apache::Util is installed then we use it
-    eval { 
-        require Apache::Util;
-        Apache::Util::escape_html('');
-    };
-    return \&Apache::Util::escape_html
-        unless $@;
-
-    # otherwise if HTML::Entities is installed then we use that
-    eval {
-        require HTML::Entities;
-    };
-    return \&HTML::Entities::encode_entities
-        unless $@;
-
-    return (undef, Template::Exception->new( html_entity => 
-                    'cannot locate Apache::Util or HTML::Entities' ));
-
-}
-
-
-#------------------------------------------------------------------------
-# indent_filter_factory($pad)                    [% FILTER indent(pad) %]
-#
-# Create a filter to indent text by a fixed pad string or when $pad is
-# numerical, a number of space. 
-#------------------------------------------------------------------------
-
-sub indent_filter_factory {
-    my ($context, $pad) = @_;
-    $pad = 4 unless defined $pad;
-    $pad = ' ' x $pad if $pad =~ /^\d+$/;
-
-    return sub {
-        my $text = shift;
-        $text = '' unless defined $text;
-        $text =~ s/^/$pad/mg;
-        return $text;
-    }
-}
-
-#------------------------------------------------------------------------
-# format_filter_factory()                     [% FILTER format(format) %]
-#
-# Create a filter to format text according to a printf()-like format
-# string.
-#------------------------------------------------------------------------
-
-sub format_filter_factory {
-    my ($context, $format) = @_;
-    $format = '%s' unless defined $format;
-
-    return sub {
-        my $text = shift;
-        $text = '' unless defined $text;
-        return join("\n", map{ sprintf($format, $_) } split(/\n/, $text));
-    }
-}
-
-
-#------------------------------------------------------------------------
-# repeat_filter_factory($n)                        [% FILTER repeat(n) %]
-#
-# Create a filter to repeat text n times.
-#------------------------------------------------------------------------
-
-sub repeat_filter_factory {
-    my ($context, $iter) = @_;
-    $iter = 1 unless defined $iter and length $iter;
-
-    return sub {
-        my $text = shift;
-        $text = '' unless defined $text;
-        return join('\n', $text) x $iter;
-    }
-}
-
-
-#------------------------------------------------------------------------
-# replace_filter_factory($s, $r)    [% FILTER replace(search, replace) %]
-#
-# Create a filter to replace 'search' text with 'replace'
-#------------------------------------------------------------------------
-
-sub replace_filter_factory {
-    my ($context, $search, $replace) = @_;
-    $search = '' unless defined $search;
-    $replace = '' unless defined $replace;
-
-    return sub {
-        my $text = shift;
-        $text = '' unless defined $text;
-        $text =~ s/$search/$replace/g;
-        return $text;
-    }
-}
-
-
-#------------------------------------------------------------------------
-# remove_filter_factory($text)                  [% FILTER remove(text) %]
-#
-# Create a filter to remove 'search' string from the input text.
-#------------------------------------------------------------------------
-
-sub remove_filter_factory {
-    my ($context, $search) = @_;
-
-    return sub {
-        my $text = shift;
-        $text = '' unless defined $text;
-        $text =~ s/$search//g;
-        return $text;
-    }
-}
-
-
-#------------------------------------------------------------------------
-# truncate_filter_factory($n)                    [% FILTER truncate(n) %]
-#
-# Create a filter to truncate text after n characters.
-#------------------------------------------------------------------------
-
-sub truncate_filter_factory {
-    my ($context, $len) = @_;
-    $len = 32 unless defined $len;
-
-    return sub {
-        my $text = shift;
-        return $text if length $text < $len;
-        return substr($text, 0, $len - 3) . "...";
-    }
-}
-
-
-#------------------------------------------------------------------------
-# eval_filter_factory                                   [% FILTER eval %]
-# 
-# Create a filter to evaluate template text.
-#------------------------------------------------------------------------
-
-sub eval_filter_factory {
-    my $context = shift;
-
-    return sub {
-        my $text = shift;
-        $context->process(\$text);
-    }
-}
-
-
-#------------------------------------------------------------------------
-# perl_filter_factory                                   [% FILTER perl %]
-# 
-# Create a filter to process Perl text iff the context EVAL_PERL flag 
-# is set.
-#------------------------------------------------------------------------
-
-sub perl_filter_factory {
-    my $context = shift;
-    my $stash = $context->stash;
-
-    return (undef, Template::Exception->new('perl', 'EVAL_PERL is not set'))
-        unless $context->eval_perl();
-
-    return sub {
-        my $text = shift;
-        local($Template::Perl::context) = $context;
-        local($Template::Perl::stash)   = $stash;
-        my $out = eval <<EOF;
-package Template::Perl; 
-\$stash = \$context->stash(); 
-$text
-EOF
-        $context->throw($@) if $@;
-        return $out;
-    }
-}
-
-
-#------------------------------------------------------------------------
-# redirect_filter_factory($context, $file)    [% FILTER redirect(file) %]
-#
-# Create a filter to redirect the block text to a file.
-#------------------------------------------------------------------------
-
-sub redirect_filter_factory {
-    my ($context, $file, $options) = @_;
-    my $outpath = $context->config->{ OUTPUT_PATH };
-
-    return (undef, Template::Exception->new('redirect', 
-                                            'OUTPUT_PATH is not set'))
-        unless $outpath;
-
-    $options = { binmode => $options } unless ref $options;
-
-    sub {
-        my $text = shift;
-        my $outpath = $context->config->{ OUTPUT_PATH }
-            || return '';
-        $outpath .= "/$file";
-        my $error = Template::_output($outpath, \$text, $options);
-        die Template::Exception->new('redirect', $error)
-            if $error;
-        return '';
-    }
-}
-
-
-#------------------------------------------------------------------------
-# stdout_filter_factory($context, $binmode)    [% FILTER stdout(binmode) %]
-#
-# Create a filter to print a block to stdout, with an optional binmode.
-#------------------------------------------------------------------------
-
-sub stdout_filter_factory {
-    my ($context, $options) = @_;
-
-    $options = { binmode => $options } unless ref $options;
-
-    sub {
-        my $text = shift;
-        binmode(STDOUT) if $options->{ binmode };
-        print STDOUT $text;
-        return '';
-    }
-}
-
-
-#------------------------------------------------------------------------
-# latex_filter_factory($context, $outputType)   [% FILTER latex(outputType) %]
-#
-# Return a filter sub that converts a (hopefully) complete LaTeX source
-# file to either "ps", "dvi", or "pdf".  Output type should be "ps", "dvi"
-# or "pdf" (pdf is default).
-#
-# Creates a temporary directory below File::Spec->tmpdir() (often /tmp)
-# and writes the text into doc.tex. It then runs either pdflatex or
-# latex and optionally dvips. Based on the exit status either returns
-# the entire doc.(pdf|ps|dvi) output or throws an error with a summary
-# of the error messages from doc.log.
-#
-# Written by Craig Barratt, Apr 28 2001.
-# Win32 additions by Richard Tietjen.
-#------------------------------------------------------------------------
-use File::Path;
-use File::Spec;
-use Cwd;
-
-sub latex_filter_factory
-{
-    my($context, $output) = @_;
-
-    $output = lc($output);
-    my $fName = "latex";
-    my($LaTeXPath, $PdfLaTeXPath, $DviPSPath)
-                        = @{Template::Config->latexpaths()};
-    if ( $output eq "ps" || $output eq "dvi" ) {
-        $context->throw($fName,
-                "latex not installed (see Template::Config::LATEX_PATH)")
-                                if ( $LaTeXPath eq "" );
-    } else {
-        $output = "pdf";
-        $LaTeXPath = $PdfLaTeXPath;
-        $context->throw($fName,
-                "pdflatex not installed (see Template::Config::PDFLATEX_PATH)")
-                                if ( $LaTeXPath eq "" );
-    }
-    if ( $output eq "ps" && $DviPSPath eq "" ) {
-        $context->throw($fName,
-                "dvips not installed (see Template::Config::DVIPS_PATH)");
-    }
-    if ( $^O !~ /^(MacOS|os2|VMS)$/i ) {
-        return sub {
-            local(*FH);
-            my $text = shift;
-            my $tmpRootDir = File::Spec->tmpdir();
-            my $cnt = 0;
-            my($tmpDir, $fileName, $devnull);
-            my $texDoc = 'doc';
-
-            do {
-                $tmpDir = File::Spec->catdir($tmpRootDir,
-                                             "tt2latex$$" . "_$cnt");
-                $cnt++;
-            } while ( -e $tmpDir );
-            mkpath($tmpDir, 0, 0700);
-            $context->throw($fName, "can't create temp dir $tmpDir")
-                    if ( !-d $tmpDir );
-            $fileName = File::Spec->catfile($tmpDir, "$texDoc.tex");
-            $devnull  = File::Spec->devnull();
-            if ( !open(FH, ">$fileName") ) {
-                rmtree($tmpDir);
-                $context->throw($fName, "can't open $fileName for output");
-            }
-            print(FH $text);
-            close(FH);
-
-            # latex must run in tmpDir directory
-            my $currDir = cwd();
-            if ( !chdir($tmpDir) ) {
-                rmtree($tmpDir);
-                $context->throw($fName, "can't chdir $tmpDir");
-            }
-            #
-            # We don't need to quote the backslashes on windows, but we
-            # do on other OSs
-            #
-            my $LaTeX_arg = "\\nonstopmode\\input{$texDoc}";
-            $LaTeX_arg = "'$LaTeX_arg'" if ( $^O ne 'MSWin32' );
-            if ( system("$LaTeXPath $LaTeX_arg"
-                   . " 1>$devnull 2>$devnull 0<$devnull") ) {
-                my $texErrs = "";
-                $fileName = File::Spec->catfile($tmpDir, "$texDoc.log");
-                if ( open(FH, "<$fileName") ) {
-                    my $state = 0;
-                    #
-                    # Try to extract just the interesting errors from
-                    # the verbose log file
-                    #
-                    while ( <FH> ) {
-                        #
-                        # TeX errors seems to start with a "!" at the
-                        # start of the line, and are followed several
-                        # lines later by a line designator of the
-                        # form "l.nnn" where nnn is the line number.
-                        # We make sure we pick up every /^!/ line, and
-                        # the first /^l.\d/ line after each /^!/ line.
-                        #
-                        if ( /^(!.*)/ ) {
-                            $texErrs .= $1 . "\n";
-                            $state = 1;
-                        }
-                        if ( $state == 1 && /^(l\.\d.*)/ ) {
-                            $texErrs .= $1 . "\n";
-                            $state = 0;
-                        }
-                    }
-                    close(FH);
-                } else {
-                    $texErrs = "Unable to open $fileName\n";
-                }
-                my $ok = chdir($currDir);
-                rmtree($tmpDir);
-                $context->throw($fName, "can't chdir $currDir") if ( !$ok );
-                $context->throw($fName, "latex exited with errors:\n$texErrs");
-            }
-            if ( $output eq "ps" ) {
-                $fileName = File::Spec->catfile($tmpDir, "$texDoc.dvi");
-                if ( system("$DviPSPath $texDoc -o"
-                       . " 1>$devnull 2>$devnull 0<$devnull") ) {
-                    my $ok = chdir($currDir);
-                    rmtree($tmpDir);
-                    $context->throw($fName, "can't chdir $currDir") if ( !$ok );
-                    $context->throw($fName, "can't run $DviPSPath $fileName");
-                }
-            }
-            if ( !chdir($currDir) ) {
-                rmtree($tmpDir);
-                $context->throw($fName, "can't chdir $currDir");
-            }
-
-            my $retStr;
-            $fileName = File::Spec->catfile($tmpDir, "$texDoc.$output");
-            if ( open(FH, $fileName) ) {
-                local $/ = undef;       # slurp file in one go
-                binmode(FH);
-                $retStr = <FH>;
-                close(FH);
-            } else {
-                rmtree($tmpDir);
-                $context->throw($fName, "Can't open output file $fileName");
-            }
-            rmtree($tmpDir);
-            return $retStr;
-        }
-    } else {
-        $context->throw("$fName not yet supported on $^O OS."
-                      . "  Please contribute code!!");
-    }
-}
-
-1;
-
-__END__
-
-
-#------------------------------------------------------------------------
-# IMPORTANT NOTE
-#   This documentation is generated automatically from source
-#   templates.  Any changes you make here may be lost.
-# 
-#   The 'docsrc' documentation source bundle is available for download
-#   from http://www.template-toolkit.org/docs.html and contains all
-#   the source templates, XML files, scripts, etc., from which the
-#   documentation for the Template Toolkit is built.
-#------------------------------------------------------------------------
-
-=head1 NAME
-
-Template::Filters - Post-processing filters for template blocks
-
-=head1 SYNOPSIS
-
-    use Template::Filters;
-
-    $filters = Template::Filters->new(\%config);
-
-    ($filter, $error) = $filters->fetch($name, \@args, $context);
-
-=head1 DESCRIPTION
-
-The Template::Filters module implements a provider for creating and/or
-returning subroutines that implement the standard filters.  Additional 
-custom filters may be provided via the FILTERS options.
-
-=head1 METHODS
-
-=head2 new(\%params) 
-
-Constructor method which instantiates and returns a reference to a
-Template::Filters object.  A reference to a hash array of configuration
-items may be passed as a parameter.  These are described below.  
-
-    my $filters = Template::Filters->new({
-        FILTERS => { ... },
-    });
-
-    my $template = Template->new({
-        LOAD_FILTERS => [ $filters ],
-    });
-
-A default Template::Filters module is created by the Template.pm module
-if the LOAD_FILTERS option isn't specified.  All configuration parameters
-are forwarded to the constructor.
-
-    $template = Template->new({
-        FILTERS => { ... },
-    });
-
-=head2 fetch($name, \@args, $context)
-
-Called to request that a filter of a given name be provided.  The name
-of the filter should be specified as the first parameter.  This should
-be one of the standard filters or one specified in the FILTERS
-configuration hash.  The second argument should be a reference to an
-array containing configuration parameters for the filter.  This may be
-specified as 0, or undef where no parameters are provided.  The third
-argument should be a reference to the current Template::Context
-object.
-
-The method returns a reference to a filter sub-routine on success.  It
-may also return (undef, STATUS_DECLINE) to decline the request, to allow
-delegation onto other filter providers in the LOAD_FILTERS chain of 
-responsibility.  On error, ($error, STATUS_ERROR) is returned where $error
-is an error message or Template::Exception object indicating the error
-that occurred. 
-
-When the TOLERANT option is set, errors are automatically downgraded to
-a STATUS_DECLINE response.
-
-
-=head1 CONFIGURATION OPTIONS
-
-The following list details the configuration options that can be provided
-to the Template::Filters new() constructor.
-
-=over 4
-
-
-
-
-=item FILTERS
-
-The FILTERS option can be used to specify custom filters which can
-then be used with the FILTER directive like any other.  These are
-added to the standard filters which are available by default.  Filters
-specified via this option will mask any standard filters of the same
-name.
-
-The FILTERS option should be specified as a reference to a hash array
-in which each key represents the name of a filter.  The corresponding
-value should contain a reference to an array containing a subroutine
-reference and a flag which indicates if the filter is static (0) or
-dynamic (1).  A filter may also be specified as a solitary subroutine
-reference and is assumed to be static.
-
-    $filters = Template::Filters->new({
-        FILTERS => {
-            'sfilt1' =>   \&static_filter,      # static
-            'sfilt2' => [ \&static_filter, 0 ], # same as above
-            'dfilt1' => [ \&dyanamic_filter_factory, 1 ],
-        },
-    });
-
-Additional filters can be specified at any time by calling the 
-define_filter() method on the current Template::Context object.
-The method accepts a filter name, a reference to a filter 
-subroutine and an optional flag to indicate if the filter is 
-dynamic.
-
-    my $context = $template->context();
-    $context->define_filter('new_html', \&new_html);
-    $context->define_filter('new_repeat', \&new_repeat, 1);
-
-Static filters are those where a single subroutine reference is used
-for all invocations of a particular filter.  Filters that don't accept
-any configuration parameters (e.g. 'html') can be implemented
-statically.  The subroutine reference is simply returned when that
-particular filter is requested.  The subroutine is called to filter
-the output of a template block which is passed as the only argument.
-The subroutine should return the modified text.
-
-    sub static_filter {
-        my $text = shift;
-        # do something to modify $text...
-        return $text;
-    }
-
-The following template fragment:
-
-    [% FILTER sfilt1 %]
-    Blah blah blah.
-    [% END %]
-
-is approximately equivalent to:
-
-    &static_filter("\nBlah blah blah.\n");
-
-Filters that can accept parameters (e.g. 'truncate') should be
-implemented dynamically.  In this case, the subroutine is taken to be
-a filter 'factory' that is called to create a unique filter subroutine
-each time one is requested.  A reference to the current
-Template::Context object is passed as the first parameter, followed by
-any additional parameters specified.  The subroutine should return
-another subroutine reference (usually a closure) which implements the
-filter.
-
-    sub dynamic_filter_factory {
-        my ($context, @args) = @_;
-
-        return sub {
-            my $text = shift;
-            # do something to modify $text...
-            return $text;           
-        }
-    }
-
-The following template fragment:
-
-    [% FILTER dfilt1(123, 456) %] 
-    Blah blah blah
-    [% END %]              
-
-is approximately equivalent to:
-
-    my $filter = &dynamic_filter_factory($context, 123, 456);
-    &$filter("\nBlah blah blah.\n");
-
-See the FILTER directive for further examples.
-
-
-
-
-=item TOLERANT
-
-The TOLERANT flag is used by the various Template Toolkit provider
-modules (Template::Provider, Template::Plugins, Template::Filters) to
-control their behaviour when errors are encountered.  By default, any
-errors are reported as such, with the request for the particular
-resource (template, plugin, filter) being denied and an exception
-raised.  When the TOLERANT flag is set to any true values, errors will
-be silently ignored and the provider will instead return
-STATUS_DECLINED.  This allows a subsequent provider to take
-responsibility for providing the resource, rather than failing the
-request outright.  If all providers decline to service the request,
-either through tolerated failure or a genuine disinclination to
-comply, then a 'E<lt>resourceE<gt> not found' exception is raised.
-
-
-
-
-=item DEBUG
-
-The DEBUG option can be used to enable debugging messages from the
-Template::Filters module by setting it to include the DEBUG_FILTERS
-value.
-
-    use Template::Constants qw( :debug );
-
-    my $template = Template->new({
-	DEBUG => DEBUG_FILTERS | DEBUG_PLUGINS,
-    });
-
-
-
-
-=back
-
-=head1 TEMPLATE TOOLKIT FILTERS
-
-The following standard filters are distributed with the Template Toolkit.
-
-
-
-=head2 format(format)
-
-The 'format' filter takes a format string as a parameter (as per
-printf()) and formats each line of text accordingly.
-
-    [% FILTER format('<!-- %-40s -->') %]
-    This is a block of text filtered 
-    through the above format.
-    [% END %]
-
-output:
-
-    <!-- This is a block of text filtered        -->
-    <!-- through the above format.               -->
-
-=head2 upper
-
-Folds the input to UPPER CASE.
-
-    [% "hello world" FILTER upper %]
-
-output:
-
-    HELLO WORLD
-
-=head2 lower
-
-Folds the input to lower case.
-
-    [% "Hello World" FILTER lower %]
-
-output:
-
-    hello world
-
-=head2 ucfirst
-
-Folds the first character of the input to UPPER CASE.
-
-    [% "hello" FILTER ucfirst %]
-
-output:
-
-    Hello
-
-=head2 lcfirst
-
-Folds the first character of the input to lower case.
-
-    [% "HELLO" FILTER lcfirst %]
-
-output:
-
-    hELLO
-
-=head2 trim
-
-Trims any leading or trailing whitespace from the input text.  Particularly 
-useful in conjunction with INCLUDE, PROCESS, etc., having the same effect
-as the TRIM configuration option.
-
-    [% INCLUDE myfile | trim %]
-
-=head2 collapse
-
-Collapse any whitespace sequences in the input text into a single space.
-Leading and trailing whitespace (which would be reduced to a single space)
-is removed, as per trim.
-
-    [% FILTER collapse %]
-
-       The   cat
-
-       sat    on
-
-       the   mat
-
-    [% END %]
-
-output:
-
-    The cat sat on the mat
-
-=head2 html
-
-Converts the characters 'E<lt>', 'E<gt>' and '&' to '<', '>' and
-'&', respectively, protecting them from being interpreted as
-representing HTML tags or entities.
-
-    [% FILTER html %]
-    Binary "<=>" returns -1, 0, or 1 depending on...
-    [% END %]
-
-output:
-
-    Binary "<=>" returns -1, 0, or 1 depending on...
-
-=head2 html_entity
-
-The html filter is fast and simple but it doesn't encode the full
-range of HTML entities that your text may contain.  The html_entity
-filter uses either the Apache::Util module (which is written in C and
-is therefore faster) or the HTML::Entities module (written in Perl but
-equally as comprehensive) to perform the encoding.  If one or other of
-these modules are installed on your system then the text will be
-encoded (via the escape_html() or encode_entities() subroutines
-respectively) to convert all extended characters into their
-appropriate HTML entities (e.g. converting 'é' to 'é').  If
-neither module is available on your system then an 'html_entity' exception
-will be thrown reporting an appropriate message.   
-
-For further information on HTML entity encoding, see
-http://www.w3.org/TR/REC-html40/sgml/entities.html.
-
-=head2 html_para
-
-This filter formats a block of text into HTML paragraphs.  A sequence of 
-two or more newlines is used as the delimiter for paragraphs which are 
-then wrapped in HTML E<lt>pE<gt>...E<lt>/pE<gt> tags.
-
-    [% FILTER html_para %]
-    The cat sat on the mat.
-
-    Mary had a little lamb.
-    [% END %]
-
-output:
-
-    <p>
-    The cat sat on the mat.
-    </p>
-
-    <p>
-    Mary had a little lamb.
-    </p>
-
-=head2 html_break / html_para_break
-
-Similar to the html_para filter described above, but uses the HTML tag
-sequence E<lt>brE<gt>E<lt>brE<gt> to join paragraphs.
-
-    [% FILTER html_break %]
-    The cat sat on the mat.
-
-    Mary had a little lamb.
-    [% END %]
-
-output:
-
-    The cat sat on the mat.
-    <br>
-    <br>
-    Mary had a little lamb.
-
-=head2 html_line_break
-
-This filter replaces any newlines with E<lt>brE<gt> HTML tags,
-thus preserving the line breaks of the original text in the 
-HTML output.
-
-    [% FILTER html_line_break %]
-    The cat sat on the mat.
-    Mary had a little lamb.
-    [% END %]
-
-output:
-
-    The cat sat on the mat.<br>
-    Mary had a little lamb.<br>
-
-=head2 uri
-
-This filter URI escapes the input text, converting any characters 
-outside of the permitted URI character set (as defined by RFC 2396)
-into a C<%nn> hex escape.
-
-    [% 'my file.html' | uri %]
-
-output:
-
-    my%20file.html
-
-Note that URI escaping isn't always enough when generating hyperlinks in
-an HTML document.  The C<&> character, for example, is valid in a URI and
-will not be escaped by the URI filter.  In this case you should also filter
-the text through the 'html' filter.
-
-    <a href="[% filename | uri | html %]">click here</a>
-
-=head2 indent(pad)
-
-Indents the text block by a fixed pad string or width.  The 'pad' argument
-can be specified as a string, or as a numerical value to indicate a pad
-width (spaces).  Defaults to 4 spaces if unspecified.
-
-    [% FILTER indent('ME> ') %]
-    blah blah blah
-    cabbages, rhubard, onions
-    [% END %]
-
-output:
-
-    ME> blah blah blah
-    ME> cabbages, rhubard, onions
-
-=head2 truncate(length)
-
-Truncates the text block to the length specified, or a default length of
-32.  Truncated text will be terminated with '...' (i.e. the '...' falls
-inside the required length, rather than appending to it).
-
-    [% FILTER truncate(21) %]
-    I have much to say on this matter that has previously 
-    been said on more than one occasion.
-    [% END %]
-
-output:
-
-    I have much to say...
-
-=head2 repeat(iterations)
-
-Repeats the text block for as many iterations as are specified (default: 1).
-
-    [% FILTER repeat(3) %]
-    We want more beer and we want more beer,
-    [% END %]
-    We are the more beer wanters!
-
-output:
-
-    We want more beer and we want more beer,
-    We want more beer and we want more beer,
-    We want more beer and we want more beer,
-    We are the more beer wanters!
-
-=head2 remove(string) 
-
-Searches the input text for any occurrences of the specified string and 
-removes them.  A Perl regular expression may be specified as the search 
-string.
-
-    [% "The  cat  sat  on  the  mat" FILTER remove('\s+') %]
-
-output: 
-
-    Thecatsatonthemat
-
-=head2 replace(search, replace) 
-
-Similar to the remove filter described above, but taking a second parameter
-which is used as a replacement string for instances of the search string.
-
-    [% "The  cat  sat  on  the  mat" | replace('\s+', '_') %]
-
-output: 
-
-    The_cat_sat_on_the_mat
-
-=head2 redirect(file, options)
-
-The 'redirect' filter redirects the output of the block into a separate
-file, specified relative to the OUTPUT_PATH configuration item.
-
-    [% FOREACH user = myorg.userlist %]
-       [% FILTER redirect("users/${user.id}.html") %]
-          [% INCLUDE userinfo %]
-       [% END %]
-    [% END %]
-
-or more succinctly, using side-effect notation:
-
-    [% INCLUDE userinfo 
-         FILTER redirect("users/${user.id}.html")
-	   FOREACH user = myorg.userlist 
-    %]
-
-A 'file' exception will be thrown if the OUTPUT_PATH option is undefined.
-
-An optional 'binmode' argument can follow the filename to explicitly set
-the output file to binary mode.
-
-    [% PROCESS my/png/generator 
-         FILTER redirect("images/logo.png", binmode=1) %]
-
-For backwards compatibility with earlier versions, a single true/false
-value can be used to set binary mode.
-
-    [% PROCESS my/png/generator 
-         FILTER redirect("images/logo.png", 1) %]
-
-For the sake of future compatibility and clarity, if nothing else, we
-would strongly recommend you explicitly use the named 'binmode' option
-as shown in the first example.
-
-=head2 eval / evaltt
-
-The 'eval' filter evaluates the block as template text, processing
-any directives embedded within it.  This allows template variables to
-contain template fragments, or for some method to be provided for
-returning template fragments from an external source such as a
-database, which can then be processed in the template as required.
-
-    my $vars  = {
-	fragment => "The cat sat on the [% place %]",
-    };
-    $template->process($file, $vars);
-
-The following example:
-
-    [% fragment | eval %]
-
-is therefore equivalent to 
-
-    The cat sat on the [% place %]
-
-The 'evaltt' filter is provided as an alias for 'eval'.
-
-=head2 perl / evalperl
-
-The 'perl' filter evaluates the block as Perl code.  The EVAL_PERL
-option must be set to a true value or a 'perl' exception will be
-thrown.
-
-    [% my_perl_code | perl %]
-
-In most cases, the [% PERL %] ... [% END %] block should suffice for 
-evaluating Perl code, given that template directives are processed 
-before being evaluate as Perl.  Thus, the previous example could have
-been written in the more verbose form:
-
-    [% PERL %]
-    [% my_perl_code %]
-    [% END %]
-
-as well as
-
-    [% FILTER perl %]
-    [% my_perl_code %]
-    [% END %]
-
-The 'evalperl' filter is provided as an alias for 'perl' for backwards
-compatibility.
-
-=head2 stdout(options)
-
-The stdout filter prints the output generated by the enclosing block to
-STDOUT.  The 'binmode' option can be passed as either a named parameter
-or a single argument to set STDOUT to binary mode (see the
-binmode perl function).
-
-    [% PROCESS something/cool
-           FILTER stdout(binmode=1) # recommended %]
-
-    [% PROCESS something/cool
-           FILTER stdout(1)         # alternate %]
-
-The stdout filter can be used to force binmode on STDOUT, or also inside
-redirect, null or stderr blocks to make sure that particular output goes
-to stdout. See the null filter below for an example.
-
-=head2 stderr
-
-The stderr filter prints the output generated by the enclosing block to
-STDERR.
-
-=head2 null
-
-The null filter prints nothing.  This is useful for plugins whose
-methods return values that you don't want to appear in the output.
-Rather than assigning every plugin method call to a dummy variable
-to silence it, you can wrap the block in a null filter:
-
-    [% FILTER null;
-        USE im = GD.Image(100,100);
-        black = im.colorAllocate(0,   0, 0);
-        red   = im.colorAllocate(255,0,  0);
-        blue  = im.colorAllocate(0,  0,  255);
-        im.arc(50,50,95,75,0,360,blue);
-        im.fill(50,50,red);
-        im.png | stdout(1);
-       END;
-    -%]
-
-Notice the use of the stdout filter to ensure that a particular expression
-generates output to stdout (in this case in binary mode).
-
-=head2 latex(outputType)
-
-Passes the text block to LaTeX and produces either PDF, DVI or
-PostScript output.  The 'outputType' argument determines the output
-format and it should be set to one of the strings: "pdf" (default),
-"dvi", or "ps".
-
-The text block should be a complete LaTeX source file.
-
-    [% FILTER latex("pdf") -%]
-    \documentclass{article}
-
-    \begin{document}
-
-    \title{A Sample TT2 \LaTeX\ Source File}
-    \author{Craig Barratt}
-    \maketitle
-
-    \section{Introduction}
-    This is some text.
-
-    \end{document}
-    [% END -%]
-
-The output will be a PDF file. You should be careful not to prepend or
-append any extraneous characters or text outside the FILTER block,
-since this text will wrap the (binary) output of the latex filter.
-Notice the END directive uses '-%]' for the END_TAG to remove the
-trailing new line.
-
-One example where you might prepend text is in a CGI script where
-you might include the Content-Type before the latex output, eg:
-
-    Content-Type: application/pdf
-
-    [% FILTER latex("pdf") -%]
-    \documentclass{article}
-    \begin{document}
-    ...
-    \end{document}
-    [% END -%]
-
-In other cases you might use the redirect filter to put the output
-into a file, rather than delivering it to stdout.  This might be
-suitable for batch scripts:
-
-    [% output = FILTER latex("pdf") -%]
-    \documentclass{article}
-    \begin{document}
-    ...
-    \end{document}
-    [% END; output | redirect("document.pdf", 1) -%]
-
-(Notice the second argument to redirect to force binary mode.)
-
-Note that the latex filter runs one or two external programs, so it
-isn't very fast.  But for modest documents the performance is adequate,
-even for interactive applications.
-
-A error of type 'latex' will be thrown if there is an error reported
-by latex, pdflatex or dvips.
-
-=head1 AUTHOR
-
-Andy Wardley E<lt>abw@andywardley.comE<gt>
-
-L<http://www.andywardley.com/|http://www.andywardley.com/>
-
-
-
-
-=head1 VERSION
-
-2.77, distributed as part of the
-Template Toolkit version 2.13, released on 30 January 2004.
-
-=head1 COPYRIGHT
-
-  Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
-  Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
-
-This module is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
-
-=head1 SEE ALSO
-
-L<Template|Template>, L<Template::Context|Template::Context>, L<Template::Manual::Filters|Template::Manual::Filters>
-
-=cut
-
-# Local Variables:
-# mode: perl
-# perl-indent-level: 4
-# indent-tabs-mode: nil
-# End:
-#
-# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Grammar.pm b/lib/Template/Grammar.pm
deleted file mode 100644
index 8635426..0000000
--- a/lib/Template/Grammar.pm
+++ /dev/null
@@ -1,6179 +0,0 @@
-#============================================================= -*-Perl-*-
-#
-# Template::Grammar
-#
-# DESCRIPTION
-#   Grammar file for the Template Toolkit language containing token
-#   definitions and parser state/rules tables generated by Parse::Yapp.
-#
-# AUTHOR
-#   Andy Wardley   <abw@wardley.org>
-#
-# COPYRIGHT
-#   Copyright (C) 1996-2000 Andy Wardley.  All Rights Reserved.
-#   Copyright (C) 1998-2000 Canon Research Centre Europe Ltd.
-#
-#   This module is free software; you can redistribute it and/or
-#   modify it under the same terms as Perl itself.
-#
-#------------------------------------------------------------------------
-#
-# NOTE: this module is constructed from the parser/Grammar.pm.skel
-# file by running the parser/yc script.  You only need to do this if 
-# you have modified the grammar in the parser/Parser.yp file and need
-# to-recompile it.  See the README in the 'parser' directory for more
-# information (sub-directory of the Template distribution).
-#
-#------------------------------------------------------------------------
-#
-# $Id: Grammar.pm,v 2.22 2004/01/13 16:19:10 abw Exp $
-#
-#========================================================================
-
-package Template::Grammar;
-
-require 5.004;
-
-use strict;
-use vars qw( $VERSION );
-
-$VERSION  = sprintf("%d.%02d", q$Revision: 2.22 $ =~ /(\d+)\.(\d+)/);
-
-my (@RESERVED, %CMPOP, $LEXTABLE, $RULES, $STATES);
-my ($factory, $rawstart);
-
-
-#========================================================================
-
-# Reserved words, comparison and binary operators
-#========================================================================
-
-@RESERVED = qw( 
-	GET CALL SET DEFAULT INSERT INCLUDE PROCESS WRAPPER BLOCK END
-	USE PLUGIN FILTER MACRO PERL RAWPERL TO STEP AND OR NOT DIV MOD
-	IF UNLESS ELSE ELSIF FOR NEXT WHILE SWITCH CASE META IN
-	TRY THROW CATCH FINAL LAST RETURN STOP CLEAR VIEW DEBUG
-    );
-
-# for historical reasons, != and == are converted to ne and eq to perform 
-# stringwise comparison (mainly because it doesn't generate "non-numerical 
-# comparison" warnings which != and == can) but the others (e.g. < > <= >=)
-# are not converted to their stringwise equivalents.  I added 'gt' et al, 
-# briefly for v2.04d and then took them out again in 2.04e.
-
-%CMPOP = qw( 
-    != ne
-    == eq
-    <  <
-    >  >
-    >= >=
-    <= <=
-);
-
-
-#========================================================================
-# Lexer Token Table
-#========================================================================
-
-# lookup table used by lexer is initialised with special-cases
-$LEXTABLE = {
-    'FOREACH' => 'FOR',
-    'BREAK'   => 'LAST',
-    '&&'      => 'AND',
-    '||'      => 'OR',
-    '!'       => 'NOT',
-    '|'	      => 'FILTER',
-    '.'       => 'DOT',
-    '_'       => 'CAT',
-    '..'      => 'TO',
-#    ':'       => 'MACRO',
-    '='       => 'ASSIGN',
-    '=>'      => 'ASSIGN',
-#    '->'      => 'ARROW',
-    ','       => 'COMMA',
-    '\\'      => 'REF',
-    'and'     => 'AND',		# explicitly specified so that qw( and or
-    'or'      => 'OR',		# not ) can always be used in lower case, 
-    'not'     => 'NOT',		# regardless of ANYCASE flag
-    'mod'     => 'MOD',
-    'div'     => 'DIV',
-};
-
-# localise the temporary variables needed to complete lexer table
-{ 
-#    my @tokens = qw< ( ) [ ] { } ${ $ / ; : ? >;
-    my @tokens = qw< ( ) [ ] { } ${ $ + / ; : ? >;
-    my @cmpop  = keys %CMPOP;
-#    my @binop  = qw( + - * % );              # '/' above, in @tokens
-    my @binop  = qw( - * % );              # '+' and '/' above, in @tokens
-
-    # fill lexer table, slice by slice, with reserved words and operators
-    @$LEXTABLE{ @RESERVED, @cmpop, @binop, @tokens } 
-	= ( @RESERVED, ('CMPOP') x @cmpop, ('BINOP') x @binop, @tokens );
-}
-
-
-#========================================================================
-# CLASS METHODS
-#========================================================================
-
-sub new {
-    my $class = shift;
-    bless {
-	LEXTABLE => $LEXTABLE,
-	STATES   => $STATES,
-	RULES    => $RULES,
-    }, $class;
-}
-
-# update method to set package-scoped $factory lexical 
-sub install_factory {
-    my ($self, $new_factory) = @_;
-    $factory = $new_factory;
-}
-
-
-#========================================================================
-# States
-#========================================================================
-
-$STATES = [
-	{#State 0
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'template' => 52,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'switch' => 34,
-			'try' => 35,
-			'assign' => 19,
-			'block' => 72,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 1
-		ACTIONS => {
-			"\$" => 43,
-			'LITERAL' => 75,
-			'IDENT' => 2,
-			"\${" => 37
-		},
-		GOTOS => {
-			'setlist' => 76,
-			'item' => 39,
-			'assign' => 19,
-			'node' => 23,
-			'ident' => 74
-		}
-	},
-	{#State 2
-		DEFAULT => -130
-	},
-	{#State 3
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 79,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 4
-		DEFAULT => -23
-	},
-	{#State 5
-		ACTIONS => {
-			";" => 80
-		}
-	},
-	{#State 6
-		DEFAULT => -37
-	},
-	{#State 7
-		DEFAULT => -14
-	},
-	{#State 8
-		ACTIONS => {
-			"\"" => 89,
-			"\$" => 86,
-			'LITERAL' => 88,
-			'FILENAME' => 83,
-			'IDENT' => 81,
-			'NUMBER' => 84
-		},
-		GOTOS => {
-			'filepart' => 87,
-			'names' => 91,
-			'nameargs' => 90,
-			'filename' => 85,
-			'name' => 82
-		}
-	},
-	{#State 9
-		ACTIONS => {
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"]" => 94,
-			"\${" => 37
-		},
-		GOTOS => {
-			'sterm' => 96,
-			'item' => 39,
-			'range' => 93,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 95,
-			'list' => 92,
-			'lterm' => 56
-		}
-	},
-	{#State 10
-		ACTIONS => {
-			";" => 97
-		}
-	},
-	{#State 11
-		DEFAULT => -5
-	},
-	{#State 12
-		ACTIONS => {
-			";" => -20
-		},
-		DEFAULT => -27
-	},
-	{#State 13
-		DEFAULT => -78,
-		GOTOS => {
-			'@5-1' => 98
-		}
-	},
-	{#State 14
-		ACTIONS => {
-			'IDENT' => 99
-		},
-		DEFAULT => -87,
-		GOTOS => {
-			'blockargs' => 102,
-			'metadata' => 101,
-			'meta' => 100
-		}
-	},
-	{#State 15
-		ACTIONS => {
-			'IDENT' => 99
-		},
-		GOTOS => {
-			'metadata' => 103,
-			'meta' => 100
-		}
-	},
-	{#State 16
-		ACTIONS => {
-			'DOT' => 104,
-			'ASSIGN' => 105
-		},
-		DEFAULT => -109
-	},
-	{#State 17
-		ACTIONS => {
-			"\"" => 89,
-			"\$" => 86,
-			'LITERAL' => 88,
-			'FILENAME' => 83,
-			'IDENT' => 81,
-			'NUMBER' => 84
-		},
-		GOTOS => {
-			'filepart' => 87,
-			'names' => 91,
-			'nameargs' => 106,
-			'filename' => 85,
-			'name' => 82
-		}
-	},
-	{#State 18
-		ACTIONS => {
-			'IDENT' => 107
-		}
-	},
-	{#State 19
-		DEFAULT => -149
-	},
-	{#State 20
-		DEFAULT => -12
-	},
-	{#State 21
-		ACTIONS => {
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 108,
-			"\"" => 60,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'sterm' => 68,
-			'item' => 39,
-			'loopvar' => 110,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 109,
-			'lterm' => 56
-		}
-	},
-	{#State 22
-		DEFAULT => -40
-	},
-	{#State 23
-		DEFAULT => -127
-	},
-	{#State 24
-		DEFAULT => -6
-	},
-	{#State 25
-		ACTIONS => {
-			"\"" => 117,
-			"\$" => 114,
-			'LITERAL' => 116,
-			'FILENAME' => 83,
-			'IDENT' => 111,
-			'NUMBER' => 84,
-			"\${" => 37
-		},
-		GOTOS => {
-			'filepart' => 87,
-			'names' => 91,
-			'nameargs' => 118,
-			'filename' => 85,
-			'lvalue' => 112,
-			'lnameargs' => 115,
-			'item' => 113,
-			'name' => 82
-		}
-	},
-	{#State 26
-		DEFAULT => -113
-	},
-	{#State 27
-		ACTIONS => {
-			"\$" => 43,
-			'IDENT' => 2,
-			"\${" => 37
-		},
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'ident' => 119
-		}
-	},
-	{#State 28
-		ACTIONS => {
-			'LITERAL' => 124,
-			'FILENAME' => 83,
-			'IDENT' => 120,
-			'NUMBER' => 84
-		},
-		DEFAULT => -87,
-		GOTOS => {
-			'blockargs' => 123,
-			'filepart' => 87,
-			'filename' => 122,
-			'blockname' => 121,
-			'metadata' => 101,
-			'meta' => 100
-		}
-	},
-	{#State 29
-		DEFAULT => -43
-	},
-	{#State 30
-		ACTIONS => {
-			"\$" => 43,
-			'LITERAL' => 129,
-			'IDENT' => 2,
-			"\${" => 37
-		},
-		DEFAULT => -119,
-		GOTOS => {
-			'params' => 128,
-			'hash' => 125,
-			'item' => 126,
-			'param' => 127
-		}
-	},
-	{#State 31
-		DEFAULT => -25
-	},
-	{#State 32
-		ACTIONS => {
-			"\"" => 117,
-			"\$" => 114,
-			'LITERAL' => 116,
-			'FILENAME' => 83,
-			'IDENT' => 111,
-			'NUMBER' => 84,
-			"\${" => 37
-		},
-		GOTOS => {
-			'filepart' => 87,
-			'names' => 91,
-			'nameargs' => 118,
-			'filename' => 85,
-			'lvalue' => 112,
-			'lnameargs' => 130,
-			'item' => 113,
-			'name' => 82
-		}
-	},
-	{#State 33
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -2,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 131,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 34
-		DEFAULT => -22
-	},
-	{#State 35
-		DEFAULT => -24
-	},
-	{#State 36
-		ACTIONS => {
-			"\"" => 89,
-			"\$" => 86,
-			'LITERAL' => 88,
-			'FILENAME' => 83,
-			'IDENT' => 81,
-			'NUMBER' => 84
-		},
-		GOTOS => {
-			'filepart' => 87,
-			'names' => 91,
-			'nameargs' => 132,
-			'filename' => 85,
-			'name' => 82
-		}
-	},
-	{#State 37
-		ACTIONS => {
-			"\"" => 60,
-			"\$" => 43,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			'REF' => 27,
-			'NUMBER' => 26,
-			"\${" => 37
-		},
-		GOTOS => {
-			'sterm' => 133,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77
-		}
-	},
-	{#State 38
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 134,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 39
-		ACTIONS => {
-			"(" => 135
-		},
-		DEFAULT => -128
-	},
-	{#State 40
-		ACTIONS => {
-			";" => 136
-		}
-	},
-	{#State 41
-		DEFAULT => -38
-	},
-	{#State 42
-		DEFAULT => -11
-	},
-	{#State 43
-		ACTIONS => {
-			'IDENT' => 137
-		}
-	},
-	{#State 44
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 138,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 45
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 139,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 46
-		DEFAULT => -42
-	},
-	{#State 47
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 140,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 48
-		ACTIONS => {
-			'IF' => 144,
-			'FILTER' => 143,
-			'FOR' => 142,
-			'WHILE' => 146,
-			'WRAPPER' => 145,
-			'UNLESS' => 141
-		}
-	},
-	{#State 49
-		DEFAULT => -39
-	},
-	{#State 50
-		DEFAULT => -10
-	},
-	{#State 51
-		ACTIONS => {
-			"\"" => 89,
-			"\$" => 86,
-			'LITERAL' => 88,
-			'FILENAME' => 83,
-			'IDENT' => 81,
-			'NUMBER' => 84
-		},
-		GOTOS => {
-			'filepart' => 87,
-			'names' => 91,
-			'nameargs' => 147,
-			'filename' => 85,
-			'name' => 82
-		}
-	},
-	{#State 52
-		ACTIONS => {
-			'' => 148
-		}
-	},
-	{#State 53
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 57,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 149,
-			'term' => 58,
-			'expr' => 151,
-			'assign' => 150,
-			'lterm' => 56
-		}
-	},
-	{#State 54
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 152,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 55
-		ACTIONS => {
-			"\"" => 89,
-			"\$" => 86,
-			'LITERAL' => 88,
-			'FILENAME' => 83,
-			'IDENT' => 81,
-			'NUMBER' => 84
-		},
-		GOTOS => {
-			'filepart' => 87,
-			'names' => 91,
-			'nameargs' => 153,
-			'filename' => 85,
-			'name' => 82
-		}
-	},
-	{#State 56
-		DEFAULT => -103
-	},
-	{#State 57
-		ACTIONS => {
-			'ASSIGN' => 154
-		},
-		DEFAULT => -112
-	},
-	{#State 58
-		DEFAULT => -146
-	},
-	{#State 59
-		DEFAULT => -15
-	},
-	{#State 60
-		DEFAULT => -176,
-		GOTOS => {
-			'quoted' => 155
-		}
-	},
-	{#State 61
-		ACTIONS => {
-			"\"" => 89,
-			"\$" => 86,
-			'LITERAL' => 88,
-			'FILENAME' => 83,
-			'IDENT' => 81,
-			'NUMBER' => 84
-		},
-		GOTOS => {
-			'filepart' => 87,
-			'names' => 91,
-			'nameargs' => 156,
-			'filename' => 85,
-			'name' => 82
-		}
-	},
-	{#State 62
-		ACTIONS => {
-			";" => -16,
-			"+" => 157,
-			'CAT' => 163,
-			'CMPOP' => 164,
-			"?" => 158,
-			'DIV' => 159,
-			'MOD' => 165,
-			"/" => 166,
-			'AND' => 160,
-			'BINOP' => 161,
-			'OR' => 162
-		},
-		DEFAULT => -26
-	},
-	{#State 63
-		DEFAULT => -13
-	},
-	{#State 64
-		DEFAULT => -36
-	},
-	{#State 65
-		ACTIONS => {
-			"\"" => 89,
-			"\$" => 86,
-			'LITERAL' => 88,
-			'FILENAME' => 83,
-			'IDENT' => 81,
-			'NUMBER' => 84
-		},
-		GOTOS => {
-			'filepart' => 87,
-			'names' => 91,
-			'nameargs' => 167,
-			'filename' => 85,
-			'name' => 82
-		}
-	},
-	{#State 66
-		DEFAULT => -9
-	},
-	{#State 67
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 168,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 68
-		DEFAULT => -104
-	},
-	{#State 69
-		ACTIONS => {
-			"\$" => 43,
-			'LITERAL' => 75,
-			'IDENT' => 2,
-			"\${" => 37
-		},
-		GOTOS => {
-			'setlist' => 169,
-			'item' => 39,
-			'assign' => 19,
-			'node' => 23,
-			'ident' => 74
-		}
-	},
-	{#State 70
-		ACTIONS => {
-			"\$" => 43,
-			'COMMA' => 171,
-			'LITERAL' => 75,
-			'IDENT' => 2,
-			"\${" => 37
-		},
-		DEFAULT => -19,
-		GOTOS => {
-			'item' => 39,
-			'assign' => 170,
-			'node' => 23,
-			'ident' => 74
-		}
-	},
-	{#State 71
-		DEFAULT => -8
-	},
-	{#State 72
-		DEFAULT => -1
-	},
-	{#State 73
-		DEFAULT => -21
-	},
-	{#State 74
-		ACTIONS => {
-			'ASSIGN' => 172,
-			'DOT' => 104
-		}
-	},
-	{#State 75
-		ACTIONS => {
-			'ASSIGN' => 154
-		}
-	},
-	{#State 76
-		ACTIONS => {
-			"\$" => 43,
-			'COMMA' => 171,
-			'LITERAL' => 75,
-			'IDENT' => 2,
-			"\${" => 37
-		},
-		DEFAULT => -30,
-		GOTOS => {
-			'item' => 39,
-			'assign' => 170,
-			'node' => 23,
-			'ident' => 74
-		}
-	},
-	{#State 77
-		ACTIONS => {
-			'DOT' => 104
-		},
-		DEFAULT => -109
-	},
-	{#State 78
-		DEFAULT => -112
-	},
-	{#State 79
-		ACTIONS => {
-			'CMPOP' => 164,
-			"?" => 158,
-			";" => 173,
-			"+" => 157,
-			'MOD' => 165,
-			'DIV' => 159,
-			"/" => 166,
-			'AND' => 160,
-			'CAT' => 163,
-			'BINOP' => 161,
-			'OR' => 162
-		}
-	},
-	{#State 80
-		DEFAULT => -7
-	},
-	{#State 81
-		DEFAULT => -173
-	},
-	{#State 82
-		DEFAULT => -166
-	},
-	{#State 83
-		DEFAULT => -172
-	},
-	{#State 84
-		DEFAULT => -174
-	},
-	{#State 85
-		ACTIONS => {
-			'DOT' => 174
-		},
-		DEFAULT => -168
-	},
-	{#State 86
-		ACTIONS => {
-			"\$" => 43,
-			'IDENT' => 2,
-			"\${" => 37
-		},
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'ident' => 175
-		}
-	},
-	{#State 87
-		DEFAULT => -171
-	},
-	{#State 88
-		DEFAULT => -169
-	},
-	{#State 89
-		DEFAULT => -176,
-		GOTOS => {
-			'quoted' => 176
-		}
-	},
-	{#State 90
-		DEFAULT => -35
-	},
-	{#State 91
-		ACTIONS => {
-			"+" => 177,
-			"(" => 178
-		},
-		DEFAULT => -156,
-		GOTOS => {
-			'args' => 179
-		}
-	},
-	{#State 92
-		ACTIONS => {
-			"{" => 30,
-			'COMMA' => 182,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"]" => 180,
-			"\${" => 37
-		},
-		GOTOS => {
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 181,
-			'lterm' => 56
-		}
-	},
-	{#State 93
-		ACTIONS => {
-			"]" => 183
-		}
-	},
-	{#State 94
-		DEFAULT => -107
-	},
-	{#State 95
-		DEFAULT => -116
-	},
-	{#State 96
-		ACTIONS => {
-			'TO' => 184
-		},
-		DEFAULT => -104
-	},
-	{#State 97
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 185,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 98
-		ACTIONS => {
-			";" => 186
-		}
-	},
-	{#State 99
-		ACTIONS => {
-			'ASSIGN' => 187
-		}
-	},
-	{#State 100
-		DEFAULT => -99
-	},
-	{#State 101
-		ACTIONS => {
-			'COMMA' => 189,
-			'IDENT' => 99
-		},
-		DEFAULT => -86,
-		GOTOS => {
-			'meta' => 188
-		}
-	},
-	{#State 102
-		ACTIONS => {
-			";" => 190
-		}
-	},
-	{#State 103
-		ACTIONS => {
-			'COMMA' => 189,
-			'IDENT' => 99
-		},
-		DEFAULT => -17,
-		GOTOS => {
-			'meta' => 188
-		}
-	},
-	{#State 104
-		ACTIONS => {
-			"\$" => 43,
-			'IDENT' => 2,
-			'NUMBER' => 192,
-			"\${" => 37
-		},
-		GOTOS => {
-			'item' => 39,
-			'node' => 191
-		}
-	},
-	{#State 105
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'WRAPPER' => 55,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'FILTER' => 25,
-			'RETURN' => 64,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 193,
-			'DEFAULT' => 69,
-			"{" => 30,
-			"\${" => 37
-		},
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'term' => 58,
-			'loop' => 4,
-			'expr' => 195,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'atomdir' => 12,
-			'mdir' => 194,
-			'sterm' => 68,
-			'filter' => 29,
-			'ident' => 149,
-			'perl' => 31,
-			'setlist' => 70,
-			'switch' => 34,
-			'try' => 35,
-			'assign' => 19,
-			'directive' => 196,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 106
-		DEFAULT => -33
-	},
-	{#State 107
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'INCLUDE' => 17,
-			"(" => 198,
-			'SWITCH' => 54,
-			'WRAPPER' => 55,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'FILTER' => 25,
-			'RETURN' => 64,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 193,
-			'DEFAULT' => 69,
-			"{" => 30,
-			"\${" => 37
-		},
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'term' => 58,
-			'loop' => 4,
-			'expr' => 199,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'atomdir' => 12,
-			'mdir' => 197,
-			'sterm' => 68,
-			'filter' => 29,
-			'ident' => 149,
-			'perl' => 31,
-			'setlist' => 70,
-			'switch' => 34,
-			'try' => 35,
-			'assign' => 19,
-			'directive' => 196,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 108
-		ACTIONS => {
-			'IN' => 201,
-			'ASSIGN' => 200
-		},
-		DEFAULT => -130
-	},
-	{#State 109
-		DEFAULT => -156,
-		GOTOS => {
-			'args' => 202
-		}
-	},
-	{#State 110
-		ACTIONS => {
-			";" => 203
-		}
-	},
-	{#State 111
-		ACTIONS => {
-			'ASSIGN' => -130
-		},
-		DEFAULT => -173
-	},
-	{#State 112
-		ACTIONS => {
-			'ASSIGN' => 204
-		}
-	},
-	{#State 113
-		DEFAULT => -159
-	},
-	{#State 114
-		ACTIONS => {
-			"\$" => 43,
-			'IDENT' => 205,
-			"\${" => 37
-		},
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'ident' => 175
-		}
-	},
-	{#State 115
-		ACTIONS => {
-			";" => 206
-		}
-	},
-	{#State 116
-		ACTIONS => {
-			'ASSIGN' => -161
-		},
-		DEFAULT => -169
-	},
-	{#State 117
-		DEFAULT => -176,
-		GOTOS => {
-			'quoted' => 207
-		}
-	},
-	{#State 118
-		DEFAULT => -158
-	},
-	{#State 119
-		ACTIONS => {
-			'DOT' => 104
-		},
-		DEFAULT => -110
-	},
-	{#State 120
-		ACTIONS => {
-			'ASSIGN' => 187
-		},
-		DEFAULT => -173
-	},
-	{#State 121
-		DEFAULT => -83
-	},
-	{#State 122
-		ACTIONS => {
-			'DOT' => 174
-		},
-		DEFAULT => -84
-	},
-	{#State 123
-		ACTIONS => {
-			";" => 208
-		}
-	},
-	{#State 124
-		DEFAULT => -85
-	},
-	{#State 125
-		ACTIONS => {
-			"}" => 209
-		}
-	},
-	{#State 126
-		ACTIONS => {
-			'ASSIGN' => 210
-		}
-	},
-	{#State 127
-		DEFAULT => -122
-	},
-	{#State 128
-		ACTIONS => {
-			"\$" => 43,
-			'COMMA' => 212,
-			'LITERAL' => 129,
-			'IDENT' => 2,
-			"\${" => 37
-		},
-		DEFAULT => -118,
-		GOTOS => {
-			'item' => 126,
-			'param' => 211
-		}
-	},
-	{#State 129
-		ACTIONS => {
-			'ASSIGN' => 213
-		}
-	},
-	{#State 130
-		DEFAULT => -73
-	},
-	{#State 131
-		DEFAULT => -4
-	},
-	{#State 132
-		ACTIONS => {
-			";" => 214
-		}
-	},
-	{#State 133
-		ACTIONS => {
-			"}" => 215
-		}
-	},
-	{#State 134
-		ACTIONS => {
-			"+" => 157,
-			'CAT' => 163,
-			'CMPOP' => 164,
-			'DIV' => 159,
-			'MOD' => 165,
-			"/" => 166,
-			'BINOP' => 161
-		},
-		DEFAULT => -142
-	},
-	{#State 135
-		DEFAULT => -156,
-		GOTOS => {
-			'args' => 216
-		}
-	},
-	{#State 136
-		DEFAULT => -76,
-		GOTOS => {
-			'@4-2' => 217
-		}
-	},
-	{#State 137
-		DEFAULT => -132
-	},
-	{#State 138
-		ACTIONS => {
-			'CMPOP' => 164,
-			"?" => 158,
-			";" => 218,
-			"+" => 157,
-			'MOD' => 165,
-			'DIV' => 159,
-			"/" => 166,
-			'AND' => 160,
-			'CAT' => 163,
-			'BINOP' => 161,
-			'OR' => 162
-		}
-	},
-	{#State 139
-		ACTIONS => {
-			"+" => 157,
-			'CAT' => 163,
-			'CMPOP' => 164,
-			"?" => 158,
-			'DIV' => 159,
-			'MOD' => 165,
-			"/" => 166,
-			'AND' => 160,
-			'BINOP' => 161,
-			'OR' => 162
-		},
-		DEFAULT => -29
-	},
-	{#State 140
-		ACTIONS => {
-			"+" => 157,
-			'CAT' => 163,
-			'CMPOP' => 164,
-			"?" => 158,
-			'DIV' => 159,
-			'MOD' => 165,
-			"/" => 166,
-			'AND' => 160,
-			'BINOP' => 161,
-			'OR' => 162
-		},
-		DEFAULT => -28
-	},
-	{#State 141
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 219,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 142
-		ACTIONS => {
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 108,
-			"\"" => 60,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'sterm' => 68,
-			'item' => 39,
-			'loopvar' => 220,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 109,
-			'lterm' => 56
-		}
-	},
-	{#State 143
-		ACTIONS => {
-			"\"" => 117,
-			"\$" => 114,
-			'LITERAL' => 116,
-			'FILENAME' => 83,
-			'IDENT' => 111,
-			'NUMBER' => 84,
-			"\${" => 37
-		},
-		GOTOS => {
-			'filepart' => 87,
-			'names' => 91,
-			'nameargs' => 118,
-			'filename' => 85,
-			'lvalue' => 112,
-			'lnameargs' => 221,
-			'item' => 113,
-			'name' => 82
-		}
-	},
-	{#State 144
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 222,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 145
-		ACTIONS => {
-			"\"" => 89,
-			"\$" => 86,
-			'LITERAL' => 88,
-			'FILENAME' => 83,
-			'IDENT' => 81,
-			'NUMBER' => 84
-		},
-		GOTOS => {
-			'filepart' => 87,
-			'names' => 91,
-			'nameargs' => 223,
-			'filename' => 85,
-			'name' => 82
-		}
-	},
-	{#State 146
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 224,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 147
-		DEFAULT => -41
-	},
-	{#State 148
-		DEFAULT => 0
-	},
-	{#State 149
-		ACTIONS => {
-			'DOT' => 104,
-			'ASSIGN' => 172
-		},
-		DEFAULT => -109
-	},
-	{#State 150
-		ACTIONS => {
-			")" => 225
-		}
-	},
-	{#State 151
-		ACTIONS => {
-			'CMPOP' => 164,
-			"?" => 158,
-			"+" => 157,
-			'MOD' => 165,
-			'DIV' => 159,
-			"/" => 166,
-			'AND' => 160,
-			'CAT' => 163,
-			'BINOP' => 161,
-			")" => 226,
-			'OR' => 162
-		}
-	},
-	{#State 152
-		ACTIONS => {
-			'CMPOP' => 164,
-			"?" => 158,
-			";" => 227,
-			"+" => 157,
-			'MOD' => 165,
-			'DIV' => 159,
-			"/" => 166,
-			'AND' => 160,
-			'CAT' => 163,
-			'BINOP' => 161,
-			'OR' => 162
-		}
-	},
-	{#State 153
-		ACTIONS => {
-			";" => 228
-		}
-	},
-	{#State 154
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 229,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 155
-		ACTIONS => {
-			"\"" => 234,
-			'TEXT' => 231,
-			";" => 233,
-			"\$" => 43,
-			'IDENT' => 2,
-			"\${" => 37
-		},
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'ident' => 230,
-			'quotable' => 232
-		}
-	},
-	{#State 156
-		DEFAULT => -34
-	},
-	{#State 157
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 235,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 158
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 236,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 159
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 237,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 160
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 238,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 161
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 239,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 162
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 240,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 163
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 241,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 164
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 242,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 165
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 243,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 166
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 244,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 167
-		DEFAULT => -32
-	},
-	{#State 168
-		ACTIONS => {
-			'CMPOP' => 164,
-			"?" => 158,
-			";" => 245,
-			"+" => 157,
-			'MOD' => 165,
-			'DIV' => 159,
-			"/" => 166,
-			'AND' => 160,
-			'CAT' => 163,
-			'BINOP' => 161,
-			'OR' => 162
-		}
-	},
-	{#State 169
-		ACTIONS => {
-			"\$" => 43,
-			'COMMA' => 171,
-			'LITERAL' => 75,
-			'IDENT' => 2,
-			"\${" => 37
-		},
-		DEFAULT => -31,
-		GOTOS => {
-			'item' => 39,
-			'assign' => 170,
-			'node' => 23,
-			'ident' => 74
-		}
-	},
-	{#State 170
-		DEFAULT => -147
-	},
-	{#State 171
-		DEFAULT => -148
-	},
-	{#State 172
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 246,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 173
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 247,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 174
-		ACTIONS => {
-			'FILENAME' => 83,
-			'IDENT' => 81,
-			'NUMBER' => 84
-		},
-		GOTOS => {
-			'filepart' => 248
-		}
-	},
-	{#State 175
-		ACTIONS => {
-			'DOT' => 104
-		},
-		DEFAULT => -156,
-		GOTOS => {
-			'args' => 249
-		}
-	},
-	{#State 176
-		ACTIONS => {
-			"\"" => 250,
-			'TEXT' => 231,
-			";" => 233,
-			"\$" => 43,
-			'IDENT' => 2,
-			"\${" => 37
-		},
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'ident' => 230,
-			'quotable' => 232
-		}
-	},
-	{#State 177
-		ACTIONS => {
-			"\"" => 89,
-			'LITERAL' => 88,
-			'FILENAME' => 83,
-			'IDENT' => 81,
-			'NUMBER' => 84
-		},
-		GOTOS => {
-			'filepart' => 87,
-			'filename' => 85,
-			'name' => 251
-		}
-	},
-	{#State 178
-		DEFAULT => -156,
-		GOTOS => {
-			'args' => 252
-		}
-	},
-	{#State 179
-		ACTIONS => {
-			"{" => 30,
-			'COMMA' => 258,
-			'LITERAL' => 256,
-			'IDENT' => 2,
-			"\"" => 60,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		DEFAULT => -163,
-		GOTOS => {
-			'sterm' => 68,
-			'item' => 254,
-			'param' => 255,
-			'node' => 23,
-			'ident' => 253,
-			'term' => 257,
-			'lterm' => 56
-		}
-	},
-	{#State 180
-		DEFAULT => -105
-	},
-	{#State 181
-		DEFAULT => -114
-	},
-	{#State 182
-		DEFAULT => -115
-	},
-	{#State 183
-		DEFAULT => -106
-	},
-	{#State 184
-		ACTIONS => {
-			"\"" => 60,
-			"\$" => 43,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			'REF' => 27,
-			'NUMBER' => 26,
-			"\${" => 37
-		},
-		GOTOS => {
-			'sterm' => 259,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77
-		}
-	},
-	{#State 185
-		ACTIONS => {
-			'FINAL' => 260,
-			'CATCH' => 262
-		},
-		DEFAULT => -72,
-		GOTOS => {
-			'final' => 261
-		}
-	},
-	{#State 186
-		ACTIONS => {
-			'TEXT' => 263
-		}
-	},
-	{#State 187
-		ACTIONS => {
-			"\"" => 266,
-			'LITERAL' => 265,
-			'NUMBER' => 264
-		}
-	},
-	{#State 188
-		DEFAULT => -97
-	},
-	{#State 189
-		DEFAULT => -98
-	},
-	{#State 190
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'template' => 267,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 72,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 191
-		DEFAULT => -125
-	},
-	{#State 192
-		DEFAULT => -126
-	},
-	{#State 193
-		ACTIONS => {
-			";" => 268
-		}
-	},
-	{#State 194
-		DEFAULT => -89
-	},
-	{#State 195
-		ACTIONS => {
-			";" => -150,
-			"+" => 157,
-			'LITERAL' => -150,
-			'IDENT' => -150,
-			'CAT' => 163,
-			"\$" => -150,
-			'CMPOP' => 164,
-			"?" => 158,
-			'DIV' => 159,
-			'MOD' => 165,
-			'COMMA' => -150,
-			"/" => 166,
-			'AND' => 160,
-			'BINOP' => 161,
-			'OR' => 162,
-			"\${" => -150
-		},
-		DEFAULT => -26
-	},
-	{#State 196
-		DEFAULT => -92
-	},
-	{#State 197
-		DEFAULT => -91
-	},
-	{#State 198
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 57,
-			'IDENT' => 269,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'sterm' => 68,
-			'item' => 39,
-			'margs' => 270,
-			'node' => 23,
-			'ident' => 149,
-			'term' => 58,
-			'expr' => 151,
-			'assign' => 150,
-			'lterm' => 56
-		}
-	},
-	{#State 199
-		ACTIONS => {
-			"+" => 157,
-			'CAT' => 163,
-			'CMPOP' => 164,
-			"?" => 158,
-			'DIV' => 159,
-			'MOD' => 165,
-			"/" => 166,
-			'AND' => 160,
-			'BINOP' => 161,
-			'OR' => 162
-		},
-		DEFAULT => -26
-	},
-	{#State 200
-		ACTIONS => {
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 271,
-			'lterm' => 56
-		}
-	},
-	{#State 201
-		ACTIONS => {
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 272,
-			'lterm' => 56
-		}
-	},
-	{#State 202
-		ACTIONS => {
-			"{" => 30,
-			'COMMA' => 258,
-			'LITERAL' => 256,
-			'IDENT' => 2,
-			"\"" => 60,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		DEFAULT => -64,
-		GOTOS => {
-			'sterm' => 68,
-			'item' => 254,
-			'param' => 255,
-			'node' => 23,
-			'ident' => 253,
-			'term' => 257,
-			'lterm' => 56
-		}
-	},
-	{#State 203
-		DEFAULT => -56,
-		GOTOS => {
-			'@1-3' => 273
-		}
-	},
-	{#State 204
-		ACTIONS => {
-			"\"" => 89,
-			"\$" => 86,
-			'LITERAL' => 88,
-			'FILENAME' => 83,
-			'IDENT' => 81,
-			'NUMBER' => 84
-		},
-		GOTOS => {
-			'filepart' => 87,
-			'names' => 91,
-			'nameargs' => 274,
-			'filename' => 85,
-			'name' => 82
-		}
-	},
-	{#State 205
-		ACTIONS => {
-			'ASSIGN' => -132
-		},
-		DEFAULT => -130
-	},
-	{#State 206
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 275,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 207
-		ACTIONS => {
-			"\"" => 276,
-			'TEXT' => 231,
-			";" => 233,
-			"\$" => 43,
-			'IDENT' => 2,
-			"\${" => 37
-		},
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'ident' => 230,
-			'quotable' => 232
-		}
-	},
-	{#State 208
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 277,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 209
-		DEFAULT => -108
-	},
-	{#State 210
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 278,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 211
-		DEFAULT => -120
-	},
-	{#State 212
-		DEFAULT => -121
-	},
-	{#State 213
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 279,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 214
-		DEFAULT => -74,
-		GOTOS => {
-			'@3-3' => 280
-		}
-	},
-	{#State 215
-		DEFAULT => -131
-	},
-	{#State 216
-		ACTIONS => {
-			"{" => 30,
-			'COMMA' => 258,
-			'LITERAL' => 256,
-			'IDENT' => 2,
-			"\"" => 60,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			")" => 281,
-			"\${" => 37
-		},
-		GOTOS => {
-			'sterm' => 68,
-			'item' => 254,
-			'param' => 255,
-			'node' => 23,
-			'ident' => 253,
-			'term' => 257,
-			'lterm' => 56
-		}
-	},
-	{#State 217
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 282,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 218
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 283,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 219
-		ACTIONS => {
-			'CMPOP' => 164,
-			"?" => 158,
-			"+" => 157,
-			'MOD' => 165,
-			'DIV' => 159,
-			"/" => 166,
-			'AND' => 160,
-			'CAT' => 163,
-			'BINOP' => 161,
-			'OR' => 162
-		},
-		DEFAULT => -47
-	},
-	{#State 220
-		DEFAULT => -58
-	},
-	{#State 221
-		DEFAULT => -81
-	},
-	{#State 222
-		ACTIONS => {
-			'CMPOP' => 164,
-			"?" => 158,
-			"+" => 157,
-			'MOD' => 165,
-			'DIV' => 159,
-			"/" => 166,
-			'AND' => 160,
-			'CAT' => 163,
-			'BINOP' => 161,
-			'OR' => 162
-		},
-		DEFAULT => -45
-	},
-	{#State 223
-		DEFAULT => -66
-	},
-	{#State 224
-		ACTIONS => {
-			'CMPOP' => 164,
-			"?" => 158,
-			"+" => 157,
-			'MOD' => 165,
-			'DIV' => 159,
-			"/" => 166,
-			'AND' => 160,
-			'CAT' => 163,
-			'BINOP' => 161,
-			'OR' => 162
-		},
-		DEFAULT => -61
-	},
-	{#State 225
-		DEFAULT => -144
-	},
-	{#State 226
-		DEFAULT => -145
-	},
-	{#State 227
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 284,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 228
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 285,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 229
-		ACTIONS => {
-			"+" => 157,
-			'CAT' => 163,
-			'CMPOP' => 164,
-			"?" => 158,
-			'DIV' => 159,
-			'MOD' => 165,
-			"/" => 166,
-			'AND' => 160,
-			'BINOP' => 161,
-			'OR' => 162
-		},
-		DEFAULT => -151
-	},
-	{#State 230
-		ACTIONS => {
-			'DOT' => 104
-		},
-		DEFAULT => -177
-	},
-	{#State 231
-		DEFAULT => -178
-	},
-	{#State 232
-		DEFAULT => -175
-	},
-	{#State 233
-		DEFAULT => -179
-	},
-	{#State 234
-		DEFAULT => -111
-	},
-	{#State 235
-		ACTIONS => {
-			'DIV' => 159,
-			'MOD' => 165,
-			"/" => 166
-		},
-		DEFAULT => -135
-	},
-	{#State 236
-		ACTIONS => {
-			":" => 286,
-			'CMPOP' => 164,
-			"?" => 158,
-			"+" => 157,
-			'MOD' => 165,
-			'DIV' => 159,
-			"/" => 166,
-			'AND' => 160,
-			'CAT' => 163,
-			'BINOP' => 161,
-			'OR' => 162
-		}
-	},
-	{#State 237
-		ACTIONS => {
-			'MOD' => 165
-		},
-		DEFAULT => -136
-	},
-	{#State 238
-		ACTIONS => {
-			"+" => 157,
-			'CAT' => 163,
-			'CMPOP' => 164,
-			'DIV' => 159,
-			'MOD' => 165,
-			"/" => 166,
-			'BINOP' => 161
-		},
-		DEFAULT => -140
-	},
-	{#State 239
-		ACTIONS => {
-			"+" => 157,
-			'DIV' => 159,
-			'MOD' => 165,
-			"/" => 166
-		},
-		DEFAULT => -133
-	},
-	{#State 240
-		ACTIONS => {
-			"+" => 157,
-			'CAT' => 163,
-			'CMPOP' => 164,
-			'DIV' => 159,
-			'MOD' => 165,
-			"/" => 166,
-			'BINOP' => 161
-		},
-		DEFAULT => -141
-	},
-	{#State 241
-		ACTIONS => {
-			"+" => 157,
-			'CMPOP' => 164,
-			'DIV' => 159,
-			'MOD' => 165,
-			"/" => 166,
-			'BINOP' => 161
-		},
-		DEFAULT => -139
-	},
-	{#State 242
-		ACTIONS => {
-			"+" => 157,
-			'DIV' => 159,
-			'MOD' => 165,
-			"/" => 166,
-			'BINOP' => 161
-		},
-		DEFAULT => -138
-	},
-	{#State 243
-		DEFAULT => -137
-	},
-	{#State 244
-		ACTIONS => {
-			'DIV' => 159,
-			'MOD' => 165
-		},
-		DEFAULT => -134
-	},
-	{#State 245
-		DEFAULT => -59,
-		GOTOS => {
-			'@2-3' => 287
-		}
-	},
-	{#State 246
-		ACTIONS => {
-			"+" => 157,
-			'CAT' => 163,
-			'CMPOP' => 164,
-			"?" => 158,
-			'DIV' => 159,
-			'MOD' => 165,
-			"/" => 166,
-			'AND' => 160,
-			'BINOP' => 161,
-			'OR' => 162
-		},
-		DEFAULT => -150
-	},
-	{#State 247
-		ACTIONS => {
-			'ELSIF' => 290,
-			'ELSE' => 288
-		},
-		DEFAULT => -50,
-		GOTOS => {
-			'else' => 289
-		}
-	},
-	{#State 248
-		DEFAULT => -170
-	},
-	{#State 249
-		ACTIONS => {
-			"{" => 30,
-			'COMMA' => 258,
-			'LITERAL' => 256,
-			'IDENT' => 2,
-			"\"" => 60,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		DEFAULT => -162,
-		GOTOS => {
-			'sterm' => 68,
-			'item' => 254,
-			'param' => 255,
-			'node' => 23,
-			'ident' => 253,
-			'term' => 257,
-			'lterm' => 56
-		}
-	},
-	{#State 250
-		DEFAULT => -167
-	},
-	{#State 251
-		DEFAULT => -165
-	},
-	{#State 252
-		ACTIONS => {
-			"{" => 30,
-			'COMMA' => 258,
-			'LITERAL' => 256,
-			'IDENT' => 2,
-			"\"" => 60,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			")" => 291,
-			"\${" => 37
-		},
-		GOTOS => {
-			'sterm' => 68,
-			'item' => 254,
-			'param' => 255,
-			'node' => 23,
-			'ident' => 253,
-			'term' => 257,
-			'lterm' => 56
-		}
-	},
-	{#State 253
-		ACTIONS => {
-			'DOT' => 104,
-			'ASSIGN' => 292
-		},
-		DEFAULT => -109
-	},
-	{#State 254
-		ACTIONS => {
-			"(" => 135,
-			'ASSIGN' => 210
-		},
-		DEFAULT => -128
-	},
-	{#State 255
-		DEFAULT => -153
-	},
-	{#State 256
-		ACTIONS => {
-			'ASSIGN' => 213
-		},
-		DEFAULT => -112
-	},
-	{#State 257
-		DEFAULT => -152
-	},
-	{#State 258
-		DEFAULT => -155
-	},
-	{#State 259
-		DEFAULT => -117
-	},
-	{#State 260
-		ACTIONS => {
-			";" => 293
-		}
-	},
-	{#State 261
-		ACTIONS => {
-			'END' => 294
-		}
-	},
-	{#State 262
-		ACTIONS => {
-			";" => 296,
-			'DEFAULT' => 297,
-			'FILENAME' => 83,
-			'IDENT' => 81,
-			'NUMBER' => 84
-		},
-		GOTOS => {
-			'filepart' => 87,
-			'filename' => 295
-		}
-	},
-	{#State 263
-		ACTIONS => {
-			'END' => 298
-		}
-	},
-	{#State 264
-		DEFAULT => -102
-	},
-	{#State 265
-		DEFAULT => -100
-	},
-	{#State 266
-		ACTIONS => {
-			'TEXT' => 299
-		}
-	},
-	{#State 267
-		ACTIONS => {
-			'END' => 300
-		}
-	},
-	{#State 268
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 301,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 269
-		ACTIONS => {
-			'COMMA' => -96,
-			'IDENT' => -96,
-			")" => -96
-		},
-		DEFAULT => -130
-	},
-	{#State 270
-		ACTIONS => {
-			'COMMA' => 304,
-			'IDENT' => 302,
-			")" => 303
-		}
-	},
-	{#State 271
-		DEFAULT => -156,
-		GOTOS => {
-			'args' => 305
-		}
-	},
-	{#State 272
-		DEFAULT => -156,
-		GOTOS => {
-			'args' => 306
-		}
-	},
-	{#State 273
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 307,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 274
-		DEFAULT => -157
-	},
-	{#State 275
-		ACTIONS => {
-			'END' => 308
-		}
-	},
-	{#State 276
-		ACTIONS => {
-			'ASSIGN' => -160
-		},
-		DEFAULT => -167
-	},
-	{#State 277
-		ACTIONS => {
-			'END' => 309
-		}
-	},
-	{#State 278
-		ACTIONS => {
-			"+" => 157,
-			'CAT' => 163,
-			'CMPOP' => 164,
-			"?" => 158,
-			'DIV' => 159,
-			'MOD' => 165,
-			"/" => 166,
-			'AND' => 160,
-			'BINOP' => 161,
-			'OR' => 162
-		},
-		DEFAULT => -124
-	},
-	{#State 279
-		ACTIONS => {
-			"+" => 157,
-			'CAT' => 163,
-			'CMPOP' => 164,
-			"?" => 158,
-			'DIV' => 159,
-			'MOD' => 165,
-			"/" => 166,
-			'AND' => 160,
-			'BINOP' => 161,
-			'OR' => 162
-		},
-		DEFAULT => -123
-	},
-	{#State 280
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 310,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 281
-		DEFAULT => -129
-	},
-	{#State 282
-		ACTIONS => {
-			'END' => 311
-		}
-	},
-	{#State 283
-		ACTIONS => {
-			'ELSIF' => 290,
-			'ELSE' => 288
-		},
-		DEFAULT => -50,
-		GOTOS => {
-			'else' => 312
-		}
-	},
-	{#State 284
-		ACTIONS => {
-			'CASE' => 313
-		},
-		DEFAULT => -55,
-		GOTOS => {
-			'case' => 314
-		}
-	},
-	{#State 285
-		ACTIONS => {
-			'END' => 315
-		}
-	},
-	{#State 286
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 316,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 287
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 317,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 288
-		ACTIONS => {
-			";" => 318
-		}
-	},
-	{#State 289
-		ACTIONS => {
-			'END' => 319
-		}
-	},
-	{#State 290
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 320,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 291
-		DEFAULT => -164
-	},
-	{#State 292
-		ACTIONS => {
-			'NOT' => 38,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"(" => 53,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'expr' => 321,
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 58,
-			'lterm' => 56
-		}
-	},
-	{#State 293
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 322,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 294
-		DEFAULT => -67
-	},
-	{#State 295
-		ACTIONS => {
-			'DOT' => 174,
-			";" => 323
-		}
-	},
-	{#State 296
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 324,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 297
-		ACTIONS => {
-			";" => 325
-		}
-	},
-	{#State 298
-		DEFAULT => -79
-	},
-	{#State 299
-		ACTIONS => {
-			"\"" => 326
-		}
-	},
-	{#State 300
-		DEFAULT => -82
-	},
-	{#State 301
-		ACTIONS => {
-			'END' => 327
-		}
-	},
-	{#State 302
-		DEFAULT => -94
-	},
-	{#State 303
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'WRAPPER' => 55,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'FILTER' => 25,
-			'RETURN' => 64,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 193,
-			'DEFAULT' => 69,
-			"{" => 30,
-			"\${" => 37
-		},
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'term' => 58,
-			'loop' => 4,
-			'expr' => 199,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'atomdir' => 12,
-			'mdir' => 328,
-			'sterm' => 68,
-			'filter' => 29,
-			'ident' => 149,
-			'perl' => 31,
-			'setlist' => 70,
-			'switch' => 34,
-			'try' => 35,
-			'assign' => 19,
-			'directive' => 196,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 304
-		DEFAULT => -95
-	},
-	{#State 305
-		ACTIONS => {
-			"{" => 30,
-			'COMMA' => 258,
-			'LITERAL' => 256,
-			'IDENT' => 2,
-			"\"" => 60,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		DEFAULT => -62,
-		GOTOS => {
-			'sterm' => 68,
-			'item' => 254,
-			'param' => 255,
-			'node' => 23,
-			'ident' => 253,
-			'term' => 257,
-			'lterm' => 56
-		}
-	},
-	{#State 306
-		ACTIONS => {
-			"{" => 30,
-			'COMMA' => 258,
-			'LITERAL' => 256,
-			'IDENT' => 2,
-			"\"" => 60,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		DEFAULT => -63,
-		GOTOS => {
-			'sterm' => 68,
-			'item' => 254,
-			'param' => 255,
-			'node' => 23,
-			'ident' => 253,
-			'term' => 257,
-			'lterm' => 56
-		}
-	},
-	{#State 307
-		ACTIONS => {
-			'END' => 329
-		}
-	},
-	{#State 308
-		DEFAULT => -80
-	},
-	{#State 309
-		DEFAULT => -88
-	},
-	{#State 310
-		ACTIONS => {
-			'END' => 330
-		}
-	},
-	{#State 311
-		DEFAULT => -77
-	},
-	{#State 312
-		ACTIONS => {
-			'END' => 331
-		}
-	},
-	{#State 313
-		ACTIONS => {
-			";" => 332,
-			'DEFAULT' => 334,
-			"{" => 30,
-			'LITERAL' => 78,
-			'IDENT' => 2,
-			"\"" => 60,
-			"\$" => 43,
-			"[" => 9,
-			'NUMBER' => 26,
-			'REF' => 27,
-			"\${" => 37
-		},
-		GOTOS => {
-			'sterm' => 68,
-			'item' => 39,
-			'node' => 23,
-			'ident' => 77,
-			'term' => 333,
-			'lterm' => 56
-		}
-	},
-	{#State 314
-		ACTIONS => {
-			'END' => 335
-		}
-	},
-	{#State 315
-		DEFAULT => -65
-	},
-	{#State 316
-		ACTIONS => {
-			"+" => 157,
-			'CAT' => 163,
-			'CMPOP' => 164,
-			"?" => 158,
-			'DIV' => 159,
-			'MOD' => 165,
-			"/" => 166,
-			'AND' => 160,
-			'BINOP' => 161,
-			'OR' => 162
-		},
-		DEFAULT => -143
-	},
-	{#State 317
-		ACTIONS => {
-			'END' => 336
-		}
-	},
-	{#State 318
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 337,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 319
-		DEFAULT => -46
-	},
-	{#State 320
-		ACTIONS => {
-			'CMPOP' => 164,
-			"?" => 158,
-			";" => 338,
-			"+" => 157,
-			'MOD' => 165,
-			'DIV' => 159,
-			"/" => 166,
-			'AND' => 160,
-			'CAT' => 163,
-			'BINOP' => 161,
-			'OR' => 162
-		}
-	},
-	{#State 321
-		ACTIONS => {
-			"+" => 157,
-			'CAT' => 163,
-			'CMPOP' => 164,
-			"?" => 158,
-			'DIV' => 159,
-			'MOD' => 165,
-			"/" => 166,
-			'AND' => 160,
-			'BINOP' => 161,
-			'OR' => 162
-		},
-		DEFAULT => -154
-	},
-	{#State 322
-		DEFAULT => -71
-	},
-	{#State 323
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 339,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 324
-		ACTIONS => {
-			'FINAL' => 260,
-			'CATCH' => 262
-		},
-		DEFAULT => -72,
-		GOTOS => {
-			'final' => 340
-		}
-	},
-	{#State 325
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 341,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 326
-		DEFAULT => -101
-	},
-	{#State 327
-		DEFAULT => -93
-	},
-	{#State 328
-		DEFAULT => -90
-	},
-	{#State 329
-		DEFAULT => -57
-	},
-	{#State 330
-		DEFAULT => -75
-	},
-	{#State 331
-		DEFAULT => -44
-	},
-	{#State 332
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 342,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 333
-		ACTIONS => {
-			";" => 343
-		}
-	},
-	{#State 334
-		ACTIONS => {
-			";" => 344
-		}
-	},
-	{#State 335
-		DEFAULT => -51
-	},
-	{#State 336
-		DEFAULT => -60
-	},
-	{#State 337
-		DEFAULT => -49
-	},
-	{#State 338
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 345,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 339
-		ACTIONS => {
-			'FINAL' => 260,
-			'CATCH' => 262
-		},
-		DEFAULT => -72,
-		GOTOS => {
-			'final' => 346
-		}
-	},
-	{#State 340
-		DEFAULT => -70
-	},
-	{#State 341
-		ACTIONS => {
-			'FINAL' => 260,
-			'CATCH' => 262
-		},
-		DEFAULT => -72,
-		GOTOS => {
-			'final' => 347
-		}
-	},
-	{#State 342
-		DEFAULT => -54
-	},
-	{#State 343
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 348,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 344
-		ACTIONS => {
-			'SET' => 1,
-			'PERL' => 40,
-			'NOT' => 38,
-			'IDENT' => 2,
-			'CLEAR' => 41,
-			'UNLESS' => 3,
-			'IF' => 44,
-			"\$" => 43,
-			'STOP' => 6,
-			'CALL' => 45,
-			'THROW' => 8,
-			'GET' => 47,
-			"[" => 9,
-			'TRY' => 10,
-			'LAST' => 49,
-			'DEBUG' => 51,
-			'RAWPERL' => 13,
-			'META' => 15,
-			'INCLUDE' => 17,
-			"(" => 53,
-			'SWITCH' => 54,
-			'MACRO' => 18,
-			'WRAPPER' => 55,
-			";" => -18,
-			'FOR' => 21,
-			'NEXT' => 22,
-			'LITERAL' => 57,
-			'TEXT' => 24,
-			"\"" => 60,
-			'PROCESS' => 61,
-			'RETURN' => 64,
-			'FILTER' => 25,
-			'INSERT' => 65,
-			'NUMBER' => 26,
-			'REF' => 27,
-			'WHILE' => 67,
-			'BLOCK' => 28,
-			'DEFAULT' => 69,
-			"{" => 30,
-			'USE' => 32,
-			'VIEW' => 36,
-			"\${" => 37
-		},
-		DEFAULT => -3,
-		GOTOS => {
-			'item' => 39,
-			'node' => 23,
-			'rawperl' => 59,
-			'term' => 58,
-			'loop' => 4,
-			'use' => 63,
-			'expr' => 62,
-			'capture' => 42,
-			'statement' => 5,
-			'view' => 7,
-			'wrapper' => 46,
-			'atomexpr' => 48,
-			'chunk' => 11,
-			'defblock' => 66,
-			'atomdir' => 12,
-			'anonblock' => 50,
-			'sterm' => 68,
-			'defblockname' => 14,
-			'filter' => 29,
-			'ident' => 16,
-			'perl' => 31,
-			'setlist' => 70,
-			'chunks' => 33,
-			'try' => 35,
-			'switch' => 34,
-			'assign' => 19,
-			'block' => 349,
-			'directive' => 71,
-			'macro' => 20,
-			'condition' => 73,
-			'lterm' => 56
-		}
-	},
-	{#State 345
-		ACTIONS => {
-			'ELSIF' => 290,
-			'ELSE' => 288
-		},
-		DEFAULT => -50,
-		GOTOS => {
-			'else' => 350
-		}
-	},
-	{#State 346
-		DEFAULT => -68
-	},
-	{#State 347
-		DEFAULT => -69
-	},
-	{#State 348
-		ACTIONS => {
-			'CASE' => 313
-		},
-		DEFAULT => -55,
-		GOTOS => {
-			'case' => 351
-		}
-	},
-	{#State 349
-		DEFAULT => -53
-	},
-	{#State 350
-		DEFAULT => -48
-	},
-	{#State 351
-		DEFAULT => -52
-	}
-]; 
-
-
-#========================================================================
-# Rules
-#========================================================================
-
-$RULES = [
-	[#Rule 0
-		 '$start', 2, undef
-	],
-	[#Rule 1
-		 'template', 1,
-sub
-#line 64 "Parser.yp"
-{ $factory->template($_[1])           }
-	],
-	[#Rule 2
-		 'block', 1,
-sub
-#line 67 "Parser.yp"
-{ $factory->block($_[1])              }
-	],
-	[#Rule 3
-		 'block', 0,
-sub
-#line 68 "Parser.yp"
-{ $factory->block()                   }
-	],
-	[#Rule 4
-		 'chunks', 2,
-sub
-#line 71 "Parser.yp"
-{ push(@{$_[1]}, $_[2]) 
-					if defined $_[2]; $_[1]           }
-	],
-	[#Rule 5
-		 'chunks', 1,
-sub
-#line 73 "Parser.yp"
-{ defined $_[1] ? [ $_[1] ] : [ ]     }
-	],
-	[#Rule 6
-		 'chunk', 1,
-sub
-#line 76 "Parser.yp"
-{ $factory->textblock($_[1])          }
-	],
-	[#Rule 7
-		 'chunk', 2,
-sub
-#line 77 "Parser.yp"
-{ return '' unless $_[1];
-                           $_[0]->location() . $_[1];
-                         }
-	],
-	[#Rule 8
-		 'statement', 1, undef
-	],
-	[#Rule 9
-		 'statement', 1, undef
-	],
-	[#Rule 10
-		 'statement', 1, undef
-	],
-	[#Rule 11
-		 'statement', 1, undef
-	],
-	[#Rule 12
-		 'statement', 1, undef
-	],
-	[#Rule 13
-		 'statement', 1, undef
-	],
-	[#Rule 14
-		 'statement', 1, undef
-	],
-	[#Rule 15
-		 'statement', 1, undef
-	],
-	[#Rule 16
-		 'statement', 1,
-sub
-#line 90 "Parser.yp"
-{ $factory->get($_[1])                }
-	],
-	[#Rule 17
-		 'statement', 2,
-sub
-#line 91 "Parser.yp"
-{ $_[0]->add_metadata($_[2]);         }
-	],
-	[#Rule 18
-		 'statement', 0, undef
-	],
-	[#Rule 19
-		 'directive', 1,
-sub
-#line 95 "Parser.yp"
-{ $factory->set($_[1])                }
-	],
-	[#Rule 20
-		 'directive', 1, undef
-	],
-	[#Rule 21
-		 'directive', 1, undef
-	],
-	[#Rule 22
-		 'directive', 1, undef
-	],
-	[#Rule 23
-		 'directive', 1, undef
-	],
-	[#Rule 24
-		 'directive', 1, undef
-	],
-	[#Rule 25
-		 'directive', 1, undef
-	],
-	[#Rule 26
-		 'atomexpr', 1,
-sub
-#line 109 "Parser.yp"
-{ $factory->get($_[1])                }
-	],
-	[#Rule 27
-		 'atomexpr', 1, undef
-	],
-	[#Rule 28
-		 'atomdir', 2,
-sub
-#line 113 "Parser.yp"
-{ $factory->get($_[2])                }
-	],
-	[#Rule 29
-		 'atomdir', 2,
-sub
-#line 114 "Parser.yp"
-{ $factory->call($_[2])               }
-	],
-	[#Rule 30
-		 'atomdir', 2,
-sub
-#line 115 "Parser.yp"
-{ $factory->set($_[2])                }
-	],
-	[#Rule 31
-		 'atomdir', 2,
-sub
-#line 116 "Parser.yp"
-{ $factory->default($_[2])            }
-	],
-	[#Rule 32
-		 'atomdir', 2,
-sub
-#line 117 "Parser.yp"
-{ $factory->insert($_[2])             }
-	],
-	[#Rule 33
-		 'atomdir', 2,
-sub
-#line 118 "Parser.yp"
-{ $factory->include($_[2])            }
-	],
-	[#Rule 34
-		 'atomdir', 2,
-sub
-#line 119 "Parser.yp"
-{ $factory->process($_[2])            }
-	],
-	[#Rule 35
-		 'atomdir', 2,
-sub
-#line 120 "Parser.yp"
-{ $factory->throw($_[2])              }
-	],
-	[#Rule 36
-		 'atomdir', 1,
-sub
-#line 121 "Parser.yp"
-{ $factory->return()                  }
-	],
-	[#Rule 37
-		 'atomdir', 1,
-sub
-#line 122 "Parser.yp"
-{ $factory->stop()                    }
-	],
-	[#Rule 38
-		 'atomdir', 1,
-sub
-#line 123 "Parser.yp"
-{ "\$output = '';";                   }
-	],
-	[#Rule 39
-		 'atomdir', 1,
-sub
-#line 124 "Parser.yp"
-{ $_[0]->{ INFOR } || $_[0]->{ INWHILE }
-                                        ? 'last LOOP;'
-                                        : 'last;'                         }
-	],
-	[#Rule 40
-		 'atomdir', 1,
-sub
-#line 127 "Parser.yp"
-{ $_[0]->{ INFOR }
-					? $factory->next()
-				        : ($_[0]->{ INWHILE }
-                                           ? 'next LOOP;'
-                                           : 'next;')                     }
-	],
-	[#Rule 41
-		 'atomdir', 2,
-sub
-#line 132 "Parser.yp"
-{ if ($_[2]->[0]->[0] =~ /^'(on|off)'$/) {
-				          $_[0]->{ DEBUG_DIRS } = ($1 eq 'on');
-					  $factory->debug($_[2]);
-				      }
-				      else {
-					  $_[0]->{ DEBUG_DIRS } ? $factory->debug($_[2]) : '';
-				      }
-				    }
-	],
-	[#Rule 42
-		 'atomdir', 1, undef
-	],
-	[#Rule 43
-		 'atomdir', 1, undef
-	],
-	[#Rule 44
-		 'condition', 6,
-sub
-#line 145 "Parser.yp"
-{ $factory->if(@_[2, 4, 5])           }
-	],
-	[#Rule 45
-		 'condition', 3,
-sub
-#line 146 "Parser.yp"
-{ $factory->if(@_[3, 1])              }
-	],
-	[#Rule 46
-		 'condition', 6,
-sub
-#line 148 "Parser.yp"
-{ $factory->if("!($_[2])", @_[4, 5])  }
-	],
-	[#Rule 47
-		 'condition', 3,
-sub
-#line 149 "Parser.yp"
-{ $factory->if("!($_[3])", $_[1])     }
-	],
-	[#Rule 48
-		 'else', 5,
-sub
-#line 153 "Parser.yp"
-{ unshift(@{$_[5]}, [ @_[2, 4] ]);
-				      $_[5];                              }
-	],
-	[#Rule 49
-		 'else', 3,
-sub
-#line 155 "Parser.yp"
-{ [ $_[3] ]                           }
-	],
-	[#Rule 50
-		 'else', 0,
-sub
-#line 156 "Parser.yp"
-{ [ undef ]                           }
-	],
-	[#Rule 51
-		 'switch', 6,
-sub
-#line 160 "Parser.yp"
-{ $factory->switch(@_[2, 5])          }
-	],
-	[#Rule 52
-		 'case', 5,
-sub
-#line 164 "Parser.yp"
-{ unshift(@{$_[5]}, [ @_[2, 4] ]); 
-				      $_[5];                              }
-	],
-	[#Rule 53
-		 'case', 4,
-sub
-#line 166 "Parser.yp"
-{ [ $_[4] ]                           }
-	],
-	[#Rule 54
-		 'case', 3,
-sub
-#line 167 "Parser.yp"
-{ [ $_[3] ]                           }
-	],
-	[#Rule 55
-		 'case', 0,
-sub
-#line 168 "Parser.yp"
-{ [ undef ]                           }
-	],
-	[#Rule 56
-		 '@1-3', 0,
-sub
-#line 171 "Parser.yp"
-{ $_[0]->{ INFOR }++                  }
-	],
-	[#Rule 57
-		 'loop', 6,
-sub
-#line 172 "Parser.yp"
-{ $_[0]->{ INFOR }--;
-				      $factory->foreach(@{$_[2]}, $_[5])  }
-	],
-	[#Rule 58
-		 'loop', 3,
-sub
-#line 176 "Parser.yp"
-{ $factory->foreach(@{$_[3]}, $_[1])  }
-	],
-	[#Rule 59
-		 '@2-3', 0,
-sub
-#line 177 "Parser.yp"
-{ $_[0]->{ INWHILE }++                }
-	],
-	[#Rule 60
-		 'loop', 6,
-sub
-#line 178 "Parser.yp"
-{ $_[0]->{ INWHILE }--;
-                                      $factory->while(@_[2, 5])           }
-	],
-	[#Rule 61
-		 'loop', 3,
-sub
-#line 180 "Parser.yp"
-{ $factory->while(@_[3, 1])           }
-	],
-	[#Rule 62
-		 'loopvar', 4,
-sub
-#line 183 "Parser.yp"
-{ [ @_[1, 3, 4] ]                     }
-	],
-	[#Rule 63
-		 'loopvar', 4,
-sub
-#line 184 "Parser.yp"
-{ [ @_[1, 3, 4] ]                     }
-	],
-	[#Rule 64
-		 'loopvar', 2,
-sub
-#line 185 "Parser.yp"
-{ [ 0, @_[1, 2] ]                     }
-	],
-	[#Rule 65
-		 'wrapper', 5,
-sub
-#line 189 "Parser.yp"
-{ $factory->wrapper(@_[2, 4])         }
-	],
-	[#Rule 66
-		 'wrapper', 3,
-sub
-#line 191 "Parser.yp"
-{ $factory->wrapper(@_[3, 1])         }
-	],
-	[#Rule 67
-		 'try', 5,
-sub
-#line 195 "Parser.yp"
-{ $factory->try(@_[3, 4])             }
-	],
-	[#Rule 68
-		 'final', 5,
-sub
-#line 199 "Parser.yp"
-{ unshift(@{$_[5]}, [ @_[2,4] ]);
-				      $_[5];                              }
-	],
-	[#Rule 69
-		 'final', 5,
-sub
-#line 202 "Parser.yp"
-{ unshift(@{$_[5]}, [ undef, $_[4] ]);
-				      $_[5];                              }
-	],
-	[#Rule 70
-		 'final', 4,
-sub
-#line 205 "Parser.yp"
-{ unshift(@{$_[4]}, [ undef, $_[3] ]);
-				      $_[4];                              }
-	],
-	[#Rule 71
-		 'final', 3,
-sub
-#line 207 "Parser.yp"
-{ [ $_[3] ]                           }
-	],
-	[#Rule 72
-		 'final', 0,
-sub
-#line 208 "Parser.yp"
-{ [ 0 ] }
-	],
-	[#Rule 73
-		 'use', 2,
-sub
-#line 211 "Parser.yp"
-{ $factory->use($_[2])                }
-	],
-	[#Rule 74
-		 '@3-3', 0,
-sub
-#line 214 "Parser.yp"
-{ $_[0]->push_defblock();		  }
-	],
-	[#Rule 75
-		 'view', 6,
-sub
-#line 215 "Parser.yp"
-{ $factory->view(@_[2,5], 
-						     $_[0]->pop_defblock) }
-	],
-	[#Rule 76
-		 '@4-2', 0,
-sub
-#line 219 "Parser.yp"
-{ ${$_[0]->{ INPERL }}++;             }
-	],
-	[#Rule 77
-		 'perl', 5,
-sub
-#line 220 "Parser.yp"
-{ ${$_[0]->{ INPERL }}--;
-				      $_[0]->{ EVAL_PERL } 
-				      ? $factory->perl($_[4])             
-				      : $factory->no_perl();              }
-	],
-	[#Rule 78
-		 '@5-1', 0,
-sub
-#line 226 "Parser.yp"
-{ ${$_[0]->{ INPERL }}++; 
-				      $rawstart = ${$_[0]->{'LINE'}};     }
-	],
-	[#Rule 79
-		 'rawperl', 5,
-sub
-#line 228 "Parser.yp"
-{ ${$_[0]->{ INPERL }}--;
-				      $_[0]->{ EVAL_PERL } 
-				      ? $factory->rawperl($_[4], $rawstart)
-				      : $factory->no_perl();              }
-	],
-	[#Rule 80
-		 'filter', 5,
-sub
-#line 235 "Parser.yp"
-{ $factory->filter(@_[2,4])           }
-	],
-	[#Rule 81
-		 'filter', 3,
-sub
-#line 237 "Parser.yp"
-{ $factory->filter(@_[3,1])           }
-	],
-	[#Rule 82
-		 'defblock', 5,
-sub
-#line 242 "Parser.yp"
-{ my $name = join('/', @{ $_[0]->{ DEFBLOCKS } });
-				      pop(@{ $_[0]->{ DEFBLOCKS } });
-				      $_[0]->define_block($name, $_[4]); 
-				      undef
-				    }
-	],
-	[#Rule 83
-		 'defblockname', 2,
-sub
-#line 249 "Parser.yp"
-{ push(@{ $_[0]->{ DEFBLOCKS } }, $_[2]);
-				      $_[2];
-				    }
-	],
-	[#Rule 84
-		 'blockname', 1, undef
-	],
-	[#Rule 85
-		 'blockname', 1,
-sub
-#line 255 "Parser.yp"
-{ $_[1] =~ s/^'(.*)'$/$1/; $_[1]      }
-	],
-	[#Rule 86
-		 'blockargs', 1, undef
-	],
-	[#Rule 87
-		 'blockargs', 0, undef
-	],
-	[#Rule 88
-		 'anonblock', 5,
-sub
-#line 263 "Parser.yp"
-{ local $" = ', ';
-				      print STDERR "experimental block args: [@{ $_[2] }]\n"
-					  if $_[2];
-				      $factory->anon_block($_[4])         }
-	],
-	[#Rule 89
-		 'capture', 3,
-sub
-#line 269 "Parser.yp"
-{ $factory->capture(@_[1, 3])         }
-	],
-	[#Rule 90
-		 'macro', 6,
-sub
-#line 273 "Parser.yp"
-{ $factory->macro(@_[2, 6, 4])        }
-	],
-	[#Rule 91
-		 'macro', 3,
-sub
-#line 274 "Parser.yp"
-{ $factory->macro(@_[2, 3])           }
-	],
-	[#Rule 92
-		 'mdir', 1, undef
-	],
-	[#Rule 93
-		 'mdir', 4,
-sub
-#line 278 "Parser.yp"
-{ $_[3]                               }
-	],
-	[#Rule 94
-		 'margs', 2,
-sub
-#line 281 "Parser.yp"
-{ push(@{$_[1]}, $_[2]); $_[1]        }
-	],
-	[#Rule 95
-		 'margs', 2,
-sub
-#line 282 "Parser.yp"
-{ $_[1]                               }
-	],
-	[#Rule 96
-		 'margs', 1,
-sub
-#line 283 "Parser.yp"
-{ [ $_[1] ]                           }
-	],
-	[#Rule 97
-		 'metadata', 2,
-sub
-#line 286 "Parser.yp"
-{ push(@{$_[1]}, @{$_[2]}); $_[1]     }
-	],
-	[#Rule 98
-		 'metadata', 2, undef
-	],
-	[#Rule 99
-		 'metadata', 1, undef
-	],
-	[#Rule 100
-		 'meta', 3,
-sub
-#line 291 "Parser.yp"
-{ for ($_[3]) { s/^'//; s/'$//; 
-						       s/\\'/'/g  }; 
-					 [ @_[1,3] ] }
-	],
-	[#Rule 101
-		 'meta', 5,
-sub
-#line 294 "Parser.yp"
-{ [ @_[1,4] ] }
-	],
-	[#Rule 102
-		 'meta', 3,
-sub
-#line 295 "Parser.yp"
-{ [ @_[1,3] ] }
-	],
-	[#Rule 103
-		 'term', 1, undef
-	],
-	[#Rule 104
-		 'term', 1, undef
-	],
-	[#Rule 105
-		 'lterm', 3,
-sub
-#line 307 "Parser.yp"
-{ "[ $_[2] ]"                         }
-	],
-	[#Rule 106
-		 'lterm', 3,
-sub
-#line 308 "Parser.yp"
-{ "[ $_[2] ]"                         }
-	],
-	[#Rule 107
-		 'lterm', 2,
-sub
-#line 309 "Parser.yp"
-{ "[ ]"                               }
-	],
-	[#Rule 108
-		 'lterm', 3,
-sub
-#line 310 "Parser.yp"
-{ "{ $_[2]  }"                        }
-	],
-	[#Rule 109
-		 'sterm', 1,
-sub
-#line 313 "Parser.yp"
-{ $factory->ident($_[1])              }
-	],
-	[#Rule 110
-		 'sterm', 2,
-sub
-#line 314 "Parser.yp"
-{ $factory->identref($_[2])           }
-	],
-	[#Rule 111
-		 'sterm', 3,
-sub
-#line 315 "Parser.yp"
-{ $factory->quoted($_[2])             }
-	],
-	[#Rule 112
-		 'sterm', 1, undef
-	],
-	[#Rule 113
-		 'sterm', 1, undef
-	],
-	[#Rule 114
-		 'list', 2,
-sub
-#line 320 "Parser.yp"
-{ "$_[1], $_[2]"                      }
-	],
-	[#Rule 115
-		 'list', 2, undef
-	],
-	[#Rule 116
-		 'list', 1, undef
-	],
-	[#Rule 117
-		 'range', 3,
-sub
-#line 325 "Parser.yp"
-{ $_[1] . '..' . $_[3]                }
-	],
-	[#Rule 118
-		 'hash', 1, undef
-	],
-	[#Rule 119
-		 'hash', 0,
-sub
-#line 330 "Parser.yp"
-{ "" }
-	],
-	[#Rule 120
-		 'params', 2,
-sub
-#line 333 "Parser.yp"
-{ "$_[1], $_[2]"                      }
-	],
-	[#Rule 121
-		 'params', 2, undef
-	],
-	[#Rule 122
-		 'params', 1, undef
-	],
-	[#Rule 123
-		 'param', 3,
-sub
-#line 338 "Parser.yp"
-{ "$_[1] => $_[3]"                    }
-	],
-	[#Rule 124
-		 'param', 3,
-sub
-#line 339 "Parser.yp"
-{ "$_[1] => $_[3]"                    }
-	],
-	[#Rule 125
-		 'ident', 3,
-sub
-#line 342 "Parser.yp"
-{ push(@{$_[1]}, @{$_[3]}); $_[1]     }
-	],
-	[#Rule 126
-		 'ident', 3,
-sub
-#line 343 "Parser.yp"
-{ push(@{$_[1]}, 
-					   map {($_, 0)} split(/\./, $_[3]));
-				      $_[1];			          }
-	],
-	[#Rule 127
-		 'ident', 1, undef
-	],
-	[#Rule 128
-		 'node', 1,
-sub
-#line 349 "Parser.yp"
-{ [ $_[1], 0 ]                        }
-	],
-	[#Rule 129
-		 'node', 4,
-sub
-#line 350 "Parser.yp"
-{ [ $_[1], $factory->args($_[3]) ]    }
-	],
-	[#Rule 130
-		 'item', 1,
-sub
-#line 353 "Parser.yp"
-{ "'$_[1]'"                           }
-	],
-	[#Rule 131
-		 'item', 3,
-sub
-#line 354 "Parser.yp"
-{ $_[2]                               }
-	],
-	[#Rule 132
-		 'item', 2,
-sub
-#line 355 "Parser.yp"
-{ $_[0]->{ V1DOLLAR }
-				       ? "'$_[2]'" 
-				       : $factory->ident(["'$_[2]'", 0])  }
-	],
-	[#Rule 133
-		 'expr', 3,
-sub
-#line 360 "Parser.yp"
-{ "$_[1] $_[2] $_[3]"                 }
-	],
-	[#Rule 134
-		 'expr', 3,
-sub
-#line 361 "Parser.yp"
-{ "$_[1] $_[2] $_[3]"                 }
-	],
-	[#Rule 135
-		 'expr', 3,
-sub
-#line 362 "Parser.yp"
-{ "$_[1] $_[2] $_[3]"                 }
-	],
-	[#Rule 136
-		 'expr', 3,
-sub
-#line 363 "Parser.yp"
-{ "int($_[1] / $_[3])"                }
-	],
-	[#Rule 137
-		 'expr', 3,
-sub
-#line 364 "Parser.yp"
-{ "$_[1] % $_[3]"                     }
-	],
-	[#Rule 138
-		 'expr', 3,
-sub
-#line 365 "Parser.yp"
-{ "$_[1] $CMPOP{ $_[2] } $_[3]"       }
-	],
-	[#Rule 139
-		 'expr', 3,
-sub
-#line 366 "Parser.yp"
-{ "$_[1]  . $_[3]"                    }
-	],
-	[#Rule 140
-		 'expr', 3,
-sub
-#line 367 "Parser.yp"
-{ "$_[1] && $_[3]"                    }
-	],
-	[#Rule 141
-		 'expr', 3,
-sub
-#line 368 "Parser.yp"
-{ "$_[1] || $_[3]"                    }
-	],
-	[#Rule 142
-		 'expr', 2,
-sub
-#line 369 "Parser.yp"
-{ "! $_[2]"                           }
-	],
-	[#Rule 143
-		 'expr', 5,
-sub
-#line 370 "Parser.yp"
-{ "$_[1] ? $_[3] : $_[5]"             }
-	],
-	[#Rule 144
-		 'expr', 3,
-sub
-#line 371 "Parser.yp"
-{ $factory->assign(@{$_[2]})          }
-	],
-	[#Rule 145
-		 'expr', 3,
-sub
-#line 372 "Parser.yp"
-{ "($_[2])"                           }
-	],
-	[#Rule 146
-		 'expr', 1, undef
-	],
-	[#Rule 147
-		 'setlist', 2,
-sub
-#line 376 "Parser.yp"
-{ push(@{$_[1]}, @{$_[2]}); $_[1]     }
-	],
-	[#Rule 148
-		 'setlist', 2, undef
-	],
-	[#Rule 149
-		 'setlist', 1, undef
-	],
-	[#Rule 150
-		 'assign', 3,
-sub
-#line 382 "Parser.yp"
-{ [ $_[1], $_[3] ]                    }
-	],
-	[#Rule 151
-		 'assign', 3,
-sub
-#line 383 "Parser.yp"
-{ [ @_[1,3] ]                         }
-	],
-	[#Rule 152
-		 'args', 2,
-sub
-#line 390 "Parser.yp"
-{ push(@{$_[1]}, $_[2]); $_[1]        }
-	],
-	[#Rule 153
-		 'args', 2,
-sub
-#line 391 "Parser.yp"
-{ push(@{$_[1]->[0]}, $_[2]); $_[1]   }
-	],
-	[#Rule 154
-		 'args', 4,
-sub
-#line 392 "Parser.yp"
-{ push(@{$_[1]->[0]}, "'', " . 
-				      $factory->assign(@_[2,4])); $_[1]  }
-	],
-	[#Rule 155
-		 'args', 2,
-sub
-#line 394 "Parser.yp"
-{ $_[1]                               }
-	],
-	[#Rule 156
-		 'args', 0,
-sub
-#line 395 "Parser.yp"
-{ [ [ ] ]                             }
-	],
-	[#Rule 157
-		 'lnameargs', 3,
-sub
-#line 405 "Parser.yp"
-{ push(@{$_[3]}, $_[1]); $_[3]        }
-	],
-	[#Rule 158
-		 'lnameargs', 1, undef
-	],
-	[#Rule 159
-		 'lvalue', 1, undef
-	],
-	[#Rule 160
-		 'lvalue', 3,
-sub
-#line 410 "Parser.yp"
-{ $factory->quoted($_[2])             }
-	],
-	[#Rule 161
-		 'lvalue', 1, undef
-	],
-	[#Rule 162
-		 'nameargs', 3,
-sub
-#line 414 "Parser.yp"
-{ [ [$factory->ident($_[2])], $_[3] ]   }
-	],
-	[#Rule 163
-		 'nameargs', 2,
-sub
-#line 415 "Parser.yp"
-{ [ @_[1,2] ] }
-	],
-	[#Rule 164
-		 'nameargs', 4,
-sub
-#line 416 "Parser.yp"
-{ [ @_[1,3] ] }
-	],
-	[#Rule 165
-		 'names', 3,
-sub
-#line 419 "Parser.yp"
-{ push(@{$_[1]}, $_[3]); $_[1] }
-	],
-	[#Rule 166
-		 'names', 1,
-sub
-#line 420 "Parser.yp"
-{ [ $_[1] ]                    }
-	],
-	[#Rule 167
-		 'name', 3,
-sub
-#line 423 "Parser.yp"
-{ $factory->quoted($_[2])  }
-	],
-	[#Rule 168
-		 'name', 1,
-sub
-#line 424 "Parser.yp"
-{ "'$_[1]'" }
-	],
-	[#Rule 169
-		 'name', 1, undef
-	],
-	[#Rule 170
-		 'filename', 3,
-sub
-#line 436 "Parser.yp"
-{ "$_[1].$_[3]" }
-	],
-	[#Rule 171
-		 'filename', 1, undef
-	],
-	[#Rule 172
-		 'filepart', 1, undef
-	],
-	[#Rule 173
-		 'filepart', 1, undef
-	],
-	[#Rule 174
-		 'filepart', 1, undef
-	],
-	[#Rule 175
-		 'quoted', 2,
-sub
-#line 450 "Parser.yp"
-{ push(@{$_[1]}, $_[2]) 
-				          if defined $_[2]; $_[1]         }
-	],
-	[#Rule 176
-		 'quoted', 0,
-sub
-#line 452 "Parser.yp"
-{ [ ]                                 }
-	],
-	[#Rule 177
-		 'quotable', 1,
-sub
-#line 455 "Parser.yp"
-{ $factory->ident($_[1])              }
-	],
-	[#Rule 178
-		 'quotable', 1,
-sub
-#line 456 "Parser.yp"
-{ $factory->text($_[1])               }
-	],
-	[#Rule 179
-		 'quotable', 1,
-sub
-#line 457 "Parser.yp"
-{ undef                               }
-	]
-];
-
-
-
-1;
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/Template/Iterator.pm b/lib/Template/Iterator.pm
deleted file mode 100644
index 710ecdc..0000000
--- a/lib/Template/Iterator.pm
+++ /dev/null
@@ -1,456 +0,0 @@
-#============================================================= -*-Perl-*-
-#
-# Template::Iterator
-#
-# DESCRIPTION
-#
-#   Module defining an iterator class which is used by the FOREACH
-#   directive for iterating through data sets.  This may be
-#   sub-classed to define more specific iterator types.
-#
-#   An iterator is an object which provides a consistent way to
-#   navigate through data which may have a complex underlying form.
-#   This implementation uses the get_first() and get_next() methods to
-#   iterate through a dataset.  The get_first() method is called once
-#   to perform any data initialisation and return the first value,
-#   then get_next() is called repeatedly to return successive values.
-#   Both these methods return a pair of values which are the data item
-#   itself and a status code.  The default implementation handles
-#   iteration through an array (list) of elements which is passed by
-#   reference to the constructor.  An empty list is used if none is
-#   passed.  The module may be sub-classed to provide custom
-#   implementations which iterate through any kind of data in any
-#   manner as long as it can conforms to the get_first()/get_next()
-#   interface.  The object also implements the get_all() method for
-#   returning all remaining elements as a list reference.
-#
-#   For further information on iterators see "Design Patterns", by the 
-#   "Gang of Four" (Erich Gamma, Richard Helm, Ralph Johnson, John 
-#   Vlissides), Addision-Wesley, ISBN 0-201-63361-2.
-#
-# AUTHOR
-#   Andy Wardley   <abw@kfs.org>
-#
-# COPYRIGHT
-#   Copyright (C) 1996-2000 Andy Wardley.  All Rights Reserved.
-#   Copyright (C) 1998-2000 Canon Research Centre Europe Ltd.
-#
-#   This module is free software; you can redistribute it and/or
-#   modify it under the same terms as Perl itself.
-#
-#----------------------------------------------------------------------------
-#
-# $Id: Iterator.pm,v 2.64 2004/01/13 16:19:15 abw Exp $
-#
-#============================================================================
-
-package Template::Iterator;
-
-require 5.004;
-
-use strict;
-use vars qw( $VERSION $DEBUG $AUTOLOAD );    # AUTO?
-use base qw( Template::Base );
-use Template::Constants;
-use Template::Exception;
-
-$VERSION = sprintf("%d.%02d", q$Revision: 2.64 $ =~ /(\d+)\.(\d+)/);
-$DEBUG   = 0 unless defined $DEBUG;
-
-
-#========================================================================
-#                      -----  CLASS METHODS -----
-#========================================================================
-
-#------------------------------------------------------------------------
-# new(\@target, \%options)
-#
-# Constructor method which creates and returns a reference to a new 
-# Template::Iterator object.  A reference to the target data (array
-# or hash) may be passed for the object to iterate through.
-#------------------------------------------------------------------------
-
-sub new {
-    my $class  = shift;
-    my $data   = shift || [ ];
-    my $params = shift || { };
-
-    if (ref $data eq 'HASH') {
-	# map a hash into a list of { key => ???, value => ??? } hashes,
-	# one for each key, sorted by keys
-	$data = [ map { { key => $_, value => $data->{ $_ } } }
-		  sort keys %$data ];
-    }
-    elsif (UNIVERSAL::can($data, 'as_list')) {
-	$data = $data->as_list();
-    }
-    elsif (ref $data ne 'ARRAY') {
-	# coerce any non-list data into an array reference
-	$data  = [ $data ] ;
-    }
-
-    bless {
-	_DATA  => $data,
-	_ERROR => '',
-    }, $class;
-}
-
-
-#========================================================================
-#                   -----  PUBLIC OBJECT METHODS -----
-#========================================================================
-
-#------------------------------------------------------------------------
-# get_first()
-#
-# Initialises the object for iterating through the target data set.  The 
-# first record is returned, if defined, along with the STATUS_OK value.
-# If there is no target data, or the data is an empty set, then undef 
-# is returned with the STATUS_DONE value.  
-#------------------------------------------------------------------------
-
-sub get_first {
-    my $self  = shift;
-    my $data  = $self->{ _DATA };
-
-    $self->{ _DATASET } = $self->{ _DATA };
-    my $size = scalar @$data;
-    my $index = 0;
-    
-    return (undef, Template::Constants::STATUS_DONE) unless $size;
-
-    # initialise various counters, flags, etc.
-    @$self{ qw( SIZE MAX INDEX COUNT FIRST LAST ) } 
-	    = ( $size, $size - 1, $index, 1, 1, $size > 1 ? 0 : 1, undef );
-    @$self{ qw( PREV NEXT ) } = ( undef, $self->{ _DATASET }->[ $index + 1 ]);
-
-    return $self->{ _DATASET }->[ $index ];
-}
-
-
-
-#------------------------------------------------------------------------
-# get_next()
-#
-# Called repeatedly to access successive elements in the data set.
-# Should only be called after calling get_first() or a warning will 
-# be raised and (undef, STATUS_DONE) returned.
-#------------------------------------------------------------------------
-
-sub get_next {
-    my $self = shift;
-    my ($max, $index) = @$self{ qw( MAX INDEX ) };
-    my $data = $self->{ _DATASET };
-
-    # warn about incorrect usage
-    unless (defined $index) {
-	my ($pack, $file, $line) = caller();
-	warn("iterator get_next() called before get_first() at $file line $line\n");
-	return (undef, Template::Constants::STATUS_DONE);   ## RETURN ##
-    }
-
-    # if there's still some data to go...
-    if ($index < $max) {
-	# update counters and flags
-	$index++;
-	@$self{ qw( INDEX COUNT FIRST LAST ) }
-	        = ( $index, $index + 1, 0, $index == $max ? 1 : 0 );
-	@$self{ qw( PREV NEXT ) } = @$data[ $index - 1, $index + 1 ];
-	return $data->[ $index ];			    ## RETURN ##
-    }
-    else {
-	return (undef, Template::Constants::STATUS_DONE);   ## RETURN ##
-    }
-}
-
-
-#------------------------------------------------------------------------
-# get_all()
-#
-# Method which returns all remaining items in the iterator as a Perl list
-# reference.  May be called at any time in the life-cycle of the iterator.
-# The get_first() method will be called automatically if necessary, and
-# then subsequent get_next() calls are made, storing each returned 
-# result until the list is exhausted.  
-#------------------------------------------------------------------------
-
-sub get_all {
-    my $self = shift;
-    my ($max, $index) = @$self{ qw( MAX INDEX ) };
-    my @data;
-
-    # if there's still some data to go...
-    if ($index < $max) {
-	$index++;
-	@data = @{ $self->{ _DATASET } } [ $index..$max ];
-
-	# update counters and flags
-	@$self{ qw( INDEX COUNT FIRST LAST ) }
-	        = ( $max, $max + 1, 0, 1 );
-
-	return \@data;					    ## RETURN ##
-    }
-    else {
-	return (undef, Template::Constants::STATUS_DONE);   ## RETURN ##
-    }
-}
-    
-
-#------------------------------------------------------------------------
-# AUTOLOAD
-#
-# Provides access to internal fields (e.g. size, first, last, max, etc)
-#------------------------------------------------------------------------
-
-sub AUTOLOAD {
-    my $self = shift;
-    my $item = $AUTOLOAD;
-    $item =~ s/.*:://;
-    return if $item eq 'DESTROY';
-
-    # alias NUMBER to COUNT for backwards compatability
-    $item = 'COUNT' if $item =~ /NUMBER/i;
-
-    return $self->{ uc $item };
-}
-
-
-#========================================================================
-#                   -----  PRIVATE DEBUG METHODS -----
-#========================================================================
-
-#------------------------------------------------------------------------
-# _dump()
-#
-# Debug method which returns a string detailing the internal state of 
-# the iterator object.
-#------------------------------------------------------------------------
-
-sub _dump {
-    my $self = shift;
-    join('',
-	 "  Data: ", $self->{ _DATA  }, "\n",
-	 " Index: ", $self->{ INDEX  }, "\n",
-	 "Number: ", $self->{ NUMBER }, "\n",
-	 "   Max: ", $self->{ MAX    }, "\n",
-	 "  Size: ", $self->{ SIZE   }, "\n",
-	 " First: ", $self->{ FIRST  }, "\n",
-	 "  Last: ", $self->{ LAST   }, "\n",
-	 "\n"
-     );
-}
-
-
-1;
-
-__END__
-
-
-#------------------------------------------------------------------------
-# IMPORTANT NOTE
-#   This documentation is generated automatically from source
-#   templates.  Any changes you make here may be lost.
-# 
-#   The 'docsrc' documentation source bundle is available for download
-#   from http://www.template-toolkit.org/docs.html and contains all
-#   the source templates, XML files, scripts, etc., from which the
-#   documentation for the Template Toolkit is built.
-#------------------------------------------------------------------------
-
-=head1 NAME
-
-Template::Iterator - Data iterator used by the FOREACH directive
-
-=head1 SYNOPSIS
-
-    my $iter = Template::Iterator->new(\@data, \%options);
-
-=head1 DESCRIPTION
-
-The Template::Iterator module defines a generic data iterator for use 
-by the FOREACH directive.  
-
-It may be used as the base class for custom iterators.
-
-=head1 PUBLIC METHODS
-
-=head2 new($data) 
-
-Constructor method.  A reference to a list of values is passed as the
-first parameter.  Subsequent calls to get_first() and get_next() calls 
-will return each element from the list.
-
-    my $iter = Template::Iterator->new([ 'foo', 'bar', 'baz' ]);
-
-The constructor will also accept a reference to a hash array and will 
-expand it into a list in which each entry is a hash array containing
-a 'key' and 'value' item, sorted according to the hash keys.
-
-    my $iter = Template::Iterator->new({ 
-	foo => 'Foo Item',
-	bar => 'Bar Item',
-    });
-
-This is equivalent to:
-
-    my $iter = Template::Iterator->new([
-	{ key => 'bar', value => 'Bar Item' },
-	{ key => 'foo', value => 'Foo Item' },
-    ]);
-
-When passed a single item which is not an array reference, the constructor
-will automatically create a list containing that single item.
-
-    my $iter = Template::Iterator->new('foo');
-
-This is equivalent to:
-
-    my $iter = Template::Iterator->new([ 'foo' ]);
-
-Note that a single item which is an object based on a blessed ARRAY 
-references will NOT be treated as an array and will be folded into 
-a list containing that one object reference.
-
-    my $list = bless [ 'foo', 'bar' ], 'MyListClass';
-    my $iter = Template::Iterator->new($list);
-
-equivalent to:
-
-    my $iter = Template::Iterator->new([ $list ]);
-
-If the object provides an as_list() method then the Template::Iterator
-constructor will call that method to return the list of data.  For example:
-
-    package MyListObject;
-
-    sub new {
-	my $class = shift;
-	bless [ @_ ], $class;
-    }
-
-    package main;
-
-    my $list = MyListObject->new('foo', 'bar');
-    my $iter = Template::Iterator->new($list);
-
-This is then functionally equivalent to:
-
-    my $iter = Template::Iterator->new([ $list ]);
-
-The iterator will return only one item, a reference to the MyListObject
-object, $list.
-
-By adding an as_list() method to the MyListObject class, we can force
-the Template::Iterator constructor to treat the object as a list and 
-use the data contained within.
-
-    package MyListObject;
-
-    ...
-
-    sub as_list {
-	my $self = shift;
-	return $self;
-    }
-
-    package main;
-
-    my $list = MyListObject->new('foo', 'bar');
-    my $iter = Template::Iterator->new($list);
-
-The iterator will now return the two item, 'foo' and 'bar', which the 
-MyObjectList encapsulates.
-
-=head2 get_first()
-
-Returns a ($value, $error) pair for the first item in the iterator set.
-The $error returned may be zero or undefined to indicate a valid datum
-was successfully returned.  Returns an error of STATUS_DONE if the list 
-is empty.
-
-=head2 get_next()
-
-Returns a ($value, $error) pair for the next item in the iterator set.
-Returns an error of STATUS_DONE if all items in the list have been 
-visited.
-
-=head2 get_all()
-
-Returns a (\@values, $error) pair for all remaining items in the iterator 
-set.  Returns an error of STATUS_DONE if all items in the list have been 
-visited.
-
-=head2 size()
-
-Returns the size of the data set or undef if unknown.
-
-=head2 max()
-
-Returns the maximum index number (i.e. the index of the last element) 
-which is equivalent to size() - 1.
-
-=head2 index()
-
-Returns the current index number which is in the range 0 to max().
-
-=head2 count()
-
-Returns the current iteration count in the range 1 to size().  This is
-equivalent to index() + 1.  Note that number() is supported as an alias
-for count() for backwards compatability.
-
-=head2 first()
-
-Returns a boolean value to indicate if the iterator is currently on 
-the first iteration of the set.
-
-=head2 last()
-
-Returns a boolean value to indicate if the iterator is currently on
-the last iteration of the set.
-
-=head2 prev()
-
-Returns the previous item in the data set, or undef if the iterator is
-on the first item.
-
-=head2 next()
-
-Returns the next item in the data set or undef if the iterator is on the 
-last item.
-
-=head1 AUTHOR
-
-Andy Wardley E<lt>abw@andywardley.comE<gt>
-
-L<http://www.andywardley.com/|http://www.andywardley.com/>
-
-
-
-
-=head1 VERSION
-
-2.64, distributed as part of the
-Template Toolkit version 2.13, released on 30 January 2004.
-
-=head1 COPYRIGHT
-
-  Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
-  Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
-
-This module is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
-
-=head1 SEE ALSO
-
-L<Template|Template>
-
-=cut
-
-# Local Variables:
-# mode: perl
-# perl-indent-level: 4
-# indent-tabs-mode: nil
-# End:
-#
-# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Library/HTML.pod b/lib/Template/Library/HTML.pod
deleted file mode 100644
index e39c120..0000000
--- a/lib/Template/Library/HTML.pod
+++ /dev/null
@@ -1,316 +0,0 @@
-#============================================================= -*-perl-*-
-#
-# Template::Library::HTML
-#
-# DESCRIPTION
-#   The HTML library provides a number of basic templates for use in
-#   building HTML pages.
-#
-# AUTHOR
-#   Andy Wardley  <abw@andywardley.com>
-#
-# COPYRIGHT
-#   Copyright (C) 1996-2001 Andy Wardley.  All Rights Reserved.
-#   Copyright (C) 1998-2001 Canon Research Centre Europe Ltd.
-#
-#   This module is free software; you can redistribute it and/or
-#   modify it under the same terms as Perl itself.
-#
-# REVISION
-#   2.69
-#
-#========================================================================
-
-
-#------------------------------------------------------------------------
-# IMPORTANT NOTE
-#   This documentation is generated automatically from source
-#   templates.  Any changes you make here may be lost.
-# 
-#   The 'docsrc' documentation source bundle is available for download
-#   from http://www.template-toolkit.org/docs.html and contains all
-#   the source templates, XML files, scripts, etc., from which the
-#   documentation for the Template Toolkit is built.
-#------------------------------------------------------------------------
-
-=head1 NAME
-
-Template::Library::HTML - Template library for building basic HTML pages
-
-=head1 DESCRIPTION
-
-B<NOTE:> This documentation is incomplete and may be incorrect
-in places. 
-
-The 'html' template library is distributed as part of the Template
-Toolkit.  It can be found in the 'templates' sub-directory of the
-installation directory.
-
-    use Template;
-
-    my $tt2 = Template->new({
-	INCLUDE_PATH => '/usr/local/tt2/templates',
-    });
-
-For a portable way to determine the installation 'templates' directory,
-you can use the C<Template::Config-E<gt>instdir()> class method.
-
-    use Template;
-
-    my $tt2 = Template->new({
-	INCLUDE_PATH => Template::Config->instdir('templates'),
-    });
-
-You should now be able to access the html library as, for example:
-
-    [% INCLUDE html/header %]
-
-Note that some of the more basic elements don't give you much more
-than the raw HTML tags.  In many cases you might be well advised to
-stick to regular HTML rather than complicating matters by the use
-of template elements.
-
-e.g.
-
-    <table>
-      . . .
-    </table>
-
-vs
-
-    [% WRAPPER html/table %]
-       . . .
-    [% END %]
-
-However, the use of template elements to generate the underlying HTML
-does have some important benefits, particularly as the constructs start
-to get more complicated and more magical.
-
-See the example in the 'examples' sub-directory of the distribution
-directory for further examples and enlightenment on using this library.
-
-=head2 Headers, Footers and Pages
-
-=over 4
-
-=item header
-
-The 'header' element generates the regular header required as the 
-pre-amble for an HTML document.  That is, everything from the initial
-E<lt>htmlE<gt> to the opening E<lt>bodyE<gt>.
-
-    [% INCLUDE html/header
-         title = 'This is a Test'
-	 bgcol = '#ffffff'
-    %]
-
-Additional header items can be provided by explicitly setting the 'headers'
-variable, e.g.
-
-    [% headers = BLOCK %]
-    <META name="description" content="Template Toolkit">
-    <META name="REVISIT-AFTER" content="14 days">	
-    <META name="keywords" content="Templates, Web, ...etc...">
-    [% END %]
-
-    [% INCLUDE html/header
-	 title = 'This is a Test'
-	 bgcol = '#ffffff'
-    %]
-
-=item footer
-
-The 'footer' element generates the terminating E<lt>/bodyE<gt> and
-E<lt>/htmlE<gt> element to balance the header.
-
-    [% PROCESS html/header %]
-
-    ...page content here...
-
-    [% PROCESS html/footer %]
-
-=item page
-
-The 'page' element combines the 'html/header' and 'html/footer' elements.
-
-    [% WRAPPER html/page %]
-
-    ...page content here...
-
-    [% END %]
-
-Page content should be defined in the 'content' variable (e.g. via WRAPPER).
-Additional HTML headers should be defined in the 'headers' variable.
-
-    [% WRAPPER html/page
-        headers = '<META name="keywords" content="foo, bar, ...">'
-    %]
-
-    ...page content here...
-
-    [% END %]
-
-=back
-
-=head2 Tables, Bars and Boxes
-
-=over 4
-
-=item table
-
-A basic element for creating HTML tables.
-
-    [% WRAPPER html/table pad=10 space=4 col='#404040' %]
-       <tr>
-	<td>Hello</td> <td>World</td>
-       </tr>
-    [% END %]
-
-The following variables may be defined:
-
-=over 4
-
-=item border
-
-Set the border width (default: 0)
-
-=item col
-
-Set the background colour (default: none).
-
-=item width
-
-Set a fixed table width.
-
-=item pad
-
-Set the cellpadding.
-
-=item space
-
-Set the cellspacing.
-
-=item content
-
-Content for the box.  Supplied automatically if used via WRAPPER.
-
-=back
-
-=item row
-
-A basic element for creating HTML table rows.
-
-    [% WRAPPER html/table %]
-       [% WRAPPER html/row %]
-	<td>Hello</td> <td>World</td>
-       [% END %]
-    [% END %]
-
-The following variables may be defined:
-
-=over 4
-
-=item col
-
-Set the background colour (default: none).
-
-=item valign
-
-Set the vertical alignment.
-
-=item rowspan
-
-Specify the number of rows to span.
-
-=item content
-
-Content for the box.  Supplied automatically if used via WRAPPER.
-
-=back
-
-=item cell
-
-A basic element for creating HTML table cells.
-
-    [% WRAPPER html/table %]
-       [% WRAPPER html/row %]
-	  [% INCLUDE html/cell 
-		FOREACH content = ['Hello', 'World'] %]
-       [% END %]
-    [% END %]
-
-The following variables may be defined:
-
-=over 4
-
-=item col
-
-Set the background colour (default: none).
-
-=item align
-
-Set the horizontal alignment.
-
-=item colspan
-
-Specify the number of columns to span.
-
-=item content
-
-Content for the cell.  Supplied automatically if used via WRAPPER.
-
-=back
-
-=item bar
-
-The bar element is a wrapping of html/table + html/row.
-
-    [% WRAPPER html/bar %]
-       <td>Foo</td>  <td>Bar</td>
-    [% END %]
-
-=item box
-
-The box element is a wrapping of html/table + html/row + html/cell
-
-    [% WRAPPER html/box %]
-       Hello World!
-    [% END %]
-
-=back
-
-=head1 AUTHOR
-
-Andy Wardley E<lt>abw@andywardley.comE<gt>
-
-L<http://www.andywardley.com/|http://www.andywardley.com/>
-
-
-
-
-=head1 VERSION
-
-2.69, distributed as part of the
-Template Toolkit version 2.13, released on 30 January 2004.
-
-=head1 COPYRIGHT
-
-  Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
-  Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
-
-This module is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
-
-=head1 SEE ALSO
-
-L<Template::Library::Splash|Template::Library::Splash>
-
-=cut
-
-# Local Variables:
-# mode: perl
-# perl-indent-level: 4
-# indent-tabs-mode: nil
-# End:
-#
-# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Library/PostScript.pod b/lib/Template/Library/PostScript.pod
deleted file mode 100644
index c30246c..0000000
--- a/lib/Template/Library/PostScript.pod
+++ /dev/null
@@ -1,78 +0,0 @@
-#============================================================= -*-perl-*-
-#
-# Template::Library::PostScript
-#
-# DESCRIPTION
-#   This library contains a number of useful templates for generating
-#   PostScript pages.
-#
-# AUTHOR
-#   Andy Wardley  <abw@andywardley.com>
-#
-# COPYRIGHT
-#   Copyright (C) 1996-2001 Andy Wardley.  All Rights Reserved.
-#   Copyright (C) 1998-2001 Canon Research Centre Europe Ltd.
-#
-#   This module is free software; you can redistribute it and/or
-#   modify it under the same terms as Perl itself.
-#
-# REVISION
-#   2.69
-#
-#========================================================================
-
-
-#------------------------------------------------------------------------
-# IMPORTANT NOTE
-#   This documentation is generated automatically from source
-#   templates.  Any changes you make here may be lost.
-# 
-#   The 'docsrc' documentation source bundle is available for download
-#   from http://www.template-toolkit.org/docs.html and contains all
-#   the source templates, XML files, scripts, etc., from which the
-#   documentation for the Template Toolkit is built.
-#------------------------------------------------------------------------
-
-=head1 NAME
-
-Template::Library::PostScript - Template library for generating PostScript
-
-=head1 DESCRIPTION
-
-The PostScript library contains a number of templates for generating
-PostScript pages.  It's very new, very incomplete, very ad-hoc and
-isn't yet documented.
-
-=head1 AUTHOR
-
-Andy Wardley E<lt>abw@andywardley.comE<gt>
-
-L<http://www.andywardley.com/|http://www.andywardley.com/>
-
-
-
-
-=head1 VERSION
-
-2.69, distributed as part of the
-Template Toolkit version 2.13, released on 30 January 2004.
-
-=head1 COPYRIGHT
-
-  Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
-  Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
-
-This module is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
-
-
-
-=cut
-
-# Local Variables:
-# mode: perl
-# perl-indent-level: 4
-# indent-tabs-mode: nil
-# End:
-#
-# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Library/Splash.pod b/lib/Template/Library/Splash.pod
deleted file mode 100644
index e8c4f8b..0000000
--- a/lib/Template/Library/Splash.pod
+++ /dev/null
@@ -1,1030 +0,0 @@
-#============================================================= -*-perl-*-
-#
-# Template::Library::Splash
-#
-# DESCRIPTION
-#   The Splash! library is built on top of the HTML library and
-#   implements a set of widgets for easy construction of stylish HTML
-#   pages
-#
-# AUTHOR
-#   Andy Wardley  <abw@andywardley.com>
-#
-# COPYRIGHT
-#   Copyright (C) 1996-2001 Andy Wardley.  All Rights Reserved.
-#   Copyright (C) 1998-2001 Canon Research Centre Europe Ltd.
-#
-#   This module is free software; you can redistribute it and/or
-#   modify it under the same terms as Perl itself.
-#
-# REVISION
-#   2.69
-#
-#========================================================================
-
-
-#------------------------------------------------------------------------
-# IMPORTANT NOTE
-#   This documentation is generated automatically from source
-#   templates.  Any changes you make here may be lost.
-# 
-#   The 'docsrc' documentation source bundle is available for download
-#   from http://www.template-toolkit.org/docs.html and contains all
-#   the source templates, XML files, scripts, etc., from which the
-#   documentation for the Template Toolkit is built.
-#------------------------------------------------------------------------
-
-=head1 NAME
-
-Template::Library::Splash - Template library for building stylish HTML user interfaces
-
-=head1 DESCRIPTION
-
-B<NOTE:> This documentation is incomplete, incorrect and outdated.
-The Splash! library is still evolving and subject to change.  See
-the examples for a much more recent and accurate demonstration of
-use.
-
-=head2 Introduction
-
-The 'Splash' template library is distributed as part of the Template
-Toolkit.  It can be found in the 'templates' sub-directory of the
-installation directory.
-
-    /your/tt2/installation
-    |
-    +-- docs
-    |      ...
-    |  
-    +-- images
-    |      ...
-    |
-    +-- examples
-    |      ...
-    |
-    +-- templates
-        |
-        +-- html
-        |      ...
-        +-- pod
-        |      ...
-        +-- splash     <<<< YOU ARE HERE
-               ...
-
-
-To use the Splash library, you first need to tell the Template Toolkit
-where to find the template files.
-
-    use Template;
-
-    my $tt2 = Template->new({
-	INCLUDE_PATH => '/usr/local/tt2/templates',
-    });
-
-For a portable way to determine the installation 'templates' directory,
-you can use the C<Template::Config-E<gt>instdir()> class method.
-
-    use Template;
-
-    my $tt2 = Template->new({
-	INCLUDE_PATH => Template::Config->instdir('templates'),
-    });
-
-Note that you should set the INCLUDE_PATH to the 'templates' directory
-as shown here and don't be tempted to set the INCLUDE_PATH to
-'templates/splash'.  Many of the Splash! components use elements in
-the 'html' directory and contain directives of the form:
-
-    [% INCLUDE html/something %].
-
-=head2 Configuration
-
-The 'splash/config' template defines a 'splash' hash array which
-contains numerous configuration items for the Splash library.  You
-must PROCESS this template to ensure that the hash definition is
-imported into your calling template.  An INCLUDE is not sufficient as
-it localises variables and prevents the 'splash' hash array from
-existing outside the splash/config template.
-
-    [% PROCESS splash/config %]
-
-Alternately, you can define the splash/config template as a PRE_PROCESS
-item when you create the Template processor. 
-
-    use Template;
-
-    my $tt2 = Template->new({
-	INCLUDE_PATH => Template::Config->instdir('templates'),
-	PRE_PROCESS  => 'splash/config',
-    });
-
-You can modify the default configuration by creating your own
-PRE_PROCESS config file which loads the 'splash/config' and then
-tweaks the settings to your own preferences.
-
-    my $tt2 = Template->new({
-	INCLUDE_PATH => [ '/home/abw/tt2/templates',
-		          Template::Config->instdir('templates') ],
-        PRE_PROCESS => 'config'
-    });
-
-/home/abw/tt2/templates/config:
-
-    [% # load the 'splash' configuration
-       PROCESS splash/config;
-       
-       # tweak values to personal preferences
-       splash.images       = '/~abw/tt2/images/splash'
-       splash.select.col   = 'leaf'
-       splash.unselect.col = 'bud'
-    %]
-
-The splash/config file includes some instructional comments on 
-things you might like to tweak.
-
-=head2 Colours
-
-The Splash! library uses the colours defined in the html/rgb template.
-The 'rgb' hash defined therein is imported as the 'splash.rgb' hash.
-
-    [% INCLUDE splash/box col='grey75' %]
-
-See the examples for further enlightenment on using colour.
-
-=head2 Style
-
-There are two very primitive "styles" implemented called "select" and
-"unselect".  These are used to indicate which item on a menu is
-selected, for example.  Each style defines characteristics like
-background colour, font face, size and colour, text alignment, and so
-on.  
-
-The styles are implemented as hashes within the 'splash' hash.  Many
-of the components respond to a 'style' variable being set and you can
-pass a direct reference to splash.select or splash.unselect (or your
-own styles).  e.g.
-
-    [% INCLUDE splash/button 
-	   content = "Unselected"
-           style   = splash.unselect
-    %]
-    [% INCLUDE splash/button 
-           content ="Selected"
-           style   = splash.select
-    %]
-
-Alternately, you can use the 'select' variable to indicate either
-of the inbuilt styles: splash.select or splash.unselect.
-
-    [% INCLUDE splash/button 
-           content = "Unselected"
-           select  = 0
-    %]
-    [% INCLUDE splash/button
-           content = "Selected"
-           select  = 1
-    %]
-
-=head1 COMPONENT TEMPLATES
-
-This section describes some of the component templates in the Splash!
-library.  This documentation is incomplete and may also be inaccurate
-in places.  The examples in the 'examples' directory are likely to be
-a much better reference.
-
-
-=head2 splash/text
-
-Simple template to format text according to a selected/unselected style,
-adding links, etc.
-
-    [% INCLUDE splash/text
-           content = 'Template Toolkit'
-           link    = 'http://www.template-toolkit.org'
-           select  = 0
-           bold    = 1
-    %]
-
-
-Configuration items:
-
-=over 4
-
-
-=item content
-
-Text content.
-
-
-=item link
-
-URL which can be defined to make the text a link.
-
-
-=item style
-
-Reference to a style hash.
-
-
-=item select
-
-Flag to default the style to splash.select (select == true value) or
-splash.unselect (select == false value).
-
-
-=back
-
-The following items default to the relevant style values:
-
-=over 4
-
-
-=item col (style.col.text)
-
-
-=item font (style.font.face)
-
-
-=item bold (style.font.bold)
-
-
-=item size (style.font.size)
-
-
-=back
-
-
-
-=head2 splash/table
-
-A thin wrapper around html/table, allowing a colour to be specified
-by name.
-
-    [% WRAPPER splash/table
-           col   = 'aqua'
-	   pad   = 4
-           width = '100%'
-    %]
-    <tr>
-      <td>Foo</td>
-      <td>Bar</td>
-    </tr>
-    [% END %]
-
-
-Configuration items:
-
-=over 4
-
-
-=item content
-
-Table content.
-
-
-=item col
-
-Background colour.
-
-
-=item border
-
-Border width (default: 0)
-
-
-=item width
-
-Width in absolute pixels (e.g. '100') or as a percentage (e.g. '50%').
-
-=item pad
-
-Cell padding.
-
-
-=item space
-
-Cell padding.
-
-
-=back
-
-
-
-=head2 splash/row
-
-Creates a row for an HTML table.
-
-    [% WRAPPER splash/table %]
-
-       [% WRAPPER splash/row col='marine' %]
-       <td>Foo</td><td>Bar</td>
-       [% END %]
-
-       [% WRAPPER splash/row col='aqua' %]
-       <td>Foo</td><td>Bar</td>
-       [% END %]
-
-    [% END %]
-
-
-Configuration items:
-
-=over 4
-
-
-=item content
-
-Row content.
-
-
-=item col
-
-Background colour.
-
-
-=item valign
-
-Vertical alignment
-
-
-=item rowspan
-
-Number of rows to span.
-
-
-=back
-
-
-
-=head2 splash/cell
-
-Creates a cell for an HTML table.
-
-    [% WRAPPER splash/table + splash/row + splash/cell col='grey75' %]
-	Hello World
-    [% END %]
-
-
-Configuration items:
-
-=over 4
-
-
-=item content
-
-Cell content.
-
-
-=item col
-
-Background colour.
-
-
-=item align
-
-Horizontal alignment
-
-
-=item colspan
-
-Number of columns to span.
-
-
-=back
-
-
-
-=head2 splash/box
-
-A box created from a union of splash/table, splash/row and splash/cell.
-The following is equivalent to the previous example.
-
-    [% WRAPPER splash/box col='grey75' %]
-	Hello World
-    [% END %]
-
-Configuration items are as per the individual templates.
-
-
-=head2 splash/button
-
-Creates a small button with rounded corners.
-
-    [% INCLUDE splash/button
-           content = 'Template Toolkit'
-           select  = 1
-           width   = '50%'
-    %]
-
-
-Configuration items:
-
-=over 4
-
-
-=item content
-
-Button content.
-
-
-=item style
-
-Reference to a style hash.
-
-
-=item select
-
-Flag to default the style to splash.select (select == true value) or
-splash.unselect (select == false value).
-
-
-=item width
-
-Width in absolute pixels (e.g. '100') or as a percentage (e.g. '50%').
-
-=back
-
-The following items default to the relevant style values:
-
-=over 4
-
-
-=item col (style.col.text)
-
-
-=item textcol (style.col.text)
-
-
-=item font (style.font.face)
-
-
-=item size (style.font.size)
-
-
-=item bold (style.font.bold)
-
-
-=item width (style.button.width)
-
-
-=item align (style.button.align)
-
-
-=back
-
-
-
-=head2 splash/bar
-
-Creates a bar with rounded corners at either the top or bottom, and 
-square corners on the other.  Default has rounded at the top, set
-'invert' to select bottom.
-
-    [% INCLUDE splash/bar
-           content = 'Hello World',
-           select  = 1
-    %]	
-
-
-Configuration items:
-
-=over 4
-
-
-=item content
-
-Bar content.
-
-
-=item style
-
-Reference to a style hash.
-
-
-=item select
-
-Flag to default the style to splash.select (select == true value) or
-splash.unselect (select == false value).
-
-
-=item width
-
-Width in absolute pixels (e.g. '100') or as a percentage (e.g. '50%').
-
-=item invert
-
-Flag to invert bar to hang down instead of sitting
-upright.
-
-
-=back
-
-The following items default to the relevant style values:
-
-=over 4
-
-
-=item col (style.col.text)
-
-
-=item textcol (style.col.text)
-
-
-=item font (style.font.face)
-
-
-=item size (style.font.size)
-
-
-=item bold (style.font.bold)
-
-
-=item width (style.button.width)
-
-
-=item align (style.button.align)
-
-
-=back
-
-
-=head2 splash/hair
-
-Generates a frame enclosing the content within crosshair corners.
-
-    [% INCLUDE splash/hair
-           content = 'Template Toolkit'
-    %]
-
-
-Configuration items:
-
-=over 4
-
-
-=item content
-
-Hair content.
-
-
-=item style
-
-Reference to a style hash.
-
-
-=back
-
-The following items default to the relevant style values:
-
-=over 4
-
-
-=item col (style.col.text)
-
-
-=item bgcol (style.col.back)
-
-
-=item align (style.button.align)
-
-
-=back
-
-
-=head2 splash/menu
-
-Creates a menu as a series of splash/button elements.
-
-    [% buttons = [ 
-	  { text => 'One', link => 'one.html' }
-          { text => 'Two', link => 'two.html' }
-       ]
-    %]
-
-    [% INCLUDE splash/menu
-           select = 2		# Two
-    %]
-
-
-Configuration items:
-
-=over 4
-
-
-=item buttons
-
-A reference to a list of hash arrays containing 'text' and 'link' items.
-
-
-=item select (n or 0)
-
-Indicates which button should be selected.  First item is 1.  0 indicates
-no button selected.
-
-
-=item width
-
-Width in absolute pixels (e.g. '100') or as a percentage (e.g. '50%').
-
-=item align
-
-Horizontal alignment
-
-
-=back
-
-
-
-=head2 splash/menubar
-
-As above, but incorporated into a wider bar.
-
-    [% WRAPPER splash/menubar %]
-       Section Title
-    [% END %]
-
-
-Configuration items:
-
-=over 4
-
-
-=item buttons
-
-A reference to a list of hash arrays containing 'text' and 'link' items.
-
-
-=item select (n or 0)
-
-Indicates which button should be selected.  First item is 1.  0 indicates
-no button selected.
-
-
-=item width
-
-Width in absolute pixels (e.g. '100') or as a percentage (e.g. '50%').
-
-=item align
-
-Horizontal alignment
-
-
-=back
-
-
-
-=head2 splash/panel
-
-A table with a coloured edge.
-
-    [% WRAPPER splash/panel edge='black' fill='grey75' border=2 %]
-       <tr>
-         <td>Hello World</td>
-       </tr>
-    [% END %]
-
-
-Configuration items:
-
-=over 4
-
-
-=item content
-
-Panel content.
-
-
-=item style
-
-Reference to a style hash.
-
-
-=item select
-
-Flag to default the style to splash.select (select == true value) or
-splash.unselect (select == false value).
-
-
-=item width
-
-Width in absolute pixels (e.g. '100') or as a percentage (e.g. '50%').
-
-=item align
-
-Horizontal alignment
-
-
-=item border
-
-Border width (default: 0)
-
-
-=back
-
-The following items default to the relevant style values:
-
-=over 4
-
-
-=item edge (style.col.edge)
-
-
-=item fill (style.col.fill)
-
-
-=item pad (style.pad)
-
-
-=back
-
-
-
-=head2 splash/pane
-
-A union of splash/row + splash/cell.
-
-    [% WRAPPER splash/panel select=1 %]
-       [% WRAPPER splash/pane col='grey75' %]
-          Hello World
-       [% END %]
-
-       [% WRAPPER splash/pane col='grey50' %]
-          Hello Again
-       [% END %]
-    [% END %]
-
-
-=head2 splash/tab
-
-A simple button looking like a page tab.
-
-    [% INCLUDE splash/tab
-           content = 'Option 1'
-           col = 'aqua'
-    %]
-
-
-Configuration items:
-
-=over 4
-
-
-=item content
-
-Tab content.
-
-
-=item style
-
-Reference to a style hash.
-
-
-=item select
-
-Flag to default the style to splash.select (select == true value) or
-splash.unselect (select == false value).
-
-
-=item width
-
-Width in absolute pixels (e.g. '100') or as a percentage (e.g. '50%').
-
-=item align
-
-Horizontal alignment
-
-
-=back
-
-The following items default to the relevant style values:
-
-=over 4
-
-
-=item col (style.col.text)
-
-
-=item textcol (style.col.text)
-
-
-=item font (style.font.face)
-
-
-=item size (style.font.size)
-
-
-=item bold (style.font.bold)
-
-
-=item tabalign (style.tab.align)
-
-
-=back
-
-
-
-=head2 splash/tabset
-
-A set of splash/tab components, similar to a menu.
-
-
-Configuration items:
-
-=over 4
-
-
-=item tabs
-
-List of hash references containing text/link entries, as per 
-menu buttons.
-
-
-=item select
-
-Flag to default the style to splash.select (select == true value) or
-splash.unselect (select == false value).
-
-
-=item invert
-
-Flag to invert tab to hang down instead of sitting
-upright.
-
-
-=back
-
-
-
-=head2 splash/tabbox
-
-Add a splash/tab to the top of a splash/box.
-
-
-Configuration items:
-
-=over 4
-
-
-=item title
-
- title.
-
-
-=item content
-
- content.
-
-
-=item width
-
-Width in absolute pixels (e.g. '100') or as a percentage (e.g. '50%').
-
-=item tabwidth
-
-Width of tabs.
-
-
-=item select
-
-Flag to default the style to splash.select (select == true value) or
-splash.unselect (select == false value).
-
-
-=item border
-
-Border width (default: 0)
-
-
-=back
-
-The following items default to the relevant style values:
-
-=over 4
-
-
-=item col (style.col.text)
-
-
-=item fill (style.col.fill)
-
-
-=item tabalign (style.tab.align)
-
-
-=item tablocate (style.tab.locate)
-
-
-=back
-
-
-
-=head2 splash/tabsbox
-
-Add a splash/tabset to the top of a splash/box.
-
-
-Configuration items:
-
-=over 4
-
-
-=item tabs
-
-List of hash references containing text/link entries, as per 
-menu buttons.
-
-
-=item select
-
-Flag to default the style to splash.select (select == true value) or
-splash.unselect (select == false value).
-
-
-=item content
-
- content.
-
-
-=item width
-
-Width in absolute pixels (e.g. '100') or as a percentage (e.g. '50%').
-
-=item border
-
-Border width (default: 0)
-
-
-=item invert
-
-Flag to invert  to hang down instead of sitting
-upright.
-
-
-=back
-
-The following items default to the relevant style values:
-
-=over 4
-
-
-=item col (style.col.text)
-
-
-=item fill (style.col.fill)
-
-
-=item tabalign (style.tab.align)
-
-
-=item tablocate (style.tab.locate)
-
-
-=back
-
-
-=head2 splash/tabspanel
-
-As per splash/tabsbox, but attached to a splash/panel instead of a
-splash/box.
-
-
-=head1 EXAMPLES
-
-See the examples in the 'examples' sub-directory of the installation 
-for comprehensive examples showing use of the Splash! library.
-
-=head1 AUTHOR
-
-Andy Wardley E<lt>abw@andywardley.comE<gt>
-
-L<http://www.andywardley.com/|http://www.andywardley.com/>
-
-
-
-
-=head1 VERSION
-
-2.69, distributed as part of the
-Template Toolkit version 2.13, released on 30 January 2004.
-
-=head1 COPYRIGHT
-
-  Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
-  Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
-
-This module is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
-
-=head1 SEE ALSO
-
-L<Template::Library::HTML|Template::Library::HTML>
-
-=cut
-
-# Local Variables:
-# mode: perl
-# perl-indent-level: 4
-# indent-tabs-mode: nil
-# End:
-#
-# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Manual.pod b/lib/Template/Manual.pod
deleted file mode 100644
index 8775a5b..0000000
--- a/lib/Template/Manual.pod
+++ /dev/null
@@ -1,180 +0,0 @@
-#============================================================= -*-perl-*-
-#
-# Template::Manual
-#
-# DESCRIPTION
-#   This is the comprehensive user guide and reference manual for the
-#   Template Toolkit.
-#
-# AUTHOR
-#   Andy Wardley  <abw@andywardley.com>
-#
-# COPYRIGHT
-#   Copyright (C) 1996-2001 Andy Wardley.  All Rights Reserved.
-#   Copyright (C) 1998-2001 Canon Research Centre Europe Ltd.
-#
-#   This module is free software; you can redistribute it and/or
-#   modify it under the same terms as Perl itself.
-#
-# REVISION
-#   
-#
-#========================================================================
-
-
-#------------------------------------------------------------------------
-# IMPORTANT NOTE
-#   This documentation is generated automatically from source
-#   templates.  Any changes you make here may be lost.
-# 
-#   The 'docsrc' documentation source bundle is available for download
-#   from http://www.template-toolkit.org/docs.html and contains all
-#   the source templates, XML files, scripts, etc., from which the
-#   documentation for the Template Toolkit is built.
-#------------------------------------------------------------------------
-
-=head1 NAME
-
-Template::Manual - User guide and reference manual for the Template Toolkit
-
-=head1 DESCRIPTION
-
-This is the comprehensive user guide and reference manual for the
-Template Toolkit.
-
-=over 4
-
-=item L<Template::Manual::Intro|Template::Manual::Intro>
-
-Introduction to the Template Toolkit
-
-This section provides a general introduction to the Template Toolkit,
-giving a quick overview of features, examples of template directives
-and use of the Template.pm module. It also described the basic concept
-underlying the toolkit: the separation of presentation elements from
-application logic and data.
-
-=item L<Template::Manual::Syntax|Template::Manual::Syntax>
-
-Directive syntax, structure and semantics
-
-This section describes the syntax, structure and semantics of the
-Template Toolkit directives and general presentation language.
-
-=item L<Template::Manual::Directives|Template::Manual::Directives>
-
-Template directives
-
-This section provides a reference of all Template Toolkit directives,
-complete with examples of use.
-
-=item L<Template::Manual::Variables|Template::Manual::Variables>
-
-Template variables and code bindings
-
-This section describes the different ways in which Perl data can be
-bound to template variables and accessed via Template Toolkit
-directives.
-
-=item L<Template::Manual::VMethods|Template::Manual::VMethods>
-
-Virtual Methods
-
-The Template Toolkit provides virtual methods for manipulating variable
-values. Most of them are analogous to regular Perl functions of the
-same names. This section describes the different virtual methods that
-can be applied to scalar, list and hash values.
-
-=item L<Template::Manual::Config|Template::Manual::Config>
-
-Configuration options
-
-This section contains details of all the configuration options that can
-be used to customise the behaviour and extend the features of the
-Template Toolkit.
-
-=item L<Template::Manual::Filters|Template::Manual::Filters>
-
-Standard filters
-
-This section lists all the standard filters distributed with the
-Template Toolkit for post-processing output.
-
-=item L<Template::Manual::Plugins|Template::Manual::Plugins>
-
-Standard plugins
-
-This section lists the standard plugins which can be used to extend the
-runtime functionality of the Template Toolkit. The plugins are
-distributed with the Template Toolkit but may required additional
-modules from CPAN.
-
-=item L<Template::Manual::Internals|Template::Manual::Internals>
-
-Template Toolkit internals
-
-This document provides an overview of the internal architecture of the
-Template Toolkit. It is a work in progress and is far from complete,
-currently providing little more than an overview of how the major
-components fit together. Nevertheless, it's a good starting point for
-anyone wishing to delve into the source code to find out how it all
-works.
-
-=item L<Template::Manual::Views|Template::Manual::Views>
-
-Template Toolkit views (experimental)
-
-This section describes dynamic views: a powerful but experimental new
-feature in version 2.01 of the Template Toolkit.
-
-=item L<Template::Manual::Refs|Template::Manual::Refs>
-
-Related modules, projects and other resources
-
-This section provides references to external modules, projects and
-other resources related to the Template Toolkit.
-
-=item L<Template::Manual::Credits|Template::Manual::Credits>
-
-Author and contributor credits
-
-This section provides a brief history of the Template Toolkit and
-details the primary author and numerous other people who have
-contributed to it.
-
-
-
-=back
-
-=head1 AUTHOR
-
-Andy Wardley E<lt>abw@andywardley.comE<gt>
-
-L<http://www.andywardley.com/|http://www.andywardley.com/>
-
-
-
-
-=head1 VERSION
-
-Template Toolkit version 2.13, released on 30 January 2004.
-
-=head1 COPYRIGHT
-
-  Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
-  Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
-
-This module is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
-
-
-
-=cut
-
-# Local Variables:
-# mode: perl
-# perl-indent-level: 4
-# indent-tabs-mode: nil
-# End:
-#
-# vim: expandtab shiftwidth=4:
diff --git a/lib/Template/Manual/Config.pod b/lib/Template/Manual/Config.pod
deleted file mode 100644
index 5020556..0000000
--- a/lib/Template/Manual/Config.pod
+++ /dev/null
@@ -1,2122 +0,0 @@
-#============================================================= -*-perl-*-
-#
-# Template::Manual::Config
-#
-# DESCRIPTION
-#   This section contains details of all the configuration options that
-#   can be used to customise the behaviour and extend the features of
-#   the Template Toolkit.
-#
-# AUTHOR
-#   Andy Wardley  <abw@andywardley.com>
-#
-# COPYRIGHT
-#   Copyright (C) 1996-2001 Andy Wardley.  All Rights Reserved.
-#   Copyright (C) 1998-2001 Canon Research Centre Europe Ltd.
-#
-#   This module is free software; you can redistribute it and/or
-#   modify it under the same terms as Perl itself.
-#
-# REVISION
-#   
-#
-#========================================================================
-
-
-#------------------------------------------------------------------------
-# IMPORTANT NOTE
-#   This documentation is generated automatically from source
-#   templates.  Any changes you make here may be lost.
-# 
-#   The 'docsrc' documentation source bundle is available for download
-#   from http://www.template-toolkit.org/docs.html and contains all
-#   the source templates, XML files, scripts, etc., from which the
-#   documentation for the Template Toolkit is built.
-#------------------------------------------------------------------------
-
-=head1 NAME
-
-Template::Manual::Config - Configuration options
-
-=head1 DESCRIPTION
-
-This section contains details of all the configuration options that can
-be used to customise the behaviour and extend the features of the
-Template Toolkit.
-
-=head2 Template Style and Parsing Options
-
-=over 4
-
-
-
-=item START_TAG, END_TAG
-
-The START_TAG and END_TAG options are used to specify character
-sequences or regular expressions that mark the start and end of a
-template directive.  The default values for START_TAG and END_TAG are
-'[%' and '%]' respectively, giving us the familiar directive style:
-
-    [% example %]
-
-Any Perl regex characters can be used and therefore should be escaped
-(or use the Perl C<quotemeta> function) if they are intended to
-represent literal characters.
-
-    my $template = Template->new({ 
-  	START_TAG => quotemeta('<+'),
-  	END_TAG   => quotemeta('+>'),
-    });
-
-example:
-
-    <+ INCLUDE foobar +>
-
-The TAGS directive can also be used to set the START_TAG and END_TAG values
-on a per-template file basis.
-
-    [% TAGS <+ +> %]
-
-
-
-
-
-
-=item TAG_STYLE
-
-The TAG_STYLE option can be used to set both START_TAG and END_TAG
-according to pre-defined tag styles.  
-
-    my $template = Template->new({ 
-  	TAG_STYLE => 'star',
-    });
-
-Available styles are:
-
-    template    [% ... %]               (default)
-    template1   [% ... %] or %% ... %%  (TT version 1)
-    metatext    %% ... %%               (Text::MetaText)
-    star        [* ... *]               (TT alternate)
-    php         <? ... ?>               (PHP)
-    asp         <% ... %>               (ASP)
-    mason       <% ...  >               (HTML::Mason)
-    html        <!-- ... -->            (HTML comments)
-
-Any values specified for START_TAG and/or END_TAG will over-ride
-those defined by a TAG_STYLE.  
-
-The TAGS directive may also be used to set a TAG_STYLE
-
-    [% TAGS html %]
-    <!-- INCLUDE header -->
-
-
-
-
-
-
-=item PRE_CHOMP, POST_CHOMP
-
-Anything outside a directive tag is considered plain text and is
-generally passed through unaltered (but see the INTERPOLATE option).
-This includes all whitespace and newlines characters surrounding
-directive tags.  Directives that don't generate any output will leave
-gaps in the output document.
-
-Example:
-
-    Foo
-    [% a = 10 %]
-    Bar
-
-Output:
-
-    Foo
-
-    Bar
-
-The PRE_CHOMP and POST_CHOMP options can help to clean up some of this
-extraneous whitespace.  Both are disabled by default.
-
-    my $template = Template->new({
-	PRE_CHOMP  => 1,
-	POST_CHOMP => 1,
-    });
-
-With PRE_CHOMP set to 1, the newline and whitespace preceding a directive
-at the start of a line will be deleted.  This has the effect of 
-concatenating a line that starts with a directive onto the end of the 
-previous line.
-
- 	Foo <----------.
- 		       |
-    ,---(PRE_CHOMP)----'
-    |
-    `-- [% a = 10 %] --.
- 		       |
-    ,---(POST_CHOMP)---'
-    |
-    `-> Bar
-
-With POST_CHOMP set to 1, any whitespace after a directive up to and
-including the newline will be deleted.  This has the effect of joining
-a line that ends with a directive onto the start of the next line.
-
-If PRE_CHOMP or POST_CHOMP is set to 2, then instead of removing all
-the whitespace, the whitespace will be collapsed to a single space.
-This is useful for HTML, where (usually) a contiguous block of
-whitespace is rendered the same as a single space.
-
-You may use the CHOMP_NONE, CHOMP_ALL, and CHOMP_COLLAPSE constants
-from the Template::Constants module to deactivate chomping, remove
-all whitespace, or collapse whitespace to a single space.
-
-PRE_CHOMP and POST_CHOMP can be activated for individual directives by
-placing a '-' immediately at the start and/or end of the directive.
-
-    [% FOREACH user = userlist %]
-       [%- user -%]
-    [% END %]
-
-The '-' characters activate both PRE_CHOMP and POST_CHOMP for the one
-directive '[%- name -%]'.  Thus, the template will be processed as if
-written:
-
-    [% FOREACH user = userlist %][% user %][% END %]
-
-Note that this is the same as if PRE_CHOMP and POST_CHOMP were set
-to CHOMP_ALL; the only way to get the CHOMP_COLLAPSE behavior is
-to set PRE_CHOMP or POST_CHOMP accordingly.  If PRE_CHOMP or POST_CHOMP
-is already set to CHOMP_COLLAPSE, using '-' will give you CHOMP_COLLAPSE
-behavior, not CHOMP_ALL behavior.
-
-Similarly, '+' characters can be used to disable PRE_CHOMP or
-POST_CHOMP (i.e.  leave the whitespace/newline intact) options on a
-per-directive basis.
-
-    [% FOREACH user = userlist %]
-    User: [% user +%]
-    [% END %]
-
-With POST_CHOMP enabled, the above example would be parsed as if written:
-
-    [% FOREACH user = userlist %]User: [% user %]
-    [% END %]
-
-
-
-
-
-=item TRIM
-
-The TRIM option can be set to have any leading and trailing whitespace 
-automatically removed from the output of all template files and BLOCKs.
-
-By example, the following BLOCK definition
-
-    [% BLOCK foo %]
-    Line 1 of foo
-    [% END %]
-
-will be processed is as "\nLine 1 of foo\n".  When INCLUDEd, the surrounding
-newlines will also be introduced.
-
-    before 
-    [% INCLUDE foo %]
-    after
-
-output:
-    before
-
-    Line 1 of foo
-
-    after
-
-With the TRIM option set to any true value, the leading and trailing
-newlines (which count as whitespace) will be removed from the output 
-of the BLOCK.
-
-    before
-    Line 1 of foo
-    after
-
-The TRIM option is disabled (0) by default.
-
-
-
-
-
-=item INTERPOLATE
-
-The INTERPOLATE flag, when set to any true value will cause variable 
-references in plain text (i.e. not surrounded by START_TAG and END_TAG)
-to be recognised and interpolated accordingly.  
-
-    my $template = Template->new({ 
-  	INTERPOLATE => 1,
-    });
-
-Variables should be prefixed by a '$' to identify them.  Curly braces
-can be used in the familiar Perl/shell style to explicitly scope the
-variable name where required.
-
-    # INTERPOLATE => 0
-    <a href="http://[% server %]/[% help %]">
-    <img src="[% images %]/help.gif"></a>
-    [% myorg.name %]
-  
-    # INTERPOLATE => 1
-    <a href="http://$server/$help">
-    <img src="$images/help.gif"></a>
-    $myorg.name
-  
-    # explicit scoping with {  }
-    <img src="$images/${icon.next}.gif">
-
-Note that a limitation in Perl's regex engine restricts the maximum length
-of an interpolated template to around 32 kilobytes or possibly less.  Files
-that exceed this limit in size will typically cause Perl to dump core with
-a segmentation fault.  If you routinely process templates of this size 
-then you should disable INTERPOLATE or split the templates in several 
-smaller files or blocks which can then be joined backed together via 
-PROCESS or INCLUDE.
-
-
-
-
-
-
-
-=item ANYCASE
-
-By default, directive keywords should be expressed in UPPER CASE.  The 
-ANYCASE option can be set to allow directive keywords to be specified
-in any case.
-
-    # ANYCASE => 0 (default)
-    [% INCLUDE foobar %]	# OK
-    [% include foobar %]        # ERROR
-    [% include = 10   %]        # OK, 'include' is a variable
-
-    # ANYCASE => 1
-    [% INCLUDE foobar %]	# OK
-    [% include foobar %]	# OK
-    [% include = 10   %]        # ERROR, 'include' is reserved word
-
-One side-effect of enabling ANYCASE is that you cannot use a variable
-of the same name as a reserved word, regardless of case.  The reserved
-words are currently:
-
-        GET CALL SET DEFAULT INSERT INCLUDE PROCESS WRAPPER 
-    IF UNLESS ELSE ELSIF FOR FOREACH WHILE SWITCH CASE
-    USE PLUGIN FILTER MACRO PERL RAWPERL BLOCK META
-    TRY THROW CATCH FINAL NEXT LAST BREAK RETURN STOP 
-    CLEAR TO STEP AND OR NOT MOD DIV END
-
-
-The only lower case reserved words that cannot be used for variables,
-regardless of the ANYCASE option, are the operators:
-
-    and or not mod div
-
-
-
-
-
-
-=back
-
-=head2 Template Files and Blocks
-
-=over 4
-
-
-
-=item INCLUDE_PATH
-
-The INCLUDE_PATH is used to specify one or more directories in which
-template files are located.  When a template is requested that isn't
-defined locally as a BLOCK, each of the INCLUDE_PATH directories is
-searched in turn to locate the template file.  Multiple directories
-can be specified as a reference to a list or as a single string where
-each directory is delimited by ':'.
-
-    my $template = Template->new({
-        INCLUDE_PATH => '/usr/local/templates',
-    });
-  
-    my $template = Template->new({
-        INCLUDE_PATH => '/usr/local/templates:/tmp/my/templates',
-    });
-  
-    my $template = Template->new({
-        INCLUDE_PATH => [ '/usr/local/templates', 
-                          '/tmp/my/templates' ],
-    });
-
-On Win32 systems, a little extra magic is invoked, ignoring delimiters
-that have ':' followed by a '/' or '\'.  This avoids confusion when using
-directory names like 'C:\Blah Blah'.
-
-When specified as a list, the INCLUDE_PATH path can contain elements 
-which dynamically generate a list of INCLUDE_PATH directories.  These 
-generator elements can be specified as a reference to a subroutine or 
-an object which implements a paths() method.
-
-    my $template = Template->new({
-        INCLUDE_PATH => [ '/usr/local/templates', 
-                          \&incpath_generator, 
-			  My::IncPath::Generator->new( ... ) ],
-    });
-
-Each time a template is requested and the INCLUDE_PATH examined, the
-subroutine or object method will be called.  A reference to a list of
-directories should be returned.  Generator subroutines should report
-errors using die().  Generator objects should return undef and make an
-error available via its error() method.
-
-For example:
-
-    sub incpath_generator {
-
-	# ...some code...
-	
-	if ($all_is_well) {
-	    return \@list_of_directories;
-	}
-	else {
-	    die "cannot generate INCLUDE_PATH...\n";
-	}
-    }
-
-or:
-
-    package My::IncPath::Generator;
-
-    # Template::Base (or Class::Base) provides error() method
-    use Template::Base;
-    use base qw( Template::Base );
-
-    sub paths {
-	my $self = shift;
-
-	# ...some code...
-
-        if ($all_is_well) {
-	    return \@list_of_directories;
-	}
-	else {
-	    return $self->error("cannot generate INCLUDE_PATH...\n");
-	}
-    }
-
-    1;
-
-
-
-
-
-=item DELIMITER
-
-Used to provide an alternative delimiter character sequence for 
-separating paths specified in the INCLUDE_PATH.  The default
-value for DELIMITER is ':'.
-
-    # tolerate Silly Billy's file system conventions
-    my $template = Template->new({
-	DELIMITER    => '; ',
-        INCLUDE_PATH => 'C:/HERE/NOW; D:/THERE/THEN',
-    });
-
-    # better solution: install Linux!  :-)
-
-On Win32 systems, the default delimiter is a little more intelligent,
-splitting paths only on ':' characters that aren't followed by a '/'.
-This means that the following should work as planned, splitting the 
-INCLUDE_PATH into 2 separate directories, C:/foo and C:/bar.
-
-    # on Win32 only
-    my $template = Template->new({
-	INCLUDE_PATH => 'C:/Foo:C:/Bar'
-    });
-
-However, if you're using Win32 then it's recommended that you
-explicitly set the DELIMITER character to something else (e.g. ';')
-rather than rely on this subtle magic.
-
-
-
-
-=item ABSOLUTE
-
-The ABSOLUTE flag is used to indicate if templates specified with
-absolute filenames (e.g. '/foo/bar') should be processed.  It is
-disabled by default and any attempt to load a template by such a
-name will cause a 'file' exception to be raised.
-
-    my $template = Template->new({
-	ABSOLUTE => 1,
-    });
-
-    # this is why it's disabled by default
-    [% INSERT /etc/passwd %]
-
-On Win32 systems, the regular expression for matching absolute 
-pathnames is tweaked slightly to also detect filenames that start
-with a driver letter and colon, such as:
-
-    C:/Foo/Bar
-
-
-
-
-
-
-=item RELATIVE
-
-The RELATIVE flag is used to indicate if templates specified with
-filenames relative to the current directory (e.g. './foo/bar' or
-'../../some/where/else') should be loaded.  It is also disabled by
-default, and will raise a 'file' error if such template names are
-encountered.  
-
-    my $template = Template->new({
-	RELATIVE => 1,
-    });
-
-    [% INCLUDE ../logs/error.log %]
-
-
-
-
-
-=item DEFAULT
-
-The DEFAULT option can be used to specify a default template which should 
-be used whenever a specified template can't be found in the INCLUDE_PATH.
-
-    my $template = Template->new({
-	DEFAULT => 'notfound.html',
-    });
-
-If a non-existant template is requested through the Template process()
-method, or by an INCLUDE, PROCESS or WRAPPER directive, then the
-DEFAULT template will instead be processed, if defined.  Note that the
-DEFAULT template is not used when templates are specified with
-absolute or relative filenames, or as a reference to a input file
-handle or text string.
-
-
-
-
-
-=item BLOCKS
-
-The BLOCKS option can be used to pre-define a default set of template 
-blocks.  These should be specified as a reference to a hash array 
-mapping template names to template text, subroutines or Template::Document
-objects.
-
-    my $template = Template->new({
-	BLOCKS => {
-	    header  => 'The Header.  [% title %]',
-	    footer  => sub { return $some_output_text },
-	    another => Template::Document->new({ ... }),
-	},
-    }); 
-
-
-
-
-=item AUTO_RESET
-
-The AUTO_RESET option is set by default and causes the local BLOCKS
-cache for the Template::Context object to be reset on each call to the
-Template process() method.  This ensures that any BLOCKs defined
-within a template will only persist until that template is finished
-processing.  This prevents BLOCKs defined in one processing request
-from interfering with other independent requests subsequently
-processed by the same context object.
-
-The BLOCKS item may be used to specify a default set of block definitions
-for the Template::Context object.  Subsequent BLOCK definitions in templates
-will over-ride these but they will be reinstated on each reset if AUTO_RESET
-is enabled (default), or if the Template::Context reset() method is called.
-
-
-
-
-
-
-
-
-
-=item RECURSION
-
-The template processor will raise a file exception if it detects
-direct or indirect recursion into a template.  Setting this option to 
-any true value will allow templates to include each other recursively.
-
-
-
-=back
-
-=head2 Template Variables
-
-=over 4
-
-=item VARIABLES, PRE_DEFINE
-
-The VARIABLES option (or PRE_DEFINE - they're equivalent) can be used
-to specify a hash array of template variables that should be used to
-pre-initialise the stash when it is created.  These items are ignored
-if the STASH item is defined.
-
-    my $template = Template->new({
-	VARIABLES => {
-	    title   => 'A Demo Page',
-	    author  => 'Joe Random Hacker',
-	    version => 3.14,
-	},
-    };
-
-or
-
-    my $template = Template->new({
-	PRE_DEFINE => {
-	    title   => 'A Demo Page',
-	    author  => 'Joe Random Hacker',
-	    version => 3.14,
-	},
-    };
-
-
-
-
-=item CONSTANTS
-
-The CONSTANTS option can be used to specify a hash array of template
-variables that are compile-time constants.  These variables are
-resolved once when the template is compiled, and thus don't require
-further resolution at runtime.  This results in significantly faster
-processing of the compiled templates and can be used for variables that
-don't change from one request to the next.
-
-    my $template = Template->new({
-	CONSTANTS => {
-	    title   => 'A Demo Page',
-	    author  => 'Joe Random Hacker',
-	    version => 3.14,
-	},
-    };
-
-=item CONSTANT_NAMESPACE
-
-Constant variables are accessed via the 'constants' namespace by
-default.
-
-    [% constants.title %]
-
-The CONSTANTS_NAMESPACE option can be set to specify an alternate
-namespace.
-
-    my $template = Template->new({
-	CONSTANTS => {
-	    title   => 'A Demo Page',
-	    # ...etc...
-	},
-	CONSTANTS_NAMESPACE => 'const',
-    };
-
-In this case the constants would then be accessed as:
-
-    [% const.title %]
-
-=item NAMESPACE
-
-The constant folding mechanism described above is an example of a
-namespace handler.  Namespace handlers can be defined to provide
-alternate parsing mechanisms for variables in different namespaces.
-
-Under the hood, the Template module converts a constructor configuration
-such as:
-
-    my $template = Template->new({
-	CONSTANTS => {
-	    title   => 'A Demo Page',
-	    # ...etc...
-	},
-	CONSTANTS_NAMESPACE => 'const',
-    };
-
-into one like:
-
-    my $template = Template->new({
-	NAMESPACE => {
-	    const => Template:::Namespace::Constants->new({
-		title   => 'A Demo Page',
-		# ...etc...
-	    }),
-	},
-    };
-
-You can use this mechanism to define multiple constant namespaces, or
-to install custom handlers of your own.  
-
-    my $template = Template->new({
-	NAMESPACE => {
-	    site => Template:::Namespace::Constants->new({
-		title   => "Wardley's Widgets",
-		version => 2.718,
-	    }),
-	    author => Template:::Namespace::Constants->new({
-		name  => 'Andy Wardley',
-		email => 'abw@andywardley.com',
-	    }),
-	    voodoo => My::Namespace::Handler->new( ... ),
-	},
-    };
-
-Now you have 2 constant namespaces, for example:
-
-    [% site.title %]
-    [% author.name %]
-
-as well as your own custom namespace handler installed for the 'voodoo'
-namespace.
-
-    [% voodoo.magic %]
-
-See L<Template::Namespace::Constants|Template::Namespace::Constants>
-for an example of what a namespace handler looks like on the inside.
-
-
-
-
-
-=back
-
-=head2 Template Processing Options
-
-
-The following options are used to specify any additional templates
-that should be processed before, after, around or instead of the
-template passed as the first argument to the Template process()
-method.  These options can be perform various useful tasks such as
-adding standard headers or footers to all pages, wrapping page output
-in other templates, pre-defining variables or performing
-initialisation or cleanup tasks, automatically generating page summary
-information, navigation elements, and so on.
-
-The task of processing the template is delegated internally to the
-Template::Service module which, unsurprisingly, also has a process()
-method.  Any templates defined by the PRE_PROCESS option are processed
-first and any output generated is added to the output buffer.  Then
-the main template is processed, or if one or more PROCESS templates
-are defined then they are instead processed in turn.  In this case,
-one of the PROCESS templates is responsible for processing the main
-template, by a directive such as:
-
-    [% PROCESS $template %]
-
-The output of processing the main template or the PROCESS template(s)
-is then wrapped in any WRAPPER templates, if defined.  WRAPPER
-templates don't need to worry about explicitly processing the template
-because it will have been done for them already.  Instead WRAPPER
-templates access the content they are wrapping via the 'content'
-variable.
-
-    wrapper before
-    [% content %]
-    wrapper after
-
-This output generated from processing the main template, and/or any
-PROCESS or WRAPPER templates is added to the output buffer.  Finally,
-any POST_PROCESS templates are processed and their output is also
-added to the output buffer which is then returned.
-
-If the main template throws an exception during processing then any
-relevant template(s) defined via the ERROR option will be processed
-instead.  If defined and successfully processed, the output from the
-error template will be added to the output buffer in place of the
-template that generated the error and processing will continue,
-applying any WRAPPER and POST_PROCESS templates.  If no relevant ERROR
-option is defined, or if the error occurs in one of the PRE_PROCESS,
-WRAPPER or POST_PROCESS templates, then the process will terminate
-immediately and the error will be returned.
-
-
-
-=over 4
-
-
-
-=item PRE_PROCESS, POST_PROCESS
-
-These values may be set to contain the name(s) of template files
-(relative to INCLUDE_PATH) which should be processed immediately
-before and/or after each template.  These do not get added to 
-templates processed into a document via directives such as INCLUDE, 
-PROCESS, WRAPPER etc.
-
-    my $template = Template->new({
-	PRE_PROCESS  => 'header',
-	POST_PROCESS => 'footer',
-    };
-
-Multiple templates may be specified as a reference to a list.  Each is 
-processed in the order defined.
-
-    my $template = Template->new({
-	PRE_PROCESS  => [ 'config', 'header' ],
-	POST_PROCESS => 'footer',
-    };
-
-Alternately, multiple template may be specified as a single string, 
-delimited by ':'.  This delimiter string can be changed via the 
-DELIMITER option.
-
-    my $template = Template->new({
-	PRE_PROCESS  => 'config:header',
-	POST_PROCESS => 'footer',
-    };
-
-The PRE_PROCESS and POST_PROCESS templates are evaluated in the same
-variable context as the main document and may define or update
-variables for subsequent use.
-
-config:
-
-    [% # set some site-wide variables
-       bgcolor = '#ffffff'
-       version = 2.718
-    %]
-
-header:
-
-    [% DEFAULT title = 'My Funky Web Site' %]
-    <html>
-    <head>
-    <title>[% title %]
-    
-    
-
-footer:
-
-    
- Version [% version %] - - - -The Template::Document object representing the main template being processed -is available within PRE_PROCESS and POST_PROCESS templates as the 'template' -variable. Metadata items defined via the META directive may be accessed -accordingly. - - $template->process('mydoc.html', $vars); - -mydoc.html: - - [% META title = 'My Document Title' %] - blah blah blah - ... - -header: - - - - [% template.title %] - - - - - - - - - - - - - - - -=item PROCESS - -The PROCESS option may be set to contain the name(s) of template files -(relative to INCLUDE_PATH) which should be processed instead of the -main template passed to the Template process() method. This can -be used to apply consistent wrappers around all templates, similar to -the use of PRE_PROCESS and POST_PROCESS templates. - - my $template = Template->new({ - PROCESS => 'content', - }; - - # processes 'content' instead of 'foo.html' - $template->process('foo.html'); - -A reference to the original template is available in the 'template' -variable. Metadata items can be inspected and the template can be -processed by specifying it as a variable reference (i.e. prefixed by -'$') to an INCLUDE, PROCESS or WRAPPER directive. - -content: - - - - [% template.title %] - - - - [% PROCESS $template %] -
- © Copyright [% template.copyright %] - - - -foo.html: - - [% META - title = 'The Foo Page' - author = 'Fred Foo' - copyright = '2000 Fred Foo' - %] -

[% template.title %]

- Welcome to the Foo Page, blah blah blah - -output: - - - - The Foo Page - - - -

The Foo Page

- Welcome to the Foo Page, blah blah blah -
- © Copyright 2000 Fred Foo - - - - - - - - - -=item WRAPPER - -The WRAPPER option can be used to specify one or more templates which -should be used to wrap around the output of the main page template. -The main template is processed first (or any PROCESS template(s)) and -the output generated is then passed as the 'content' variable to the -WRAPPER template(s) as they are processed. - - my $template = Template->new({ - WRAPPER => 'wrapper', - }; - - # process 'foo' then wrap in 'wrapper' - $template->process('foo', { message => 'Hello World!' }); - -wrapper: - - - [% content %] - - -foo: - - This is the foo file! - Message: [% message %] - -The output generated from this example is: - - - This is the foo file! - Message: Hello World! - - -You can specify more than one WRAPPER template by setting the value to -be a reference to a list of templates. The WRAPPER templates will be -processed in reverse order with the output of each being passed to the -next (or previous, depending on how you look at it) as the 'content' -variable. It sounds complicated, but the end result is that it just -"Does The Right Thing" to make wrapper templates nest in the order you -specify. - - my $template = Template->new({ - WRAPPER => [ 'outer', 'inner' ], - }; - - # process 'foo' then wrap in 'inner', then in 'outer' - $template->process('foo', { message => 'Hello World!' }); - -outer: - - - [% content %] - - -inner: - - - [% content %] - - -The output generated is then: - - - - This is the foo file! - Message: Hello World! - - - -One side-effect of the "inside-out" processing of the WRAPPER -configuration item (and also the WRAPPER directive) is that any -variables set in the template being wrapped will be visible to the -template doing the wrapping, but not the other way around. - -You can use this to good effect in allowing page templates to set -pre-defined values which are then used in the wrapper templates. For -example, our main page template 'foo' might look like this: - -foo: - - [% page = { - title = 'Foo Page' - subtitle = 'Everything There is to Know About Foo' - author = 'Frank Oliver Octagon' - } - %] - -

- Welcome to the page that tells you everything about foo - blah blah blah... -

- -The 'foo' template is processed before the wrapper template meaning -that the 'page' data structure will be defined for use in the wrapper -template. - -wrapper: - - - - [% page.title %] - - -

[% page.title %]

-

[% page.subtitle %]

-

by [% page.author %]

- - [% content %] - - - -It achieves the same effect as defining META items which are then -accessed via the 'template' variable (which you are still free to -use within WRAPPER templates), but gives you more flexibility in -the type and complexity of data that you can define. - - - - - -=item ERROR - -The ERROR (or ERRORS if you prefer) configuration item can be used to -name a single template or specify a hash array mapping exception types -to templates which should be used for error handling. If an uncaught -exception is raised from within a template then the appropriate error -template will instead be processed. - -If specified as a single value then that template will be processed -for all uncaught exceptions. - - my $template = Template->new({ - ERROR => 'error.html' - }); - -If the ERROR item is a hash reference the keys are assumed to be -exception types and the relevant template for a given exception will -be selected. A 'default' template may be provided for the general -case. Note that 'ERROR' can be pluralised to 'ERRORS' if you find -it more appropriate in this case. - - my $template = Template->new({ - ERRORS => { - user => 'user/index.html', - dbi => 'error/database', - default => 'error/default', - }, - }); - -In this example, any 'user' exceptions thrown will cause the -'user/index.html' template to be processed, 'dbi' errors are handled -by 'error/database' and all others by the 'error/default' template. -Any PRE_PROCESS and/or POST_PROCESS templates will also be applied -to these error templates. - -Note that exception types are hierarchical and a 'foo' handler will -catch all 'foo.*' errors (e.g. foo.bar, foo.bar.baz) if a more -specific handler isn't defined. Be sure to quote any exception types -that contain periods to prevent Perl concatenating them into a single -string (i.e. C is parsed as 'user'.'passwd'). - - my $template = Template->new({ - ERROR => { - 'user.login' => 'user/login.html', - 'user.passwd' => 'user/badpasswd.html', - 'user' => 'user/index.html', - 'default' => 'error/default', - }, - }); - -In this example, any template processed by the $template object, or -other templates or code called from within, can raise a 'user.login' -exception and have the service redirect to the 'user/login.html' -template. Similarly, a 'user.passwd' exception has a specific -handling template, 'user/badpasswd.html', while all other 'user' or -'user.*' exceptions cause a redirection to the 'user/index.html' page. -All other exception types are handled by 'error/default'. - - -Exceptions can be raised in a template using the THROW directive, - - [% THROW user.login 'no user id: please login' %] - -or by calling the throw() method on the current Template::Context object, - - $context->throw('user.passwd', 'Incorrect Password'); - $context->throw('Incorrect Password'); # type 'undef' - -or from Perl code by calling die() with a Template::Exception object, - - die (Template::Exception->new('user.denied', 'Invalid User ID')); - -or by simply calling die() with an error string. This is -automagically caught and converted to an exception of 'undef' -type which can then be handled in the usual way. - - die "I'm sorry Dave, I can't do that"; - - - - - - -=back - -=head2 Template Runtime Options - -=over 4 - - - - -=item EVAL_PERL - -This flag is used to indicate if PERL and/or RAWPERL blocks should be -evaluated. By default, it is disabled and any PERL or RAWPERL blocks -encountered will raise exceptions of type 'perl' with the message -'EVAL_PERL not set'. Note however that any RAWPERL blocks should -always contain valid Perl code, regardless of the EVAL_PERL flag. The -parser will fail to compile templates that contain invalid Perl code -in RAWPERL blocks and will throw a 'file' exception. - -When using compiled templates (see -L and -L), -the EVAL_PERL has an affect when the template is compiled, and again -when the templates is subsequently processed, possibly in a different -context to the one that compiled it. - -If the EVAL_PERL is set when a template is compiled, then all PERL and -RAWPERL blocks will be included in the compiled template. If the -EVAL_PERL option isn't set, then Perl code will be generated which -B throws a 'perl' exception with the message 'EVAL_PERL not -set' B the compiled template code is run. - -Thus, you must have EVAL_PERL set if you want your compiled templates -to include PERL and RAWPERL blocks. - -At some point in the future, using a different invocation of the -Template Toolkit, you may come to process such a pre-compiled -template. Assuming the EVAL_PERL option was set at the time the -template was compiled, then the output of any RAWPERL blocks will be -included in the compiled template and will get executed when the -template is processed. This will happen regardless of the runtime -EVAL_PERL status. - -Regular PERL blocks are a little more cautious, however. If the -EVAL_PERL flag isn't set for the I context, that is, the -one which is trying to process it, then it will throw the familiar 'perl' -exception with the message, 'EVAL_PERL not set'. - -Thus you can compile templates to include PERL blocks, but optionally -disable them when you process them later. Note however that it is -possible for a PERL block to contain a Perl "BEGIN { # some code }" -block which will always get run regardless of the runtime EVAL_PERL -status. Thus, if you set EVAL_PERL when compiling templates, it is -assumed that you trust the templates to Do The Right Thing. Otherwise -you must accept the fact that there's no bulletproof way to prevent -any included code from trampling around in the living room of the -runtime environment, making a real nuisance of itself if it really -wants to. If you don't like the idea of such uninvited guests causing -a bother, then you can accept the default and keep EVAL_PERL disabled. - - - - - - - -=item OUTPUT - -Default output location or handler. This may be specified as one of: -a file name (relative to OUTPUT_PATH, if defined, or the current -working directory if not specified absolutely); a file handle -(e.g. GLOB or IO::Handle) opened for writing; a reference to a text -string to which the output is appended (the string isn't cleared); a -reference to a subroutine which is called, passing the output text as -an argument; as a reference to an array, onto which the content will be -push()ed; or as a reference to any object that supports the print() -method. This latter option includes the Apache::Request object which -is passed as the argument to Apache/mod_perl handlers. - -example 1 (file name): - - my $template = Template->new({ - OUTPUT => "/tmp/foo", - }); - -example 2 (text string): - - my $output = ''; - - my $template = Template->new({ - OUTPUT => \$output, - }); - -example 3 (file handle): - - open (TOUT, "> $file") || die "$file: $!\n"; - - my $template = Template->new({ - OUTPUT => \*TOUT, - }); - -example 4 (subroutine): - - sub output { my $out = shift; print "OUTPUT: $out" } - - my $template = Template->new({ - OUTPUT => \&output, - }); - -example 5 (array reference): - - my $template = Template->new({ - OUTPUT => \@output, - }) - -example 6 (Apache/mod_perl handler): - - sub handler { - my $r = shift; - - my $t = Template->new({ - OUTPUT => $r, - }); - ... - } - -The default OUTPUT location be overridden by passing a third parameter -to the Template process() method. This can be specified as any of the -above argument types. - - $t->process($file, $vars, "/tmp/foo"); - $t->process($file, $vars, "bar"); - $t->process($file, $vars, \*MYGLOB); - $t->process($file, $vars, \@output); - $t->process($file, $vars, $r); # Apache::Request - ... - - - - - - - - -=item OUTPUT_PATH - -The OUTPUT_PATH allows a directory to be specified into which output -files should be written. An output file can be specified by the -OUTPUT option, or passed by name as the third parameter to the -Template process() method. - - my $template = Template->new({ - INCLUDE_PATH => "/tmp/src", - OUTPUT_PATH => "/tmp/dest", - }); - - my $vars = { - ... - }; - - foreach my $file ('foo.html', 'bar.html') { - $template->process($file, $vars, $file) - || die $template->error(); - } - -This example will read the input files '/tmp/src/foo.html' and -'/tmp/src/bar.html' and write the processed output to '/tmp/dest/foo.html' -and '/tmp/dest/bar.html', respectively. - - - - - - - - -=item DEBUG - -The DEBUG option can be used to enable debugging within the various -different modules that comprise the Template Toolkit. The -L module defines a set of -DEBUG_XXXX constants which can be combined using the logical OR -operator, '|'. - - use Template::Constants qw( :debug ); - - my $template = Template->new({ - DEBUG => DEBUG_PARSER | DEBUG_PROVIDER, - }); - -For convenience, you can also provide a string containing a list -of lower case debug options, separated by any non-word characters. - - my $template = Template->new({ - DEBUG => 'parser, provider', - }); - -The following DEBUG_XXXX flags can be used: - -=over 4 - -=item DEBUG_SERVICE - -Enables general debugging messages for the -L module. - -=item DEBUG_CONTEXT - -Enables general debugging messages for the -L module. - -=item DEBUG_PROVIDER - -Enables general debugging messages for the -L module. - -=item DEBUG_PLUGINS - -Enables general debugging messages for the -L module. - -=item DEBUG_FILTERS - -Enables general debugging messages for the -L module. - -=item DEBUG_PARSER - -This flag causes the L to generate -debugging messages that show the Perl code generated by parsing and -compiling each template. - -=item DEBUG_UNDEF - -This option causes the Template Toolkit to throw an 'undef' error -whenever it encounters an undefined variable value. - -=item DEBUG_DIRS - -This option causes the Template Toolkit to generate comments -indicating the source file, line and original text of each directive -in the template. These comments are embedded in the template output -using the format defined in the DEBUG_FORMAT configuration item, or a -simple default format if unspecified. - -For example, the following template fragment: - - - Hello World - -would generate this output: - - ## input text line 1 : ## - Hello - ## input text line 2 : World ## - World - -=item DEBUG_ALL - -Enables all debugging messages. - -=item DEBUG_CALLER - -This option causes all debug messages that aren't newline terminated -to have the file name and line number of the caller appended to them. - - -=back - -=item DEBUG_FORMAT - -The DEBUG_FORMAT option can be used to specify a format string for the -debugging messages generated via the DEBUG_DIRS option described -above. Any occurances of C<$file>, C<$line> or C<$text> will be -replaced with the current file name, line or directive text, -respectively. Notice how the format is single quoted to prevent Perl -from interpolating those tokens as variables. - - my $template = Template->new({ - DEBUG => 'dirs', - DEBUG_FORMAT => '', - }); - -The following template fragment: - - [% foo = 'World' %] - Hello [% foo %] - -would then generate this output: - - - Hello World - -The DEBUG directive can also be used to set a debug format within -a template. - - [% DEBUG format '' %] - - -=back - -=head2 Caching and Compiling Options - -=over 4 - - - -=item CACHE_SIZE - -The Template::Provider module caches compiled templates to avoid the need -to re-parse template files or blocks each time they are used. The CACHE_SIZE -option is used to limit the number of compiled templates that the module -should cache. - -By default, the CACHE_SIZE is undefined and all compiled templates are -cached. When set to any positive value, the cache will be limited to -storing no more than that number of compiled templates. When a new -template is loaded and compiled and the cache is full (i.e. the number -of entries == CACHE_SIZE), the least recently used compiled template -is discarded to make room for the new one. - -The CACHE_SIZE can be set to 0 to disable caching altogether. - - my $template = Template->new({ - CACHE_SIZE => 64, # only cache 64 compiled templates - }); - - my $template = Template->new({ - CACHE_SIZE => 0, # don't cache any compiled templates - }); - - - - - - -=item COMPILE_EXT - -From version 2 onwards, the Template Toolkit has the ability to -compile templates to Perl code and save them to disk for subsequent -use (i.e. cache persistence). The COMPILE_EXT option may be -provided to specify a filename extension for compiled template files. -It is undefined by default and no attempt will be made to read or write -any compiled template files. - - my $template = Template->new({ - COMPILE_EXT => '.ttc', - }); - -If COMPILE_EXT is defined (and COMPILE_DIR isn't, see below) then compiled -template files with the COMPILE_EXT extension will be written to the same -directory from which the source template files were loaded. - -Compiling and subsequent reuse of templates happens automatically -whenever the COMPILE_EXT or COMPILE_DIR options are set. The Template -Toolkit will automatically reload and reuse compiled files when it -finds them on disk. If the corresponding source file has been modified -since the compiled version as written, then it will load and re-compile -the source and write a new compiled version to disk. - -This form of cache persistence offers significant benefits in terms of -time and resources required to reload templates. Compiled templates can -be reloaded by a simple call to Perl's require(), leaving Perl to handle -all the parsing and compilation. This is a Good Thing. - -=item COMPILE_DIR - -The COMPILE_DIR option is used to specify an alternate directory root -under which compiled template files should be saved. - - my $template = Template->new({ - COMPILE_DIR => '/tmp/ttc', - }); - -The COMPILE_EXT option may also be specified to have a consistent file -extension added to these files. - - my $template1 = Template->new({ - COMPILE_DIR => '/tmp/ttc', - COMPILE_EXT => '.ttc1', - }); - - my $template2 = Template->new({ - COMPILE_DIR => '/tmp/ttc', - COMPILE_EXT => '.ttc2', - }); - - -When COMPILE_EXT is undefined, the compiled template files have the -same name as the original template files, but reside in a different -directory tree. - -Each directory in the INCLUDE_PATH is replicated in full beneath the -COMPILE_DIR directory. This example: - - my $template = Template->new({ - COMPILE_DIR => '/tmp/ttc', - INCLUDE_PATH => '/home/abw/templates:/usr/share/templates', - }); - -would create the following directory structure: - - /tmp/ttc/home/abw/templates/ - /tmp/ttc/usr/share/templates/ - -Files loaded from different INCLUDE_PATH directories will have their -compiled forms save in the relevant COMPILE_DIR directory. - -On Win32 platforms a filename may by prefixed by a drive letter and -colon. e.g. - - C:/My Templates/header - -The colon will be silently stripped from the filename when it is added -to the COMPILE_DIR value(s) to prevent illegal filename being generated. -Any colon in COMPILE_DIR elements will be left intact. For example: - - # Win32 only - my $template = Template->new({ - DELIMITER => ';', - COMPILE_DIR => 'C:/TT2/Cache', - INCLUDE_PATH => 'C:/TT2/Templates;D:/My Templates', - }); - -This would create the following cache directories: - - C:/TT2/Cache/C/TT2/Templates - C:/TT2/Cache/D/My Templates - - -=back - -=head2 Plugins and Filters - -=over 4 - - - -=item PLUGINS - -The PLUGINS options can be used to provide a reference to a hash array -that maps plugin names to Perl module names. A number of standard -plugins are defined (e.g. 'table', 'cgi', 'dbi', etc.) which map to -their corresponding Template::Plugin::* counterparts. These can be -redefined by values in the PLUGINS hash. - - my $template = Template->new({ - PLUGINS => { - cgi => 'MyOrg::Template::Plugin::CGI', - foo => 'MyOrg::Template::Plugin::Foo', - bar => 'MyOrg::Template::Plugin::Bar', - }, - }); - -The USE directive is used to create plugin objects and does so by -calling the plugin() method on the current Template::Context object. -If the plugin name is defined in the PLUGINS hash then the -corresponding Perl module is loaded via require(). The context then -calls the load() class method which should return the class name -(default and general case) or a prototype object against which the -new() method can be called to instantiate individual plugin objects. - -If the plugin name is not defined in the PLUGINS hash then the PLUGIN_BASE -and/or LOAD_PERL options come into effect. - - - - - -=item PLUGIN_BASE - -If a plugin is not defined in the PLUGINS hash then the PLUGIN_BASE is used -to attempt to construct a correct Perl module name which can be successfully -loaded. - -The PLUGIN_BASE can be specified as a single value or as a reference -to an array of multiple values. The default PLUGIN_BASE value, -'Template::Plugin', is always added the the end of the PLUGIN_BASE -list (a single value is first converted to a list). Each value should -contain a Perl package name to which the requested plugin name is -appended. - -example 1: - - my $template = Template->new({ - PLUGIN_BASE => 'MyOrg::Template::Plugin', - }); - - [% USE Foo %] # => MyOrg::Template::Plugin::Foo - or Template::Plugin::Foo - -example 2: - - my $template = Template->new({ - PLUGIN_BASE => [ 'MyOrg::Template::Plugin', - 'YourOrg::Template::Plugin' ], - }); - - [% USE Foo %] # => MyOrg::Template::Plugin::Foo - or YourOrg::Template::Plugin::Foo - or Template::Plugin::Foo - - - - - - -=item LOAD_PERL - -If a plugin cannot be loaded using the PLUGINS or PLUGIN_BASE -approaches then the provider can make a final attempt to load the -module without prepending any prefix to the module path. This allows -regular Perl modules (i.e. those that don't reside in the -Template::Plugin or some other such namespace) to be loaded and used -as plugins. - -By default, the LOAD_PERL option is set to 0 and no attempt will be made -to load any Perl modules that aren't named explicitly in the PLUGINS -hash or reside in a package as named by one of the PLUGIN_BASE -components. - -Plugins loaded using the PLUGINS or PLUGIN_BASE receive a reference to -the current context object as the first argument to the new() -constructor. Modules loaded using LOAD_PERL are assumed to not -conform to the plugin interface. They must provide a new() class -method for instantiating objects but it will not receive a reference -to the context as the first argument. Plugin modules should provide a -load() class method (or inherit the default one from the -Template::Plugin base class) which is called the first time the plugin -is loaded. Regular Perl modules need not. In all other respects, -regular Perl objects and Template Toolkit plugins are identical. - -If a particular Perl module does not conform to the common, but not -unilateral, new() constructor convention then a simple plugin wrapper -can be written to interface to it. - - - - -=item FILTERS - -The FILTERS option can be used to specify custom filters which can -then be used with the FILTER directive like any other. These are -added to the standard filters which are available by default. Filters -specified via this option will mask any standard filters of the same -name. - -The FILTERS option should be specified as a reference to a hash array -in which each key represents the name of a filter. The corresponding -value should contain a reference to an array containing a subroutine -reference and a flag which indicates if the filter is static (0) or -dynamic (1). A filter may also be specified as a solitary subroutine -reference and is assumed to be static. - - $template = Template->new({ - FILTERS => { - 'sfilt1' => \&static_filter, # static - 'sfilt2' => [ \&static_filter, 0 ], # same as above - 'dfilt1' => [ \&dyanamic_filter_factory, 1 ], - }, - }); - -Additional filters can be specified at any time by calling the -define_filter() method on the current Template::Context object. -The method accepts a filter name, a reference to a filter -subroutine and an optional flag to indicate if the filter is -dynamic. - - my $context = $template->context(); - $context->define_filter('new_html', \&new_html); - $context->define_filter('new_repeat', \&new_repeat, 1); - -Static filters are those where a single subroutine reference is used -for all invocations of a particular filter. Filters that don't accept -any configuration parameters (e.g. 'html') can be implemented -statically. The subroutine reference is simply returned when that -particular filter is requested. The subroutine is called to filter -the output of a template block which is passed as the only argument. -The subroutine should return the modified text. - - sub static_filter { - my $text = shift; - # do something to modify $text... - return $text; - } - -The following template fragment: - - [% FILTER sfilt1 %] - Blah blah blah. - [% END %] - -is approximately equivalent to: - - &static_filter("\nBlah blah blah.\n"); - -Filters that can accept parameters (e.g. 'truncate') should be -implemented dynamically. In this case, the subroutine is taken to be -a filter 'factory' that is called to create a unique filter subroutine -each time one is requested. A reference to the current -Template::Context object is passed as the first parameter, followed by -any additional parameters specified. The subroutine should return -another subroutine reference (usually a closure) which implements the -filter. - - sub dynamic_filter_factory { - my ($context, @args) = @_; - - return sub { - my $text = shift; - # do something to modify $text... - return $text; - } - } - -The following template fragment: - - [% FILTER dfilt1(123, 456) %] - Blah blah blah - [% END %] - -is approximately equivalent to: - - my $filter = &dynamic_filter_factory($context, 123, 456); - &$filter("\nBlah blah blah.\n"); - -See the FILTER directive for further examples. - - -=back - -=head2 Compatibility, Customisation and Extension - -=over 4 - - - -=item V1DOLLAR - -In version 1 of the Template Toolkit, an optional leading '$' could be placed -on any template variable and would be silently ignored. - - # VERSION 1 - [% $foo %] === [% foo %] - [% $hash.$key %] === [% hash.key %] - -To interpolate a variable value the '${' ... '}' construct was used. -Typically, one would do this to index into a hash array when the key -value was stored in a variable. - -example: - - my $vars = { - users => { - aba => { name => 'Alan Aardvark', ... }, - abw => { name => 'Andy Wardley', ... }, - ... - }, - uid => 'aba', - ... - }; - - $template->process('user/home.html', $vars) - || die $template->error(), "\n"; - -'user/home.html': - - [% user = users.${uid} %] # users.aba - Name: [% user.name %] # Alan Aardvark - -This was inconsistent with double quoted strings and also the -INTERPOLATE mode, where a leading '$' in text was enough to indicate a -variable for interpolation, and the additional curly braces were used -to delimit variable names where necessary. Note that this use is -consistent with UNIX and Perl conventions, among others. - - # double quoted string interpolation - [% name = "$title ${user.name}" %] - - # INTERPOLATE = 1 -
- - -For version 2, these inconsistencies have been removed and the syntax -clarified. A leading '$' on a variable is now used exclusively to -indicate that the variable name should be interpolated -(e.g. subsituted for its value) before being used. The earlier example -from version 1: - - # VERSION 1 - [% user = users.${uid} %] - Name: [% user.name %] - -can now be simplified in version 2 as: - - # VERSION 2 - [% user = users.$uid %] - Name: [% user.name %] - -The leading dollar is no longer ignored and has the same effect of -interpolation as '${' ... '}' in version 1. The curly braces may -still be used to explicitly scope the interpolated variable name -where necessary. - -e.g. - - [% user = users.${me.id} %] - Name: [% user.name %] - -The rule applies for all variables, both within directives and in -plain text if processed with the INTERPOLATE option. This means that -you should no longer (if you ever did) add a leading '$' to a variable -inside a directive, unless you explicitly want it to be interpolated. - -One obvious side-effect is that any version 1 templates with variables -using a leading '$' will no longer be processed as expected. Given -the following variable definitions, - - [% foo = 'bar' - bar = 'baz' - %] - -version 1 would interpret the following as: - - # VERSION 1 - [% $foo %] => [% GET foo %] => bar - -whereas version 2 interprets it as: - - # VERSION 2 - [% $foo %] => [% GET $foo %] => [% GET bar %] => baz - -In version 1, the '$' is ignored and the value for the variable 'foo' is -retrieved and printed. In version 2, the variable '$foo' is first interpolated -to give the variable name 'bar' whose value is then retrieved and printed. - -The use of the optional '$' has never been strongly recommended, but -to assist in backwards compatibility with any version 1 templates that -may rely on this "feature", the V1DOLLAR option can be set to 1 -(default: 0) to revert the behaviour and have leading '$' characters -ignored. - - my $template = Template->new({ - V1DOLLAR => 1, - }); - - - - -=item LOAD_TEMPLATES - -The LOAD_TEMPLATE option can be used to provide a reference to a list -of Template::Provider objects or sub-classes thereof which will take -responsibility for loading and compiling templates. - - my $template = Template->new({ - LOAD_TEMPLATES => [ - MyOrg::Template::Provider->new({ ... }), - Template::Provider->new({ ... }), - ], - }); - -When a PROCESS, INCLUDE or WRAPPER directive is encountered, the named -template may refer to a locally defined BLOCK or a file relative to -the INCLUDE_PATH (or an absolute or relative path if the appropriate -ABSOLUTE or RELATIVE options are set). If a BLOCK definition can't be -found (see the Template::Context template() method for a discussion of -BLOCK locality) then each of the LOAD_TEMPLATES provider objects is -queried in turn via the fetch() method to see if it can supply the -required template. Each provider can return a compiled template, an -error, or decline to service the request in which case the -responsibility is passed to the next provider. If none of the -providers can service the request then a 'not found' error is -returned. The same basic provider mechanism is also used for the -INSERT directive but it bypasses any BLOCK definitions and doesn't -attempt is to parse or process the contents of the template file. - -This is an implementation of the 'Chain of Responsibility' -design pattern as described in -"Design Patterns", Erich Gamma, Richard Helm, Ralph Johnson, John -Vlissides), Addision-Wesley, ISBN 0-201-63361-2, page 223 -. - -If LOAD_TEMPLATES is undefined, a single default provider will be -instantiated using the current configuration parameters. For example, -the Template::Provider INCLUDE_PATH option can be specified in the Template configuration and will be correctly passed to the provider's -constructor method. - - my $template = Template->new({ - INCLUDE_PATH => '/here:/there', - }); - - - - - -=item LOAD_PLUGINS - -The LOAD_PLUGINS options can be used to specify a list of provider -objects (i.e. they implement the fetch() method) which are responsible -for loading and instantiating template plugin objects. The -Template::Content plugin() method queries each provider in turn in a -"Chain of Responsibility" as per the template() and filter() methods. - - my $template = Template->new({ - LOAD_PLUGINS => [ - MyOrg::Template::Plugins->new({ ... }), - Template::Plugins->new({ ... }), - ], - }); - -By default, a single Template::Plugins object is created using the -current configuration hash. Configuration items destined for the -Template::Plugins constructor may be added to the Template -constructor. - - my $template = Template->new({ - PLUGIN_BASE => 'MyOrg::Template::Plugins', - LOAD_PERL => 1, - }); - - - - - -=item LOAD_FILTERS - -The LOAD_FILTERS option can be used to specify a list of provider -objects (i.e. they implement the fetch() method) which are responsible -for returning and/or creating filter subroutines. The -Template::Context filter() method queries each provider in turn in a -"Chain of Responsibility" as per the template() and plugin() methods. - - my $template = Template->new({ - LOAD_FILTERS => [ - MyTemplate::Filters->new(), - Template::Filters->new(), - ], - }); - -By default, a single Template::Filters object is created for the -LOAD_FILTERS list. - - - - - -=item TOLERANT - -The TOLERANT flag is used by the various Template Toolkit provider -modules (Template::Provider, Template::Plugins, Template::Filters) to -control their behaviour when errors are encountered. By default, any -errors are reported as such, with the request for the particular -resource (template, plugin, filter) being denied and an exception -raised. When the TOLERANT flag is set to any true values, errors will -be silently ignored and the provider will instead return -STATUS_DECLINED. This allows a subsequent provider to take -responsibility for providing the resource, rather than failing the -request outright. If all providers decline to service the request, -either through tolerated failure or a genuine disinclination to -comply, then a 'EresourceE not found' exception is raised. - - - - - - -=item SERVICE - -A reference to a Template::Service object, or sub-class thereof, to which -the Template module should delegate. If unspecified, a Template::Service -object is automatically created using the current configuration hash. - - my $template = Template->new({ - SERVICE => MyOrg::Template::Service->new({ ... }), - }); - - - - - -=item CONTEXT - -A reference to a Template::Context object which is used to define a -specific environment in which template are processed. A Template::Context -object is passed as the only parameter to the Perl subroutines that -represent "compiled" template documents. Template subroutines make -callbacks into the context object to access Template Toolkit functionality, -for example, to to INCLUDE or PROCESS another template (include() and -process() methods, respectively), to USE a plugin (plugin()) or -instantiate a filter (filter()) or to access the stash (stash()) which -manages variable definitions via the get() and set() methods. - - my $template = Template->new({ - CONTEXT => MyOrg::Template::Context->new({ ... }), - }); - - - -=item STASH - -A reference to a Template::Stash object or sub-class which will take -responsibility for managing template variables. - - my $stash = MyOrg::Template::Stash->new({ ... }); - my $template = Template->new({ - STASH => $stash, - }); - -If unspecified, a default stash object is created using the VARIABLES -configuration item to initialise the stash variables. These may also -be specified as the PRE_DEFINE option for backwards compatibility with -version 1. - - my $template = Template->new({ - VARIABLES => { - id => 'abw', - name => 'Andy Wardley', - }, - }; - - - - - -=item PARSER - -The Template::Parser module implements a parser object for compiling -templates into Perl code which can then be executed. A default object -of this class is created automatically and then used by the -Template::Provider whenever a template is loaded and requires -compilation. The PARSER option can be used to provide a reference to -an alternate parser object. - - my $template = Template->new({ - PARSER => MyOrg::Template::Parser->new({ ... }), - }); - - - - - -=item GRAMMAR - -The GRAMMAR configuration item can be used to specify an alternate -grammar for the parser. This allows a modified or entirely new -template language to be constructed and used by the Template Toolkit. - -Source templates are compiled to Perl code by the Template::Parser -using the Template::Grammar (by default) to define the language -structure and semantics. Compiled templates are thus inherently -"compatible" with each other and there is nothing to prevent any -number of different template languages being compiled and used within -the same Template Toolkit processing environment (other than the usual -time and memory constraints). - -The Template::Grammar file is constructed from a YACC like grammar -(using Parse::YAPP) and a skeleton module template. These files are -provided, along with a small script to rebuild the grammar, in the -'parser' sub-directory of the distribution. You don't have to know or -worry about these unless you want to hack on the template language or -define your own variant. There is a README file in the same directory -which provides some small guidance but it is assumed that you know -what you're doing if you venture herein. If you grok LALR parsers, -then you should find it comfortably familiar. - -By default, an instance of the default Template::Grammar will be -created and used automatically if a GRAMMAR item isn't specified. - - use MyOrg::Template::Grammar; - - my $template = Template->new({ - GRAMMAR = MyOrg::Template::Grammar->new(); - }); - - - -=back - -=head1 AUTHOR - -Andy Wardley Eabw@andywardley.comE - -L - - - - -=head1 VERSION - -Template Toolkit version 2.13, released on 30 January 2004. - -=head1 COPYRIGHT - - Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved. - Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. - -This module is free software; you can redistribute it and/or -modify it under the same terms as Perl itself. - - - -=cut - -# Local Variables: -# mode: perl -# perl-indent-level: 4 -# indent-tabs-mode: nil -# End: -# -# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Manual/Credits.pod b/lib/Template/Manual/Credits.pod deleted file mode 100644 index 64999ac..0000000 --- a/lib/Template/Manual/Credits.pod +++ /dev/null @@ -1,188 +0,0 @@ -#============================================================= -*-perl-*- -# -# Template::Manual::Credits -# -# DESCRIPTION -# This section provides a brief history of the Template Toolkit and -# details the primary author and numerous other people who have -# contributed to it. -# -# AUTHOR -# Andy Wardley -# -# COPYRIGHT -# Copyright (C) 1996-2001 Andy Wardley. All Rights Reserved. -# Copyright (C) 1998-2001 Canon Research Centre Europe Ltd. -# -# This module is free software; you can redistribute it and/or -# modify it under the same terms as Perl itself. -# -# REVISION -# -# -#======================================================================== - - -#------------------------------------------------------------------------ -# IMPORTANT NOTE -# This documentation is generated automatically from source -# templates. Any changes you make here may be lost. -# -# The 'docsrc' documentation source bundle is available for download -# from http://www.template-toolkit.org/docs.html and contains all -# the source templates, XML files, scripts, etc., from which the -# documentation for the Template Toolkit is built. -#------------------------------------------------------------------------ - -=head1 NAME - -Template::Manual::Credits - Author and contributor credits - -=head1 DESCRIPTION - -This section provides a brief history of the Template Toolkit and -details the primary author and numerous other people who have -contributed to it. - -=head1 HISTORY - -The Template Toolkit began its life as the Text::MetaText module, -originally released to CPAN around 1996. This itself was the public -manifestation of an earlier template processing system I developed -while working at Peritas (now Knowledge Pool - - http://www.knowledgepool.com/) - -Text::MetaText was the prototype - the one we always planned to throw -away. It did the job well, showing us what worked and what didn't, what -was good and what was bad, and gave us some ideas about what could be -done better, given the chance to start again from scratch. - -Some time late in 1998 I threw away the prototype and started work on -the Template Toolkit. By then I was working at Canon Research Centre -Europe Ltd. (http://www.cre.canon.co.uk), involved in a general -research programme related to web publishing and dynamic content -generation. The first alpha release was in June 1999, followed by -numerous more alpha and beta releases culminating in 1.00 being -released on 2nd December 1999. - -A month or so later, work had begun on version 2.00. The plan was to -get the template language relatively stable in version 1.00 and not -worry too much about performance or other internal matters. Then, -version 2.00 would follow to improve performance, clean up the -architecture and fix anything that, with the benefit of hindsight, we -thought could be improved. As it happens, me starting work on version -2.00 coincided with Doug Steinwand sending me his parser variant which -compiled templates to Perl code, giving a major performance boost. -As well as the speedups, there are a whole host of significant new -features in version 2.00, and a greatly improved internal architecture. -Apart from a few minor "fixups" the template directives and language -have remained the same as in version 1.00 - -Version 2.00 was available in beta release form in July 2000, just -in time for the 4th Perl Conference where version 1.00 was awarded -"Best New Perl Module". After another extended beta release period, -version 2.00 was released on 1st December 2000. - - - - -=head1 CONTRIBUTORS - -Many people have contributed ideas, inspiration, fixes and features to -the Template Toolkit. Their efforts continue to be very much appreciated. -Please let me know if you think anyone is missing from this list. - - Chuck Adams - Stephen Adkins - Ivan Adzhubey - Mark Anderson - Bradley Baetz - Thierry-Michel Barral - Craig Barratt - Stas Bekman - Tony Bowden - Neil Bowers - Leon Brocard - Lyle Brooks - Dave Cash - Piers Cawley - Darren Chamberlain - Eric Cholet - Dave Cross - Chris Dean - Francois Desarmenien - Horst Dumcke - Mark Fowler - Michael Fowler - Axel Gerstmair - Dylan William Hardison - Perrin Harkins - Bryce Harrington - Dave Hodgkinson - Harald Joerg - Colin Johnson - Vivek Khera - Rafael Kitover - Ivan Kurmanov - Hans von Lengerke - Jonas Liljegren - Simon Luff - Paul Makepeace - Gervase Markham - Simon Matthews - Robert McArthur - Craig McLane - Leslie Michael Orchard - Eugene Miretskiy - Tatsuhiko Miyagawa - Keith G. Murphy - Chris Nandor - Briac Pilpré - Martin Portman - Slaven Rezic - Christian Schaffner - Randal L. Schwartz - Paul Sharpe - Ville Skyttä - Doug Steinwand - Michael Stevens - Drew Taylor - Swen Thuemmler - Richard Tietjen - Stathy G. Touloumis - Jim Vaughan - Simon Wilcox - Chris Winters - -=head1 AUTHOR - -Andy Wardley Eabw@andywardley.comE - -L - - - - -=head1 VERSION - -Template Toolkit version 2.13, released on 30 January 2004. - -=head1 COPYRIGHT - - Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved. - Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. - -This module is free software; you can redistribute it and/or -modify it under the same terms as Perl itself. - - - -=cut - -# Local Variables: -# mode: perl -# perl-indent-level: 4 -# indent-tabs-mode: nil -# End: -# -# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Manual/Directives.pod b/lib/Template/Manual/Directives.pod deleted file mode 100644 index 3b8af3e..0000000 --- a/lib/Template/Manual/Directives.pod +++ /dev/null @@ -1,2179 +0,0 @@ -#============================================================= -*-perl-*- -# -# Template::Manual::Directives -# -# DESCRIPTION -# This section provides a reference of all Template Toolkit -# directives, complete with examples of use. -# -# AUTHOR -# Andy Wardley -# -# COPYRIGHT -# Copyright (C) 1996-2001 Andy Wardley. All Rights Reserved. -# Copyright (C) 1998-2001 Canon Research Centre Europe Ltd. -# -# This module is free software; you can redistribute it and/or -# modify it under the same terms as Perl itself. -# -# REVISION -# -# -#======================================================================== - - -#------------------------------------------------------------------------ -# IMPORTANT NOTE -# This documentation is generated automatically from source -# templates. Any changes you make here may be lost. -# -# The 'docsrc' documentation source bundle is available for download -# from http://www.template-toolkit.org/docs.html and contains all -# the source templates, XML files, scripts, etc., from which the -# documentation for the Template Toolkit is built. -#------------------------------------------------------------------------ - -=head1 NAME - -Template::Manual::Directives - Template directives - -=head1 DESCRIPTION - -This section provides a reference of all Template Toolkit directives, -complete with examples of use. - -=head2 Accessing and Updating Template Variables - -=over 4 - - -=item GET - -The GET directive retrieves and outputs the value of the named variable. - - [% GET foo %] - -The GET keyword is optional. A variable can be specified in a directive -tag by itself. - - [% foo %] - -The variable can have an unlimited number of elements, each separated -by a dot '.'. Each element can have arguments specified within -parentheses. - - [% foo %] - [% bar.baz %] - [% biz.baz(10) %] - ...etc... - -See L for a full discussion on template -variables. - -You can also specify expressions using the logical (and, or, not, ?:) and -mathematic operators (+ - * / % mod div). - - [% template.title or default.title %] - - [% score * 100 %] - - [% order.nitems ? checkout(order.total) : 'no items' %] - -The 'div' operator returns the integer result of division. Both '%' and -'mod' return the modulus (i.e. remainder) of division. 'mod' is provided -as an alias for '%' for backwards compatibility with version 1. - - [% 15 / 6 %] # 2.5 - [% 15 div 6 %] # 2 - [% 15 mod 6 %] # 3 - - - -=item CALL - -The CALL directive is similar to GET in evaluating the variable named, -but doesn't print the result returned. This can be useful when a -variable is bound to a sub-routine or object method which you want to -call but aren't interested in the value returned. - - [% CALL dbi.disconnect %] - - [% CALL inc_page_counter(page_count) %] - - - - -=item SET - -The SET directive allows you to assign new values to existing variables -or create new temporary variables. - - [% SET title = 'Hello World' %] - -The SET keyword is also optional. - - [% title = 'Hello World' %] - -Variables may be assigned the values of other variables, unquoted -numbers (digits), literal text ('single quotes') or quoted text -("double quotes"). In the latter case, any variable references within -the text will be interpolated when the string is evaluated. Variables -should be prefixed by '$', using curly braces to explicitly scope -the variable name where necessary. - - [% foo = 'Foo' %] # literal value 'Foo' - [% bar = foo %] # value of variable 'foo' - [% cost = '$100' %] # literal value '$100' - [% item = "$bar: ${cost}.00" %] # value "Foo: $100.00" - -Multiple variables may be assigned in the same directive and are -evaluated in the order specified. Thus, the above could have been -written: - - [% foo = 'Foo' - bar = foo - cost = '$100' - item = "$bar: ${cost}.00" - %] - -Simple expressions can also be used, as per GET. - - [% ten = 10 - twenty = 20 - thirty = twenty + ten - forty = 2 * twenty - fifty = 100 div 2 - six = twenty mod 7 - %] - -You can concatenate strings together using the ' _ ' operator. In Perl 5, -the '.' is used for string concatenation, but in Perl 6, as in the Template -Toolkit, the '.' will be used as the method calling operator and ' _ ' will -be used for string concatenation. Note that the operator must be -specified with surrounding whitespace which, as Larry says, is construed as -a feature: - - [% copyright = '(C) Copyright' _ year _ ' ' _ author %] - -You can, of course, achieve a similar effect with double quoted string -interpolation. - - [% copyright = "(C) Copyright $year $author" %] - - - - - -=item DEFAULT - -The DEFAULT directive is similar to SET but only updates variables -that are currently undefined or have no "true" value (in the Perl -sense). - - [% DEFAULT - name = 'John Doe' - id = 'jdoe' - %] - -This can be particularly useful in common template components to -ensure that some sensible default are provided for otherwise -undefined variables. - - [% DEFAULT - title = 'Hello World' - bgcol = '#ffffff' - %] - - - [% title %] - - - - - -=back - -=head2 Processing Other Template Files and Blocks - -=over 4 - - -=item INSERT - -The INSERT directive is used to insert the contents of an external file -at the current position. - - [% INSERT myfile %] - -No attempt to parse or process the file is made. The contents, -possibly including any embedded template directives, are inserted -intact. - -The filename specified should be relative to one of the INCLUDE_PATH -directories. Absolute (i.e. starting with C) and relative -(i.e. starting with C<.>) filenames may be used if the ABSOLUTE and -RELATIVE options are set, respectively. Both these options are -disabled by default. - - my $template = Template->new({ - INCLUDE_PATH => '/here:/there', - }); - - $template->process('myfile'); - -'myfile': - - [% INSERT foo %] # looks for /here/foo then /there/foo - [% INSERT /etc/passwd %] # file error: ABSOLUTE not set - [% INSERT ../secret %] # file error: RELATIVE not set - -For convenience, the filename does not need to be quoted as long as it -contains only alphanumeric characters, underscores, dots or forward -slashes. Names containing any other characters should be quoted. - - [% INSERT misc/legalese.txt %] - [% INSERT 'dos98/Program Files/stupid' %] - -To evaluate a variable to specify a filename, you should explicitly -prefix it with a '$' or use double-quoted string interpolation. - - [% language = 'en' - legalese = 'misc/legalese.txt' - %] - - [% INSERT $legalese %] # 'misc/legalese.txt' - [% INSERT "$language/$legalese" %] # 'en/misc/legalese.txt' - -Multiple files can be specified using '+' as a delimiter. All files -should be unquoted names or quoted strings. Any variables should be -interpolated into double-quoted strings. - - [% INSERT legalese.txt + warning.txt %] - [% INSERT "$legalese" + warning.txt %] # requires quoting - - - - - - - - - - - - - - - - - -=item INCLUDE - -The INCLUDE directive is used to process and include the output of -another template file or block. - - [% INCLUDE header %] - -If a BLOCK of the specified name is defined in the same file, or in a file -from which the current template has been called (i.e. a parent template) -then it will be used in preference to any file of the same name. - - [% INCLUDE table %] # uses BLOCK defined below - - [% BLOCK table %] - - ... -
- [% END %] - -If a BLOCK definition is not currently visible then the template name -should be a file relative to one of the INCLUDE_PATH directories, or -an absolute or relative file name if the ABSOLUTE/RELATIVE options are -appropriately enabled. The INCLUDE directive automatically quotes the -filename specified, as per INSERT described above. When a variable -contains the name of the template for the INCLUDE directive, it should -be explicitly prefixed by '$' or double-quoted - - [% myheader = 'my/misc/header' %] - [% INCLUDE myheader %] # 'myheader' - [% INCLUDE $myheader %] # 'my/misc/header' - [% INCLUDE "$myheader" %] # 'my/misc/header' - -Any template directives embedded within the file will be processed -accordingly. All variables currently defined will be visible and -accessible from within the included template. - - [% title = 'Hello World' %] - [% INCLUDE header %] - - ... - -'header': - - - [% title %] - -output: - - - Hello World - - ... - -Local variable definitions may be specified after the template name, -temporarily masking any existing variables. Insignificant whitespace -is ignored within directives so you can add variable definitions on the -same line, the next line or split across several line with comments -interspersed, if you prefer. - - [% INCLUDE table %] - - [% INCLUDE table title="Active Projects" %] - - [% INCLUDE table - title = "Active Projects" - bgcolor = "#80ff00" # chartreuse - border = 2 - %] - -The INCLUDE directive localises (i.e. copies) all variables before -processing the template. Any changes made within the included -template will not affect variables in the including template. - - [% foo = 10 %] - - foo is originally [% foo %] - [% INCLUDE bar %] - foo is still [% foo %] - - [% BLOCK bar %] - foo was [% foo %] - [% foo = 20 %] - foo is now [% foo %] - [% END %] - -output: - foo is originally 10 - foo was 10 - foo is now 20 - foo is still 10 - -Technical Note: the localisation of the stash (that is, the process by -which variables are copied before an INCLUDE to prevent being -overwritten) is only skin deep. The top-level variable namespace -(hash) is copied, but no attempt is made to perform a deep-copy of -other structures (hashes, arrays, objects, etc.) Therefore, a 'foo' -variable referencing a hash will be copied to create a new 'foo' -variable but which points to the same hash array. Thus, if you update -compound variables (e.g. foo.bar) then you will change the original -copy, regardless of any stash localisation. If you're not worried -about preserving variable values, or you trust the templates you're -including then you might prefer to use the PROCESS directive which is -faster by virtue of not performing any localisation. - -From version 2.04 onwards, you can specify dotted variables as "local" -variables to an INCLUDE directive. However, be aware that because of -the localisation issues explained above (if you skipped the previous -Technical Note above then you might want to go back and read it or -skip this section too), the variables might not actualy be "local". -If the first element of the variable name already references a hash -array then the variable update will affect the original variable. - - [% foo = { - bar = 'Baz' - } - %] - - [% INCLUDE somefile foo.bar='Boz' %] - - [% foo.bar %] # Boz - -This behaviour can be a little unpredictable (and may well be improved -upon in a future version). If you know what you're doing with it and -you're sure that the variables in question are defined (nor not) as you -expect them to be, then you can rely on this feature to implement some -powerful "global" data sharing techniques. Otherwise, you might prefer -to steer well clear and always pass simple (undotted) variables as -parameters to INCLUDE and other similar directives. - -If you want to process several templates in one go then you can -specify each of their names (quoted or unquoted names only, no unquoted -'$variables') joined together by '+'. The INCLUDE directive -will then process them in order. - - [% INCLUDE html/header + "site/$header" + site/menu - title = "My Groovy Web Site" - %] - -The variable stash is localised once and then the templates specified -are processed in order, all within that same variable context. This -makes it slightly faster than specifying several separate INCLUDE -directives (because you only clone the variable stash once instead of -n times), but not quite as "safe" because any variable changes in the -first file will be visible in the second, third and so on. This -might be what you want, of course, but then again, it might not. - - - -=item PROCESS - -The PROCESS directive is similar to INCLUDE but does not perform any -localisation of variables before processing the template. Any changes -made to variables within the included template will be visible in the -including template. - - [% foo = 10 %] - - foo is [% foo %] - [% PROCESS bar %] - foo is [% foo %] - - [% BLOCK bar %] - [% foo = 20 %] - changed foo to [% foo %] - [% END %] - -output: - - foo is 10 - changed foo to 20 - foo is 20 - -Parameters may be specified in the PROCESS directive, but these too will -become visible changes to current variable values. - - [% foo = 10 %] - foo is [% foo %] - [% PROCESS bar - foo = 20 - %] - foo is [% foo %] - - [% BLOCK bar %] - this is bar, foo is [% foo %] - [% END %] - -output: - - foo is 10 - this is bar, foo is 20 - foo is 20 - -The PROCESS directive is slightly faster than INCLUDE because it -avoids the need to localise (i.e. copy) the variable stash before -processing the template. As with INSERT and INCLUDE, the first -parameter does not need to be quoted as long as it contains only -alphanumeric characters, underscores, periods or forward slashes. -A '$' prefix can be used to explicitly indicate a variable which -should be interpolated to provide the template name: - - [% myheader = 'my/misc/header' %] - [% PROCESS myheader %] # 'myheader' - [% PROCESS $myheader %] # 'my/misc/header' - -As with INCLUDE, multiple templates can be specified, delimited by -'+', and are processed in order. - - [% PROCESS html/header + my/header %] - - - - - -=item WRAPPER - -It's not unusual to find yourself adding common headers and footers to -pages or sub-sections within a page. Something like this: - - [% INCLUDE section/header - title = 'Quantum Mechanics' - %] - Quantum mechanics is a very interesting subject wish - should prove easy for the layman to fully comprehend. - [% INCLUDE section/footer %] - - [% INCLUDE section/header - title = 'Desktop Nuclear Fusion for under $50' - %] - This describes a simple device which generates significant - sustainable electrical power from common tap water by process - of nuclear fusion. - [% INCLUDE section/footer %] - -The individual template components being included might look like these: - -section/header: - -

-

[% title %]

- -section/footer: - -

- -The WRAPPER directive provides a way of simplifying this a little. It -encloses a block up to a matching END directive, which is first -processed to generate some output. This is then passed to the named -template file or BLOCK as the 'content' variable. - - [% WRAPPER section - title = 'Quantum Mechanics' - %] - Quantum mechanics is a very interesting subject wish - should prove easy for the layman to fully comprehend. - [% END %] - - [% WRAPPER section - title = 'Desktop Nuclear Fusion for under $50' - %] - This describes a simple device which generates significant - sustainable electrical power from common tap water by process - of nuclear fusion. - [% END %] - -The single 'section' template can then be defined as: - -

-

[% title %]

- [% content %] -

- -Like other block directives, it can be used in side-effect notation: - - [% INSERT legalese.txt WRAPPER big_bold_table %] - -It's also possible to specify multiple templates to a WRAPPER directive. -The specification order indicates outermost to innermost wrapper templates. -For example, given the following template block definitions: - - [% BLOCK bold %][% content %][% END %] - [% BLOCK italic %][% content %][% END %] - -the directive - - [% WRAPPER bold+italic %]Hello World[% END %] - -would generate the following output: - - Hello World - - - - - - - - - - - - - - - - - - -=item BLOCK - -The BLOCK ... END construct can be used to define template component -blocks which can be processed with the INCLUDE, PROCESS and WRAPPER -directives. - - [% BLOCK tabrow %] - [% name %][% email %] - [% END %] - - - [% PROCESS tabrow name='Fred' email='fred@nowhere.com' %] - [% PROCESS tabrow name='Alan' email='alan@nowhere.com' %] -
- -A BLOCK definition can be used before it is defined, as long as the -definition resides in the same file. The block definition itself does -not generate any output. - - [% PROCESS tmpblk %] - - [% BLOCK tmpblk %] This is OK [% END %] - -You can use an anonymous BLOCK to capture the output of a template -fragment. - - [% julius = BLOCK %] - And Caesar's spirit, ranging for revenge, - With Ate by his side come hot from hell, - Shall in these confines with a monarch's voice - Cry 'Havoc', and let slip the dogs of war; - That this foul deed shall smell above the earth - With carrion men, groaning for burial. - [% END %] - -Like a named block, it can contain any other template directives which -are processed when the block is defined. The output generated by the -block is then assigned to the variable 'julius'. - -Anonymous BLOCKs can also be used to define block macros. The -enclosing block is processed each time the macro is called. - - [% MACRO locate BLOCK %] - The [% animal %] sat on the [% place %]. - [% END %] - - [% locate(animal='cat', place='mat') %] # The cat sat on the mat - [% locate(animal='dog', place='log') %] # The dog sat on the log - - - -=back - -=head2 Conditional Processing - -=over 4 - - -=item IF / UNLESS / ELSIF / ELSE - -The IF and UNLESS directives can be used to process or ignore a -block based on some run-time condition. - - [% IF frames %] - [% INCLUDE frameset %] - [% END %] - - [% UNLESS text_mode %] - [% INCLUDE biglogo %] - [% END %] - -Multiple conditions may be joined with ELSIF and/or ELSE blocks. - - [% IF age < 10 %] - Hello [% name %], does your mother know you're - using her AOL account? - [% ELSIF age < 18 %] - Sorry, you're not old enough to enter - (and too dumb to lie about your age) - [% ELSE %] - Welcome [% name %]. - [% END %] - -The following conditional and boolean operators may be used: - - == != < <= > >= && || ! and or not - -Note that C, C and C are also provided as aliases for -C<&&>, C<||> and C, respectively. - -Conditions may be arbitrarily complex and are evaluated with the same -precedence as in Perl. Parenthesis may be used to explicitly -determine evaluation order. - - # ridiculously contrived complex example - [% IF (name == 'admin' || uid <= 0) && mode == 'debug' %] - I'm confused. - [% ELSIF more > less %] - That's more or less correct. - [% END %] - - - - - - -=item SWITCH / CASE - -The SWITCH / CASE construct can be used to perform a multi-way -conditional test. The SWITCH directive expects an expression which is -first evaluated and then compared against each CASE statement in turn. -Each CASE directive should contain a single value or a list of values -which should match. CASE may also be left blank or written as [% CASE -DEFAULT %] to specify a default match. Only one CASE matches, there -is no drop-through between CASE statements. - - [% SWITCH myvar %] - [% CASE value1 %] - ... - [% CASE [ value2 value3 ] %] # multiple values - ... - [% CASE myhash.keys %] # ditto - ... - [% CASE %] # default - ... - [% END %] - - - - -=back - -=head2 Loop Processing - -=over 4 - - -=item FOREACH - -The FOREACH directive will iterate through the items in a list, processing -the enclosed block for each one. - - my $vars = { - foo => 'Foo', - items => [ 'one', 'two', 'three' ], - }; - -template: - - Things: - [% FOREACH thing = [ foo 'Bar' "$foo Baz" ] %] - * [% thing %] - [% END %] - - Items: - [% FOREACH i = items %] - * [% i %] - [% END %] - - Stuff: - [% stuff = [ foo "$foo Bar" ] %] - [% FOREACH s = stuff %] - * [% s %] - [% END %] - -output: - - Things: - * Foo - * Bar - * Foo Baz - - Items: - * one - * two - * three - - Stuff: - * Foo - * Foo Bar - -You can use also use 'IN' instead of '=' if you prefer. - - [% FOREACH crook IN government %] - -When the FOREACH directive is used without specifying a target variable, -any iterated values which are hash references will be automatically -imported. - - [% userlist = [ - { id => 'tom', name => 'Thomas' }, - { id => 'dick', name => 'Richard' }, - { id => 'larry', name => 'Lawrence' }, - ] - %] - - [% FOREACH user IN userlist %] - [% user.id %] [% user.name %] - [% END %] - -short form: - - [% FOREACH userlist %] - [% id %] [% name %] - [% END %] - -Note that this particular usage creates a localised variable context -to prevent the imported hash keys from overwriting any existing -variables. The imported definitions and any other variables defined -in such a FOREACH loop will be lost at the end of the loop, when the -previous context and variable values are restored. - -However, under normal operation, the loop variable remains in scope -after the FOREACH loop has ended (caveat: overwriting any variable -previously in scope). This is useful as the loop variable is secretly -an iterator object (see below) and can be used to analyse the last -entry processed by the loop. - -The FOREACH directive can also be used to iterate through the entries -in a hash array. Each entry in the hash is returned in sorted order -(based on the key) as a hash array containing 'key' and 'value' items. - - [% users = { - tom => 'Thomas', - dick => 'Richard', - larry => 'Lawrence', - } - %] - - [% FOREACH u IN users %] - * [% u.key %] : [% u.value %] - [% END %] - -Output: - - * dick : Richard - * larry : Lawrence - * tom : Thomas - -The NEXT directive starts the next iteration in the FOREACH loop. - - [% FOREACH user IN userlist %] - [% NEXT IF user.isguest %] - Name: [% user.name %] Email: [% user.email %] - [% END %] - -The LAST directive can be used to prematurely exit the loop. BREAK is -also provided as an alias for LAST. - - [% FOREACH match IN results.nsort('score').reverse %] - [% LAST IF match.score < 50 %] - [% match.score %] : [% match.url %] - [% END %] - -The FOREACH directive is implemented using the Template::Iterator -module. A reference to the iterator object for a FOREACH directive is -implicitly available in the 'loop' variable. The following methods -can be called on the 'loop' iterator. - - size() number of elements in the list - max() index number of last element (size - 1) - index() index of current iteration from 0 to max() - count() iteration counter from 1 to size() (i.e. index() + 1) - first() true if the current iteration is the first - last() true if the current iteration is the last - prev() return the previous item in the list - next() return the next item in the list - -See L for further details. - -Example: - - [% FOREACH item IN [ 'foo', 'bar', 'baz' ] -%] - [%- "
    \n" IF loop.first %] -
  • [% loop.count %]/[% loop.size %]: [% item %] - [%- "
\n" IF loop.last %] - [% END %] - -Output: - -
    -
  • 1/3: foo -
  • 2/3: bar -
  • 3/3: baz -
- -Note that the number() method is supported as an alias for count() for -backwards compatibility but may be deprecated in some future version. - -Nested loops will work as expected, with the 'loop' variable correctly -referencing the innermost loop and being restored to any previous -value (i.e. an outer loop) at the end of the loop. - - [% FOREACH group IN grouplist; - # loop => group iterator - "Groups:\n" IF loop.first; - - FOREACH user IN group.userlist; - # loop => user iterator - "$loop.count: $user.name\n"; - END; - - # loop => group iterator - "End of Groups\n" IF loop.last; - END - %] - -The 'iterator' plugin can also be used to explicitly create an -iterator object. This can be useful within nested loops where you -need to keep a reference to the outer iterator within the inner loop. -The iterator plugin effectively allows you to create an iterator by a -name other than 'loop'. See Template::Plugin::Iterator for further -details. - - [% USE giter = iterator(grouplist) %] - - [% FOREACH group IN giter %] - [% FOREACH user IN group.userlist %] - user #[% loop.count %] in - group [% giter.count %] is - named [% user.name %] - [% END %] - [% END %] - - - - -=item WHILE - -The WHILE directive can be used to repeatedly process a template block -while a conditional expression evaluates true. The expression may -be arbitrarily complex as per IF / UNLESS. - - [% WHILE total < 100 %] - ... - [% total = calculate_new_total %] - [% END %] - -An assignment can be enclosed in parenthesis to evaluate the assigned -value. - - [% WHILE (user = get_next_user_record) %] - [% user.name %] - [% END %] - -The NEXT directive can be used to start the next iteration of a -WHILE loop and BREAK can be used to exit the loop, both as per FOREACH. - -The Template Toolkit uses a failsafe counter to prevent runaway WHILE -loops which would otherwise never terminate. If the loop exceeds 1000 -iterations then an 'undef' exception will be thrown, reporting the -error: - - WHILE loop terminated (> 1000 iterations) - -The $Template::Directive::WHILE_MAX variable controls this behaviour -and can be set to a higher value if necessary. - - -=back - -=head2 Filters, Plugins, Macros and Perl - -=over 4 - - -=item FILTER - -The FILTER directive can be used to post-process the output of a -block. A number of standard filters are provided with the Template -Toolkit. The 'html' filter, for example, escapes the 'E', 'E' -and '&' characters to prevent them from being interpreted as HTML tags -or entity reference markers. - - [% FILTER html %] - HTML text may have < and > characters embedded - which you want converted to the correct HTML entities. - [% END %] - -output: - - HTML text may have < and > characters embedded - which you want converted to the correct HTML entities. - -The FILTER directive can also follow various other non-block directives. -For example: - - [% INCLUDE mytext FILTER html %] - -The '|' character can also be used as an alias for 'FILTER'. - - [% INCLUDE mytext | html %] - -Multiple filters can be chained together and will be called in sequence. - - [% INCLUDE mytext FILTER html FILTER html_para %] - -or - - [% INCLUDE mytext | html | html_para %] - -Filters come in two flavours, known as 'static' or 'dynamic'. A -static filter is a simple subroutine which accepts a text string as -the only argument and returns the modified text. The 'html' filter is -an example of a static filter, implemented as: - - sub html_filter { - my $text = shift; - for ($text) { - s/&/&/g; - s//>/g; - } - return $text; - } - -Dynamic filters can accept arguments which are specified when the filter -is called from a template. The 'repeat' filter is such an example, -accepting a numerical argument which specifies the number of times -that the input text should be repeated. - - [% FILTER repeat(3) %]blah [% END %] - -output: - - blah blah blah - -These are implemented as filter 'factories'. The factory subroutine -is passed a reference to the current Template::Context object along -with any additional arguments specified. It should then return a -subroutine reference (e.g. a closure) which implements the filter. -The 'repeat' filter factory is implemented like this: - - sub repeat_filter_factory { - my ($context, $iter) = @_; - $iter = 1 unless defined $iter; - - return sub { - my $text = shift; - $text = '' unless defined $text; - return join('\n', $text) x $iter; - } - } - -The FILTERS option, described in L, allows -custom filters to be defined when a Template object is instantiated. -The Template::Context define_filter() method allows further filters -to be defined at any time. - -When using a filter, it is possible to assign an alias to it for -further use. This is most useful for dynamic filters that you want -to re-use with the same configuration. - - [% FILTER echo = repeat(2) %] - Is there anybody out there? - [% END %] - - [% FILTER echo %] - Mother, should I build a wall? - [% END %] - -Output: - - Is there anybody out there? - Is there anybody out there? - - Mother, should I build a wall? - Mother, should I build a wall? - -The FILTER directive automatically quotes the name of the filter. As -with INCLUDE et al, you can use a variable to provide the name of the -filter, prefixed by '$'. - - [% myfilter = 'html' %] - [% FILTER $myfilter %] # same as [% FILTER html %] - ... - [% END %] - -A template variable can also be used to define a static filter -subroutine. However, the Template Toolkit will automatically call any -subroutine bound to a variable and use the value returned. Thus, the -above example could be implemented as: - - my $vars = { - myfilter => sub { return 'html' }, - }; - -template: - - [% FILTER $myfilter %] # same as [% FILTER html %] - ... - [% END %] - -To define a template variable that evaluates to a subroutine reference -that can be used by the FILTER directive, you should create a -subroutine that, when called automatically by the Template Toolkit, -returns another subroutine reference which can then be used to perform -the filter operation. Note that only static filters can be -implemented in this way. - - my $vars = { - myfilter => sub { \&my_filter_sub }, - }; - - sub my_filter_sub { - my $text = shift; - # do something - return $text; - } - -template: - - [% FILTER $myfilter %] - ... - [% END %] - -Alternately, you can bless a subroutine reference into a class (any -class will do) to fool the Template Toolkit into thinking it's an -object rather than a subroutine. This will then bypass the automatic -"call-a-subroutine-to-return-a-value" magic. - - my $vars = { - myfilter => bless(\&my_filter_sub, 'anything_you_like'), - }; - -template: - - [% FILTER $myfilter %] - ... - [% END %] - -Filters bound to template variables remain local to the variable -context in which they are defined. That is, if you define a filter in -a PERL block within a template that is loaded via INCLUDE, then the -filter definition will only exist until the end of that template when -the stash is delocalised, restoring the previous variable state. If -you want to define a filter which persists for the lifetime of the -processor, or define additional dynamic filter factories, then you can -call the define_filter() method on the current Template::Context -object. - -See L for a complete list of available filters, -their descriptions and examples of use. - - - - - - -=item USE - -The USE directive can be used to load and initialise "plugin" -extension modules. - - [% USE myplugin %] - -A plugin is a regular Perl module that conforms to a particular -object-oriented interface, allowing it to be loaded into and used -automatically by the Template Toolkit. For details of this interface -and information on writing plugins, consult L. - -The plugin name is case-sensitive and will be appended to the -PLUGIN_BASE value (default: 'Template::Plugin') to construct a full -module name. Any periods, '.', in the name will be converted to '::'. - - [% USE MyPlugin %] # => Template::Plugin::MyPlugin - [% USE Foo.Bar %] # => Template::Plugin::Foo::Bar - -Various standard plugins are included with the Template Toolkit (see -below and L). These can be specified in lower -case and are mapped to the appropriate name. - - [% USE cgi %] # => Template::Plugin::CGI - [% USE table %] # => Template::Plugin::Table - -Any additional parameters supplied in parenthesis after the plugin -name will be also be passed to the new() constructor. A reference to -the current Template::Context object is always passed as the first -parameter. - - [% USE MyPlugin('foo', 123) %] - -equivalent to: - - Template::Plugin::MyPlugin->new($context, 'foo', 123); - -Named parameters may also be specified. These are collated into a -hash which is passed by reference as the last parameter to the -constructor, as per the general code calling interface. - - [% USE url('/cgi-bin/foo', mode='submit', debug=1) %] - -equivalent to: - - Template::Plugin::URL->new($context, '/cgi-bin/foo' - { mode => 'submit', debug => 1 }); - -The plugin may represent any data type; a simple variable, hash, list or -code reference, but in the general case it will be an object reference. -Methods can be called on the object (or the relevant members of the -specific data type) in the usual way: - - [% USE table(mydata, rows=3) %] - - [% FOREACH row = table.rows %] - - [% FOREACH item = row %] - [% item %] - [% END %] - - [% END %] - -An alternative name may be provided for the plugin by which it can be -referenced: - - [% USE scores = table(myscores, cols=5) %] - - [% FOREACH row = scores.rows %] - ... - [% END %] - -You can use this approach to create multiple plugin objects with -different configurations. This example shows how the 'format' plugin -is used to create sub-routines bound to variables for formatting text -as per printf(). - - [% USE bold = format('%s') %] - [% USE ital = format('%s') %] - - [% bold('This is bold') %] - [% ital('This is italic') %] - -Output: - - This is bold - This is italic - -This next example shows how the URL plugin can be used to build -dynamic URLs from a base part and optional query parameters. - - [% USE mycgi = URL('/cgi-bin/foo.pl', debug=1) %] - ... - ... - ... - -The CGI plugin is an example of one which delegates to another Perl -module. In this this case, it is to Lincoln Stein's CGI.pm module. -All of the methods provided by CGI.pm are available via the plugin. - - [% USE CGI %] - - [% CGI.start_form %] - - [% CGI.checkbox_group(name => 'colours', - values => [ 'red' 'green' 'blue' ]) - %] - - [% CGI.popup_menu(name => 'items', - values => [ 'foo' 'bar' 'baz' ]) - %] - - [% CGI.end_form %] - -Simon Matthews has written the DBI plugin which provides an interface -to Tim Bunce's DBI module (available from CPAN). Here's a short -example: - - [% USE DBI('DBI:mSQL:mydbname') %] - - [% FOREACH user = DBI.query('SELECT * FROM users') %] - [% user.id %] [% user.name %] [% user.etc.etc %] - [% END %] - -See L for more information on the plugins -distributed with the toolkit or available from CPAN. - -The LOAD_PERL option (disabled by default) provides a further way by -which external Perl modules may be loaded. If a regular Perl module -(i.e. not a Template::Plugin::* or other module relative to some -PLUGIN_BASE) supports an object-oriented interface and a new() -constructor then it can be loaded and instantiated automatically. The -following trivial example shows how the IO::File module might be used. - - [% USE file = IO.File('/tmp/mydata') %] - - [% WHILE (line = file.getline) %] - - [% END %] - - - - - - -=item MACRO - -The MACRO directive allows you to define a directive or directive block -which is then evaluated each time the macro is called. - - [% MACRO header INCLUDE header %] - -Calling the macro as: - - [% header %] - -is then equivalent to: - - [% INCLUDE header %] - -Macros can be passed named parameters when called. These values remain -local to the macro. - - [% header(title='Hello World') %] - -equivalent to: - - [% INCLUDE header title='Hello World' %] - -A MACRO definition may include parameter names. Values passed to the -macros are then mapped to these local variables. Other named parameters -may follow these. - - [% MACRO header(title) INCLUDE header %] - - [% header('Hello World') %] - [% header('Hello World', bgcol='#123456') %] - -equivalent to: - - [% INCLUDE header title='Hello World' %] - [% INCLUDE header title='Hello World' bgcol='#123456' %] - -Here's another example, defining a macro for display numbers -in comma-delimited groups of 3, using the chunk and join virtual -method. - - [% MACRO number(n) GET n.chunk(-3).join(',') %] - - [% number(1234567) %] # 1,234,567 - -A MACRO may precede any directive and must conform to the structure -of the directive. - - [% MACRO header IF frames %] - [% INCLUDE frames/header %] - [% ELSE %] - [% INCLUDE header %] - [% END %] - - [% header %] - -A MACRO may also be defined as an anonymous BLOCK. The block will be -evaluated each time the macro is called. - - [% MACRO header BLOCK %] - ...content... - [% END %] - - [% header %] - -If you've got the EVAL_PERL option set, then you can even define a -MACRO as a PERL block (see below): - - [% MACRO triple(n) PERL %] - my $n = $stash->get('n'); - print $n * 3; - [% END -%] - - - - - - - -=item PERL - -(for the advanced reader) - -The PERL directive is used to mark the start of a block which contains -Perl code for evaluation. The EVAL_PERL option must be enabled for Perl -code to be evaluated or a 'perl' exception will be thrown with the -message 'EVAL_PERL not set'. - -Perl code is evaluated in the Template::Perl package. The $context -package variable contains a reference to the current Template::Context -object. This can be used to access the functionality of the Template -Toolkit to process other templates, load plugins, filters, etc. -See L for further details. - - [% PERL %] - print $context->include('myfile'); - [% END %] - -The $stash variable contains a reference to the top-level stash object -which manages template variables. Through this, variable values can -be retrieved and updated. See L for further details. - - [% PERL %] - $stash->set(foo => 'bar'); - print "foo value: ", $stash->get('foo'); - [% END %] - -Output - foo value: bar - -Output is generated from the PERL block by calling print(). Note that -the Template::Perl::PERLOUT handle is selected (tied to an output -buffer) instead of STDOUT. - - [% PERL %] - print "foo\n"; # OK - print PERLOUT "bar\n"; # OK, same as above - print Template::Perl::PERLOUT "baz\n"; # OK, same as above - print STDOUT "qux\n"; # WRONG! - [% END %] - -The PERL block may contain other template directives. These are -processed before the Perl code is evaluated. - - [% name = 'Fred Smith' %] - - [% PERL %] - print "[% name %]\n"; - [% END %] - -Thus, the Perl code in the above example is evaluated as: - - print "Fred Smith\n"; - -Exceptions may be thrown from within PERL blocks via die() and will be -correctly caught by enclosing TRY blocks. - - [% TRY %] - [% PERL %] - die "nothing to live for\n"; - [% END %] - [% CATCH %] - error: [% error.info %] - [% END %] - -output: - error: nothing to live for - - - - -=item RAWPERL - -(for the very advanced reader) - -The Template Toolkit parser reads a source template and generates the -text of a Perl subroutine as output. It then uses eval() to evaluate -it into a subroutine reference. This subroutine is then called to -process the template, passing a reference to the current -Template::Context object through which the functionality of the -Template Toolkit can be accessed. The subroutine reference can be -cached, allowing the template to be processed repeatedly without -requiring any further parsing. - -For example, a template such as: - - [% PROCESS header %] - The [% animal %] sat on the [% location %] - [% PROCESS footer %] - -is converted into the following Perl subroutine definition: - - sub { - my $context = shift; - my $stash = $context->stash; - my $output = ''; - my $error; - - eval { BLOCK: { - $output .= $context->process('header'); - $output .= "The "; - $output .= $stash->get('animal'); - $output .= " sat on the "; - $output .= $stash->get('location'); - $output .= $context->process('footer'); - $output .= "\n"; - } }; - if ($@) { - $error = $context->catch($@, \$output); - die $error unless $error->type eq 'return'; - } - - return $output; - } - -To examine the Perl code generated, such as in the above example, set -the $Template::Parser::DEBUG package variable to any true value. You -can also set the $Template::Directive::PRETTY variable true to have -the code formatted in a readable manner for human consumption. The -source code for each generated template subroutine will be printed to -STDERR on compilation (i.e. the first time a template is used). - - $Template::Parser::DEBUG = 1; - $Template::Directive::PRETTY = 1; - - ... - - $template->process($file, $vars) - || die $template->error(), "\n"; - -The PERL ... END construct allows Perl code to be embedded into a -template (when the EVAL_PERL option is set), but it is evaluated at -"runtime" using eval() each time the template subroutine is called. -This is inherently flexible, but not as efficient as it could be, -especially in a persistent server environment where a template may be -processed many times. - -The RAWPERL directive allows you to write Perl code that is integrated -directly into the generated Perl subroutine text. It is evaluated -once at compile time and is stored in cached form as part of the -compiled template subroutine. This makes RAWPERL blocks more -efficient than PERL blocks. - -The downside is that you must code much closer to the metal. Within -PERL blocks, you can call print() to generate some output. RAWPERL -blocks don't afford such luxury. The code is inserted directly into -the generated subroutine text and should conform to the convention of -appending to the '$output' variable. - - [% PROCESS header %] - - [% RAWPERL %] - $output .= "Some output\n"; - ... - $output .= "Some more output\n"; - [% END %] - -The critical section of the generated subroutine for this example would -then look something like: - - ... - eval { BLOCK: { - $output .= $context->process('header'); - $output .= "\n"; - $output .= "Some output\n"; - ... - $output .= "Some more output\n"; - $output .= "\n"; - } }; - ... - -As with PERL blocks, the $context and $stash references are pre-defined -and available for use within RAWPERL code. - - -=back - -=head2 Exception Handling and Flow Control - -=over 4 - - -=item TRY / THROW / CATCH / FINAL - -(more advanced material) - -The Template Toolkit supports fully functional, nested exception -handling. The TRY directive introduces an exception handling scope -which continues until the matching END directive. Any errors that -occur within that block will be caught and can be handled by one -of the CATCH blocks defined. - - [% TRY %] - ...blah...blah... - [% CALL somecode %] - ...etc... - [% INCLUDE someblock %] - ...and so on... - [% CATCH %] - An error occurred! - [% END %] - -Errors are raised as exceptions (objects of the Template::Exception -class) and contain two fields, 'type' and 'info'. The exception -'type' can be any string containing letters, numbers, '_' or '.', and -is used to indicate the kind of error that occurred. The 'info' field -contains an error message indicating what actually went wrong. Within -a catch block, the exception object is aliased to the 'error' variable. -You can access the 'type' and 'info' fields directly. - - [% mydsn = 'dbi:MySQL:foobar' %] - ... - - [% TRY %] - [% USE DBI(mydsn) %] - [% CATCH %] - ERROR! Type: [% error.type %] - Info: [% error.info %] - [% END %] - -output (assuming a non-existant database called 'foobar'): - - ERROR! Type: DBI - Info: Unknown database "foobar" - -The 'error' variable can also be specified by itself and will return a -string of the form "$type error - $info". - - ... - [% CATCH %] - ERROR: [% error %] - [% END %] - -output: - - ERROR: DBI error - Unknown database "foobar" - -Each CATCH block may be specified with a particular exception type -denoting the kind of error that it should catch. Multiple CATCH -blocks can be provided to handle different types of exception that may -be thrown in the TRY block. A CATCH block specified without any type, -as in the previous example, is a default handler which will catch any -otherwise uncaught exceptions. This can also be specified as -[% CATCH DEFAULT %]. - - [% TRY %] - [% INCLUDE myfile %] - [% USE DBI(mydsn) %] - [% CALL somecode %] - ... - [% CATCH file %] - File Error! [% error.info %] - [% CATCH DBI %] - [% INCLUDE database/error.html %] - [% CATCH %] - [% error %] - [% END %] - -Remember that you can specify multiple directives within a single tag, -each delimited by ';'. Thus, you might prefer to write your simple -CATCH blocks more succinctly as: - - [% TRY %] - ... - [% CATCH file; "File Error! $error.info" %] - [% CATCH DBI; INCLUDE database/error.html %] - [% CATCH; error %] - [% END %] - -or even: - - [% TRY %] - ... - [% CATCH file ; - "File Error! $error.info" ; - CATCH DBI ; - INCLUDE database/error.html ; - CATCH ; - error ; - END - %] - -The DBI plugin throws exceptions of the 'DBI' type (in case that -wasn't already obvious). The other specific exception caught here is -of the 'file' type. - -A 'file' error is automatically thrown by the Template Toolkit when it -can't find a file, or fails to load, parse or process a file that has -been requested by an INCLUDE, PROCESS, INSERT or WRAPPER directive. -If 'myfile' can't be found in the example above, the [% INCLUDE myfile -%] directive will raise a 'file' exception which is then caught by the -[% CATCH file %] block, generating the output: - - File Error! myfile: not found - -Note that the DEFAULT option (disabled by default) allows you to -specify a default file to be used any time a template file can't be -found. This will prevent file exceptions from ever being raised when -a non-existant file is requested (unless, of course, the DEFAULT file -doesn't exist). Errors encountered once the file has been found -(i.e. read error, parse error) will be raised as file exceptions as per -usual. - -Uncaught exceptions (i.e. the TRY block doesn't have a type specific -or default CATCH handler) may be caught by enclosing TRY blocks which -can be nested indefinitely across multiple templates. If the error -isn't caught at any level then processing will stop and the Template -process() method will return a false value to the caller. The -relevant Template::Exception object can be retrieved by calling the -error() method. - - [% TRY %] - ... - [% TRY %] - [% INCLUDE $user.header %] - [% CATCH file %] - [% INCLUDE header %] - [% END %] - ... - [% CATCH DBI %] - [% INCLUDE database/error.html %] - [% END %] - -In this example, the inner TRY block is used to ensure that the first -INCLUDE directive works as expected. We're using a variable to -provide the name of the template we want to include, user.header, and -it's possible this contains the name of a non-existant template, or -perhaps one containing invalid template directives. If the INCLUDE fails - with a 'file' error then we CATCH it in the inner block and INCLUDE -the default 'header' file instead. Any DBI errors that occur within -the scope of the outer TRY block will be caught in the relevant CATCH -block, causing the 'database/error.html' template to be processed. -Note that included templates inherit all currently defined template -variable so these error files can quite happily access the 'error' -variable to retrieve information about the currently caught exception. -e.g. - -'database/error.html': - -

Database Error

- A database error has occurred: [% error.info %] - -You can also specify a FINAL block. This is always processed -regardless of the outcome of the TRY and/or CATCH block. If an -exception is uncaught then the FINAL block is processed before jumping -to the enclosing block or returning to the caller. - - [% TRY %] - ... - [% CATCH this %] - ... - [% CATCH that %] - ... - [% FINAL %] - All done! - [% END %] - -The output from the TRY block is left intact up to the point where an -exception occurs. For example, this template: - - [% TRY %] - This gets printed - [% THROW food 'carrots' %] - This doesn't - [% CATCH food %] - culinary delights: [% error.info %] - [% END %] - -generates the following output: - - This gets printed - culinary delights: carrots - -The CLEAR directive can be used in a CATCH or FINAL block to clear -any output created in the TRY block. - - [% TRY %] - This gets printed - [% THROW food 'carrots' %] - This doesn't - [% CATCH food %] - [% CLEAR %] - culinary delights: [% error.info %] - [% END %] - -output: - - culinary delights: carrots - -Exception types are hierarchical, with each level being separated by -the familiar dot operator. A 'DBI.connect' exception is a more -specific kind of 'DBI' error. Similarly, a 'myown.error.barf' is a -more specific kind of 'myown.error' type which itself is also a -'myown' error. A CATCH handler that specifies a general exception -type (such as 'DBI' or 'myown.error') will also catch more specific -types that have the same prefix as long as a more specific handler -isn't defined. Note that the order in which CATCH handlers are -defined is irrelevant; a more specific handler will always catch an -exception in preference to a more generic or default one. - - [% TRY %] - ... - [% CATCH DBI ; - INCLUDE database/error.html ; - CATCH DBI.connect ; - INCLUDE database/connect.html ; - CATCH ; - INCLUDE error.html ; - END - %] - -In this example, a 'DBI.connect' error has it's own handler, a more -general 'DBI' block is used for all other DBI or DBI.* errors and a -default handler catches everything else. - -Exceptions can be raised in a template using the THROW directive. The -first parameter is the exception type which doesn't need to be quoted -(but can be, it's the same as INCLUDE) followed by the relevant error -message which can be any regular value such as a quoted string, -variable, etc. - - [% THROW food "Missing ingredients: $recipe.error" %] - - [% THROW user.login 'no user id: please login' %] - - [% THROW $myerror.type "My Error: $myerror.info" %] - -It's also possible to specify additional positional or named -parameters to the THROW directive if you want to pass more than -just a simple message back as the error info field. - - [% THROW food 'eggs' 'flour' msg='Missing Ingredients' %] - -In this case, the error 'info' field will be a hash array containing -the named arguments, in this case 'msg' =E 'Missing Ingredients', -and an 'args' item which contains a list of the positional arguments, -in this case 'eggs' and 'flour'. The error 'type' field remains -unchanged, here set to 'food'. - - [% CATCH food %] - [% error.info.msg %] - [% FOREACH item = error.info.args %] - * [% item %] - [% END %] - [% END %] - -This produces the output: - - Missing Ingredients - * eggs - * flour - -In addition to specifying individual positional arguments as -[% error.info.args.n %], the 'info' hash contains keys directly -pointing to the positional arguments, as a convenient shortcut. - - [% error.info.0 %] # same as [% error.info.args.0 %] - -Exceptions can also be thrown from Perl code which you've bound to -template variables, or defined as a plugin or other extension. To -raise an exception, call die() passing a reference to a -Template::Exception object as the argument. This will then be caught -by any enclosing TRY blocks from where the code was called. - - use Template::Exception; - ... - - my $vars = { - foo => sub { - # ... do something ... - die Template::Exception->new('myerr.naughty', - 'Bad, bad error'); - }, - }; - -template: - - [% TRY %] - ... - [% foo %] - ... - [% CATCH myerr ; - "Error: $error" ; - END - %] - -output: - - Error: myerr.naughty error - Bad, bad error - -The 'info' field can also be a reference to another object or data -structure, if required. - - die Template::Exception->new('myerror', { - module => 'foo.pl', - errors => [ 'bad permissions', 'naughty boy' ], - }); - -Later, in a template: - - [% TRY %] - ... - [% CATCH myerror %] - [% error.info.errors.size or 'no'; - error.info.errors.size == 1 ? ' error' : ' errors' %] - in [% error.info.module %]: - [% error.info.errors.join(', ') %]. - [% END %] - -Generating the output: - - 2 errors in foo.pl: - bad permissions, naughty boy. - -You can also call die() with a single string, as is common in much -existing Perl code. This will automatically be converted to an -exception of the 'undef' type (that's the literal string 'undef', -not the undefined value). If the string isn't terminated with a -newline then Perl will append the familiar " at $file line $line" -message. - - sub foo { - # ... do something ... - die "I'm sorry, Dave, I can't do that\n"; - } - -If you're writing a plugin, or some extension code that has the -current Template::Context in scope (you can safely skip this section -if this means nothing to you) then you can also raise an exception by -calling the context throw() method. You can pass it an -Template::Exception object reference, a pair of ($type, $info) parameters -or just an $info string to create an exception of 'undef' type. - - $context->throw($e); # exception object - $context->throw('Denied'); # 'undef' type - $context->throw('user.passwd', 'Bad Password'); - - - - - - - -=item NEXT - -The NEXT directive can be used to start the next iteration of a FOREACH -or WHILE loop. - - [% FOREACH user = userlist %] - [% NEXT IF user.isguest %] - Name: [% user.name %] Email: [% user.email %] - [% END %] - - - - - -=item LAST - -The LAST directive can be used to prematurely exit a FOREACH or WHILE -loop. - - [% FOREACH user = userlist %] - Name: [% user.name %] Email: [% user.email %] - [% LAST IF some.condition %] - [% END %] - -BREAK can also be used as an alias for LAST. - - - - -=item RETURN - -The RETURN directive can be used to stop processing the current -template and return to the template from which it was called, resuming -processing at the point immediately after the INCLUDE, PROCESS or -WRAPPER directive. If there is no enclosing template then the -Template process() method will return to the calling code with a -true value. - - Before - [% INCLUDE half_wit %] - After - - [% BLOCK half_wit %] - This is just half... - [% RETURN %] - ...a complete block - [% END %] - -output: - - Before - This is just half... - After - - - - -=item STOP - -The STOP directive can be used to indicate that the processor should -stop gracefully without processing any more of the template document. -This is a planned stop and the Template process() method will return a -B value to the caller. This indicates that the template was -processed successfully according to the directives within it. - - [% IF something.terrible.happened %] - [% INCLUDE fatal/error.html %] - [% STOP %] - [% END %] - - [% TRY %] - [% USE DBI(mydsn) %] - ... - [% CATCH DBI.connect %] -

Cannot connect to the database: [% error.info %]

-
- We apologise for the inconvenience. The cleaning lady - has removed the server power to plug in her vacuum cleaner. - Please try again later. -

- [% INCLUDE footer %] - [% STOP %] - [% END %] - - - - -=item CLEAR - -The CLEAR directive can be used to clear the output buffer for the current -enclosing block. It is most commonly used to clear the output generated -from a TRY block up to the point where the error occurred. - - [% TRY %] - blah blah blah # this is normally left intact - [% THROW some 'error' %] # up to the point of error - ... - [% CATCH %] - [% CLEAR %] # clear the TRY output - [% error %] # print error string - [% END %] - - - - -=back - -=head2 Miscellaneous - -=over 4 - - -=item META - -The META directive allows simple metadata items to be defined within a -template. These are evaluated when the template is parsed and as such -may only contain simple values (e.g. it's not possible to interpolate -other variables values into META variables). - - [% META - title = 'The Cat in the Hat' - author = 'Dr. Seuss' - version = 1.23 - %] - -The 'template' variable contains a reference to the main template -being processed. These metadata items may be retrieved as attributes -of the template. - -

[% template.title %]

-

[% template.author %]

- -The 'name' and 'modtime' metadata items are automatically defined for -each template to contain its name and modification time in seconds -since the epoch. - - [% USE date %] # use Date plugin to format time - ... - [% template.name %] last modified - at [% date.format(template.modtime) %] - -The PRE_PROCESS and POST_PROCESS options allow common headers and -footers to be added to all templates. The 'template' reference is -correctly defined when these templates are processed, allowing headers -and footers to reference metadata items from the main template. - - $template = Template->new({ - PRE_PROCESS => 'header', - POST_PROCESS => 'footer', - }); - - $template->process('cat_in_hat'); - -header: - - - - [% template.title %] - - - -cat_in_hat: - - [% META - title = 'The Cat in the Hat' - author = 'Dr. Seuss' - version = 1.23 - year = 2000 - %] - - The cat in the hat sat on the mat. - -footer: - -
- © [% template.year %] [% template.author %] - - - -The output generated from the above example is: - - - - The Cat in the Hat - - - - The cat in the hat sat on the mat. - -
- © 2000 Dr. Seuss - - - - - -=item TAGS - -The TAGS directive can be used to set the START_TAG and END_TAG values -on a per-template file basis. - - [% TAGS <+ +> %] - - <+ INCLUDE header +> - -The TAGS directive may also be used to set a named TAG_STYLE - - [% TAGS html %] - - -See the TAGS and TAG_STYLE configuration options for further details. - - - - - - - - -=item DEBUG - -The DEBUG directive can be used to enable or disable directive debug -messages within a template. The DEBUG configuration option must be -set to include DEBUG_DIRS for the DEBUG directives to have any effect. -If DEBUG_DIRS is not set then the parser will automatically ignore and -remove any DEBUG directives. - -The DEBUG directive can be used with an 'on' or 'off' parameter to -enable or disable directive debugging messages from that point -forward. When enabled, the output of each directive in the generated -output will be prefixed by a comment indicate the file, line and -original directive text. - - [% DEBUG on %] - directive debugging is on (assuming DEBUG option is set true) - [% DEBUG off %] - directive debugging is off - -The 'format' parameter can be used to change the format of the debugging -message. - - [% DEBUG format '' %] - - - - - -=back - -=head1 AUTHOR - -Andy Wardley Eabw@andywardley.comE - -L - - - - -=head1 VERSION - -Template Toolkit version 2.13, released on 30 January 2004. - -=head1 COPYRIGHT - - Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved. - Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. - -This module is free software; you can redistribute it and/or -modify it under the same terms as Perl itself. - - - -=cut - -# Local Variables: -# mode: perl -# perl-indent-level: 4 -# indent-tabs-mode: nil -# End: -# -# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Manual/Filters.pod b/lib/Template/Manual/Filters.pod deleted file mode 100644 index c42f2ef..0000000 --- a/lib/Template/Manual/Filters.pod +++ /dev/null @@ -1,529 +0,0 @@ -#============================================================= -*-perl-*- -# -# Template::Manual::Filters -# -# DESCRIPTION -# This section lists all the standard filters distributed with the -# Template Toolkit for post-processing output. -# -# AUTHOR -# Andy Wardley -# -# COPYRIGHT -# Copyright (C) 1996-2001 Andy Wardley. All Rights Reserved. -# Copyright (C) 1998-2001 Canon Research Centre Europe Ltd. -# -# This module is free software; you can redistribute it and/or -# modify it under the same terms as Perl itself. -# -# REVISION -# -# -#======================================================================== - - -#------------------------------------------------------------------------ -# IMPORTANT NOTE -# This documentation is generated automatically from source -# templates. Any changes you make here may be lost. -# -# The 'docsrc' documentation source bundle is available for download -# from http://www.template-toolkit.org/docs.html and contains all -# the source templates, XML files, scripts, etc., from which the -# documentation for the Template Toolkit is built. -#------------------------------------------------------------------------ - -=head1 NAME - -Template::Manual::Filters - Standard filters - -=head1 DESCRIPTION - -This section lists all the standard filters distributed with the -Template Toolkit for post-processing output. - -=head1 STANDARD FILTERS - - - -=head2 format(format) - -The 'format' filter takes a format string as a parameter (as per -printf()) and formats each line of text accordingly. - - [% FILTER format('') %] - This is a block of text filtered - through the above format. - [% END %] - -output: - - - - -=head2 upper - -Folds the input to UPPER CASE. - - [% "hello world" FILTER upper %] - -output: - - HELLO WORLD - -=head2 lower - -Folds the input to lower case. - - [% "Hello World" FILTER lower %] - -output: - - hello world - -=head2 ucfirst - -Folds the first character of the input to UPPER CASE. - - [% "hello" FILTER ucfirst %] - -output: - - Hello - -=head2 lcfirst - -Folds the first character of the input to lower case. - - [% "HELLO" FILTER lcfirst %] - -output: - - hELLO - -=head2 trim - -Trims any leading or trailing whitespace from the input text. Particularly -useful in conjunction with INCLUDE, PROCESS, etc., having the same effect -as the TRIM configuration option. - - [% INCLUDE myfile | trim %] - -=head2 collapse - -Collapse any whitespace sequences in the input text into a single space. -Leading and trailing whitespace (which would be reduced to a single space) -is removed, as per trim. - - [% FILTER collapse %] - - The cat - - sat on - - the mat - - [% END %] - -output: - - The cat sat on the mat - -=head2 html - -Converts the characters 'E', 'E' and '&' to '<', '>' and -'&', respectively, protecting them from being interpreted as -representing HTML tags or entities. - - [% FILTER html %] - Binary "<=>" returns -1, 0, or 1 depending on... - [% END %] - -output: - - Binary "<=>" returns -1, 0, or 1 depending on... - -=head2 html_entity - -The html filter is fast and simple but it doesn't encode the full -range of HTML entities that your text may contain. The html_entity -filter uses either the Apache::Util module (which is written in C and -is therefore faster) or the HTML::Entities module (written in Perl but -equally as comprehensive) to perform the encoding. If one or other of -these modules are installed on your system then the text will be -encoded (via the escape_html() or encode_entities() subroutines -respectively) to convert all extended characters into their -appropriate HTML entities (e.g. converting 'é' to 'é'). If -neither module is available on your system then an 'html_entity' exception -will be thrown reporting an appropriate message. - -For further information on HTML entity encoding, see -http://www.w3.org/TR/REC-html40/sgml/entities.html. - -=head2 html_para - -This filter formats a block of text into HTML paragraphs. A sequence of -two or more newlines is used as the delimiter for paragraphs which are -then wrapped in HTML EpE...E/pE tags. - - [% FILTER html_para %] - The cat sat on the mat. - - Mary had a little lamb. - [% END %] - -output: - -

- The cat sat on the mat. -

- -

- Mary had a little lamb. -

- -=head2 html_break / html_para_break - -Similar to the html_para filter described above, but uses the HTML tag -sequence EbrEEbrE to join paragraphs. - - [% FILTER html_break %] - The cat sat on the mat. - - Mary had a little lamb. - [% END %] - -output: - - The cat sat on the mat. -
-
- Mary had a little lamb. - -=head2 html_line_break - -This filter replaces any newlines with EbrE HTML tags, -thus preserving the line breaks of the original text in the -HTML output. - - [% FILTER html_line_break %] - The cat sat on the mat. - Mary had a little lamb. - [% END %] - -output: - - The cat sat on the mat.
- Mary had a little lamb.
- -=head2 uri - -This filter URI escapes the input text, converting any characters -outside of the permitted URI character set (as defined by RFC 2396) -into a C<%nn> hex escape. - - [% 'my file.html' | uri %] - -output: - - my%20file.html - -Note that URI escaping isn't always enough when generating hyperlinks in -an HTML document. The C<&> character, for example, is valid in a URI and -will not be escaped by the URI filter. In this case you should also filter -the text through the 'html' filter. - -
click here - -=head2 indent(pad) - -Indents the text block by a fixed pad string or width. The 'pad' argument -can be specified as a string, or as a numerical value to indicate a pad -width (spaces). Defaults to 4 spaces if unspecified. - - [% FILTER indent('ME> ') %] - blah blah blah - cabbages, rhubard, onions - [% END %] - -output: - - ME> blah blah blah - ME> cabbages, rhubard, onions - -=head2 truncate(length) - -Truncates the text block to the length specified, or a default length of -32. Truncated text will be terminated with '...' (i.e. the '...' falls -inside the required length, rather than appending to it). - - [% FILTER truncate(21) %] - I have much to say on this matter that has previously - been said on more than one occasion. - [% END %] - -output: - - I have much to say... - -=head2 repeat(iterations) - -Repeats the text block for as many iterations as are specified (default: 1). - - [% FILTER repeat(3) %] - We want more beer and we want more beer, - [% END %] - We are the more beer wanters! - -output: - - We want more beer and we want more beer, - We want more beer and we want more beer, - We want more beer and we want more beer, - We are the more beer wanters! - -=head2 remove(string) - -Searches the input text for any occurrences of the specified string and -removes them. A Perl regular expression may be specified as the search -string. - - [% "The cat sat on the mat" FILTER remove('\s+') %] - -output: - - Thecatsatonthemat - -=head2 replace(search, replace) - -Similar to the remove filter described above, but taking a second parameter -which is used as a replacement string for instances of the search string. - - [% "The cat sat on the mat" | replace('\s+', '_') %] - -output: - - The_cat_sat_on_the_mat - -=head2 redirect(file, options) - -The 'redirect' filter redirects the output of the block into a separate -file, specified relative to the OUTPUT_PATH configuration item. - - [% FOREACH user = myorg.userlist %] - [% FILTER redirect("users/${user.id}.html") %] - [% INCLUDE userinfo %] - [% END %] - [% END %] - -or more succinctly, using side-effect notation: - - [% INCLUDE userinfo - FILTER redirect("users/${user.id}.html") - FOREACH user = myorg.userlist - %] - -A 'file' exception will be thrown if the OUTPUT_PATH option is undefined. - -An optional 'binmode' argument can follow the filename to explicitly set -the output file to binary mode. - - [% PROCESS my/png/generator - FILTER redirect("images/logo.png", binmode=1) %] - -For backwards compatibility with earlier versions, a single true/false -value can be used to set binary mode. - - [% PROCESS my/png/generator - FILTER redirect("images/logo.png", 1) %] - -For the sake of future compatibility and clarity, if nothing else, we -would strongly recommend you explicitly use the named 'binmode' option -as shown in the first example. - -=head2 eval / evaltt - -The 'eval' filter evaluates the block as template text, processing -any directives embedded within it. This allows template variables to -contain template fragments, or for some method to be provided for -returning template fragments from an external source such as a -database, which can then be processed in the template as required. - - my $vars = { - fragment => "The cat sat on the [% place %]", - }; - $template->process($file, $vars); - -The following example: - - [% fragment | eval %] - -is therefore equivalent to - - The cat sat on the [% place %] - -The 'evaltt' filter is provided as an alias for 'eval'. - -=head2 perl / evalperl - -The 'perl' filter evaluates the block as Perl code. The EVAL_PERL -option must be set to a true value or a 'perl' exception will be -thrown. - - [% my_perl_code | perl %] - -In most cases, the [% PERL %] ... [% END %] block should suffice for -evaluating Perl code, given that template directives are processed -before being evaluate as Perl. Thus, the previous example could have -been written in the more verbose form: - - [% PERL %] - [% my_perl_code %] - [% END %] - -as well as - - [% FILTER perl %] - [% my_perl_code %] - [% END %] - -The 'evalperl' filter is provided as an alias for 'perl' for backwards -compatibility. - -=head2 stdout(options) - -The stdout filter prints the output generated by the enclosing block to -STDOUT. The 'binmode' option can be passed as either a named parameter -or a single argument to set STDOUT to binary mode (see the -binmode perl function). - - [% PROCESS something/cool - FILTER stdout(binmode=1) # recommended %] - - [% PROCESS something/cool - FILTER stdout(1) # alternate %] - -The stdout filter can be used to force binmode on STDOUT, or also inside -redirect, null or stderr blocks to make sure that particular output goes -to stdout. See the null filter below for an example. - -=head2 stderr - -The stderr filter prints the output generated by the enclosing block to -STDERR. - -=head2 null - -The null filter prints nothing. This is useful for plugins whose -methods return values that you don't want to appear in the output. -Rather than assigning every plugin method call to a dummy variable -to silence it, you can wrap the block in a null filter: - - [% FILTER null; - USE im = GD.Image(100,100); - black = im.colorAllocate(0, 0, 0); - red = im.colorAllocate(255,0, 0); - blue = im.colorAllocate(0, 0, 255); - im.arc(50,50,95,75,0,360,blue); - im.fill(50,50,red); - im.png | stdout(1); - END; - -%] - -Notice the use of the stdout filter to ensure that a particular expression -generates output to stdout (in this case in binary mode). - -=head2 latex(outputType) - -Passes the text block to LaTeX and produces either PDF, DVI or -PostScript output. The 'outputType' argument determines the output -format and it should be set to one of the strings: "pdf" (default), -"dvi", or "ps". - -The text block should be a complete LaTeX source file. - - [% FILTER latex("pdf") -%] - \documentclass{article} - - \begin{document} - - \title{A Sample TT2 \LaTeX\ Source File} - \author{Craig Barratt} - \maketitle - - \section{Introduction} - This is some text. - - \end{document} - [% END -%] - -The output will be a PDF file. You should be careful not to prepend or -append any extraneous characters or text outside the FILTER block, -since this text will wrap the (binary) output of the latex filter. -Notice the END directive uses '-%]' for the END_TAG to remove the -trailing new line. - -One example where you might prepend text is in a CGI script where -you might include the Content-Type before the latex output, eg: - - Content-Type: application/pdf - - [% FILTER latex("pdf") -%] - \documentclass{article} - \begin{document} - ... - \end{document} - [% END -%] - -In other cases you might use the redirect filter to put the output -into a file, rather than delivering it to stdout. This might be -suitable for batch scripts: - - [% output = FILTER latex("pdf") -%] - \documentclass{article} - \begin{document} - ... - \end{document} - [% END; output | redirect("document.pdf", 1) -%] - -(Notice the second argument to redirect to force binary mode.) - -Note that the latex filter runs one or two external programs, so it -isn't very fast. But for modest documents the performance is adequate, -even for interactive applications. - -A error of type 'latex' will be thrown if there is an error reported -by latex, pdflatex or dvips. - -=head1 AUTHOR - -Andy Wardley Eabw@andywardley.comE - -L - - - - -=head1 VERSION - -Template Toolkit version 2.13, released on 30 January 2004. - -=head1 COPYRIGHT - - Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved. - Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. - -This module is free software; you can redistribute it and/or -modify it under the same terms as Perl itself. - - - -=cut - -# Local Variables: -# mode: perl -# perl-indent-level: 4 -# indent-tabs-mode: nil -# End: -# -# vim: expandtab shiftwidth=4: diff --git a/lib/Template/Manual/Internals.pod b/lib/Template/Manual/Internals.pod deleted file mode 100644 index b8cf80b..0000000 --- a/lib/Template/Manual/Internals.pod +++ /dev/null @@ -1,556 +0,0 @@ -#============================================================= -*-perl-*- -# -# Template::Manual::Internals -# -# DESCRIPTION -# This document provides an overview of the internal architecture of -# the Template Toolkit. It is a work in progress and is far from -# complete, currently providing little more than an overview of how -# the major components fit together. Nevertheless, it's a good -# starting point for anyone wishing to delve into the source code to -# find out how it all works. -# -# AUTHOR -# Andy Wardley -# -# COPYRIGHT -# Copyright (C) 1996-2001 Andy Wardley. All Rights Reserved. -# Copyright (C) 1998-2001 Canon Research Centre Europe Ltd. -# -# This module is free software; you can redistribute it and/or -# modify it under the same terms as Perl itself. -# -# REVISION -# -# -#======================================================================== - - -#------------------------------------------------------------------------ -# IMPORTANT NOTE -# This documentation is generated automatically from source -# templates. Any changes you make here may be lost. -# -# The 'docsrc' documentation source bundle is available for download -# from http://www.template-toolkit.org/docs.html and contains all -# the source templates, XML files, scripts, etc., from which the -# documentation for the Template Toolkit is built. -#------------------------------------------------------------------------ - -=head1 NAME - -Template::Manual::Internals - Template Toolkit internals - -=head1 DESCRIPTION - -This document provides an overview of the internal architecture of the -Template Toolkit. It is a work in progress and is far from complete, -currently providing little more than an overview of how the major -components fit together. Nevertheless, it's a good starting point for -anyone wishing to delve into the source code to find out how it all -works. - -=head2 Outside Looking In - -The B