pax_global_header00006660000000000000000000000064135211623760014520gustar00rootroot0000000000000052 comment=31badbab19cdaa51fe73da51f869f43ab215cbf1 txt2html-2.53/000077500000000000000000000000001352116237600132375ustar00rootroot00000000000000txt2html-2.53/Build.PL000066400000000000000000000023761352116237600145430ustar00rootroot00000000000000 use strict; use warnings; use Module::Build 0.3601; my %module_build_args = ( "build_requires" => { "Module::Build" => "0.3601" }, "configure_requires" => { "Module::Build" => "0.3601" }, "dist_abstract" => "convert plain text file to HTML.", "dist_author" => [ "Kathryn Andersen " ], "dist_name" => "txt2html", "dist_version" => "2.53", "license" => "gpl", "module_name" => "txt2html", "recommends" => {}, "recursive_test_files" => 1, "requires" => { "File::Basename" => 0, "Getopt::Long" => 0, "Pod::Usage" => 0, "YAML::Syck" => 0, "constant" => 0, "perl" => "v5.8.1", "strict" => 0 }, "script_files" => [ "scripts/txt2html" ], "test_requires" => { "File::Find" => 0, "File::Temp" => 0, "Test::More" => 0, "warnings" => 0 } ); unless ( eval { Module::Build->VERSION(0.4004) } ) { my $tr = delete $module_build_args{test_requires}; my $br = $module_build_args{build_requires}; for my $mod ( keys %$tr ) { if ( exists $br->{$mod} ) { $br->{$mod} = $tr->{$mod} if $tr->{$mod} > $br->{$mod}; } else { $br->{$mod} = $tr->{$mod}; } } } my $build = Module::Build->new(%module_build_args); $build->create_build_script; txt2html-2.53/CONTRIBUTING.md000066400000000000000000000017751352116237600155020ustar00rootroot00000000000000## HOW TO CONTRIBUTE TO TXT2HTML DEVELOPMENT txt2html is available at https://github.com/resurrecting-open-source-projects/txt2html If you are interested in contribute to txt2html development, please, follow these steps: 1. Send me a patch that fix an issue or that implement a new feature. Alternatively, you can do a 'pull request'[1] in GitHub. [1] https://help.github.com/articles/using-pull-requests 2. Ask for join to txt2html project in GitHub, if you want to work officially. Note that this second step is not compulsory. However, to accept you in project, I need a minimum collaboration before. To find issues and bugs to fix, you can check these addresses: - https://github.com/resurrecting-open-source-projects/txt2html/issues - https://bugs.debian.org/cgi-bin/pkgreport.cgi?dist=unstable;package=txt2html - https://bugs.launchpad.net/ubuntu/+source/txt2html/+bugs If you want to join, please contact me: eriberto at eriberto.pro.br -- Eriberto, Thu, 01 Aug 2019 21:55:53 -0300 txt2html-2.53/ChangeLog000066400000000000000000000577051352116237600150270ustar00rootroot00000000000000Revision History for txt2html ============================= 2.53 2019-08-02 * New repository for this project (now in GitHub). https://github.com/resurrecting-open-source-projects/txt2html * Added CONTRIBUTING.md file. * Added README.md and renamed old README file to README.txt2html. * Fixed the licensing in LICENSE file. * Fixed some spelling errors. * Fixed the path for Perl in scripts/txt2html. * Unified the changelogs. | ----------------------- | | ---- OLD CHANGELOG ---- | \ / ---- OLD UPSTREAM ---- \ / · ----------------------- · 2.52.01 (aka 2.5201) 2013-05-21 ------------------------------- * 2013-05-21 16:25:10 +1000 rebuilding with new version * 2012-05-11 14:20:41 +1000 Updating website. 2.51 Sun 4th March 2008 - fixed bug with underscores in links - fixed docs about escape_chars (should be escapechars) - fixed docs about DOCTYPE 2.50 Sat 22nd December 2007 - fixed bug with formatting and punctuation - removed old reference-to-an-array argument method - made --xhtml true by default (used to be false) - moved the debugging options to global variables 2.46 Fri 9th November 2007 - updated docs on custom_heading_regexp - fixed bug with xhtml output - documented all undocumented functions 2.45 Fri 26th January 2007 - fixed bug with umlauts - fixed bug with UTF-8 characters - added --underline_delimiter option. 2.44 Tue 17th January 2006 - fixed bug with delimiter tables - minor documentation fixes 2.43 Fri 7th October 2005 - fixed bug with interaction between #bolding# and #anchor links 2.42 Wed 10th August 2005 - new option to txt2html script: --instring, which enables one to process a string instead of a file. - new options to HTML::TextToHTML: * instring, as above * inhandle, which enables one to pass in input file handles to process * outhandle, which enables one to pass in an output file handle 2.41 Sun 8th May 2005 - solved the system links dictionary problem! No longer uses an external file at all, uses the DATA handle. This means that there is no longer a --system_link_dict option. - changed versioning scheme; now bugfix versions will be things like 2.4101 - removed the run_txt2html command; it isn't needed when the txt2html script is part of the package and does things much nicer. - generate the README from the PoD 2.40 Sat 12th February 2005 - much improved speed 2.37 Thu 10th February 2005 - another fix to installation - fixed CPAN module problem 2.36 Sun 23rd January 2005 - slight fix to installation 2.35 Wed 18th January 2005 - fixed bug where a Dos file was processed on a Unix system. - removed Makefile.PL; not needed with modern perls 2.34 Thu 6th January 2005 - fixed another bug with demoronize code (gah!) 2.33 Wed 5th January 2005 - darn, left out some files! 2.32 Wed 5th January 2005 - fixed bug with demoronize code - fixed documentation for lower_case_tags - changed around installation so that no custom Module::Builder is needed; also moved files into more customary places, and now use Filter::Simple to change the system dictionary path in the module and script files for installation. 2.31 Tue 21st September 2004 - fixed bug with install - did some changes to help version-changing 2.30 Fri 27th August 2004 - changed build system over to Module::Build to eliminate problems with different versions of ExtUtils::MakeMaker and the installation of the system links dictionary, as well as hoping to make the installation more portable. - changed build so that the system links dictionary (in defaults and documentation) is automatically set to where the system links dictionary is going to be installed (yay!) - improved the INSTALL document (thanks to Mark Schmidt) - improved the bold and italic processing (now it's not messed up by short lines putting a
in) - bug fix for paragraphs with "0" (thanks to Andrew Williams) 2.25 Sun 23rd May 2004 - the default location for the system links dictionary (txt2html.dict) is now "/usr/local/share/txt2html/txt2html.dict". (It uses SITEPREFIX not PREFIX now) - added --bold_delimiter and --italic_delimiter options; now the bold and italic matching is done separately, not as part of the links-dictionary stuff. This means it's much easier to change or turn off if you don't want it. - links-dictionary matching is now done on segments without structural tags in them so matching for things like '^

' should be replaced with just '^'. I don't think this will break anything, and will prevent certain kinds of illegal substitutions. - tidied up some of the links in the links dictionary 2.24 Sun 16th May 2004 - bug fixes for preformatting: fixed up loss of trailing PRE, and now preformats and lists no longer have a trailing blank line - documented the 'quote_mail' and 'quote_explicit' classes, and added the 'mail_header' class for mail-header paragraphs. - made the #bold# and *italic* matches more aggressive. - added Alan Jackson's "demoronize" patch from John Walker's demoronize script at 2.23 Wed 25th February 2004 - oops! Forgot to include one of the test files! 2.22 Sun 22nd February 2004 - bug fix with delimiter table 2.21 Sat 10th January 2004 - bugfixes with a stricter perl 5.8.2 - bugfix for processing empty file 2.20 Sun 7th December 2003 - added --table_type option to say which types of table will be recognised and parsed if the --make_tables option is true. In other words, there are now new types of table which can be parsed. * ALIGN is the original space-aligned table type * PGSQL is the type of table you get from a Postgresql query * BORDER is a table with +-----+ lines around it as a border * DELIM is delimited columns 2.10 Sat 6th December 2003 - changed process_para method to assume it has only one paragraph; and added process_chunk method to deal with processing strings which may contain more than one paragraph in them. - a fair few internal changes to make more things think in terms of paragraphs rather than lines; this changes the parsing of a few things, but doesn't break the conventions. - fixed a bug where unordered lists were allowed to have bullets which were more than one character wide. Well, I considered it a bug, it was annoying me. - added --bullets and --bullets_ordered options to enable the user to define the bullet characters used for unordered and ordered lists. - hooray! Figured out a way of having multi-paragraph list items! - woo hoo! Added definition lists! And managed to do it so that they are treated like the other lists, that is, you can nest lists in definition lists and visa versa. 2.06 Sun 15th November 2003 - fixed bug with processing STDIN (ie piping input to txt2html) - moved test input files into separate tfiles directory - added in most of Seth's old test files to the testing; and fixed resulting bugs that were flushed out of cover 2.05 Wed 5th November 2003 - error in fix to PREFIX! Argh! 2.04 Tue 4th November 2003 - changed Makefile.PL to fix PREFIX - use "#!/usr/bin/env perl" trick (courtesy of Sami Haahtinen) instead of using ExtUtils::configPL module - made Getopt::ArgvFile an official prerequisite - enabled CAPS tagging to be optional (just give an empty caps_tag) 2.03 Tue 15th July 2003 - fixed bug with para tests (it didn't fail on my system because it was using the already installed system links dictionary) 2.02 Sun 13th July 2003 - fixed bug in documentation about custom headings - moved tests into t/ directory - added is_fragment option to process_para to enable it to process a fragment without assuming that it was a paragraph. 2.01 Sun 1st June 2003 - fixed up a few documentation/reference things that I'd forgotten, changing names in sample.txt for example. 2.00 Sat 31st May 2003 - merge of HTML::TextToHTML and the official txt2html - hence the version jump. * the distribution name is now txt2html * renamed texthyper to txt2html, TextToHTML.dict to txt2html.dict * merged change history * split README into README, INSTALL and LICENSE files * updated DEVNOTES - merged in the changes from 1.28 to 1.35 as much as I could * corrected bugs that still applied * added --style_url option * added --body_deco option * added two CSS classes: quote_mail and quote_explicit - Did Not add the following, as it was rather more complicated: * multi-paragraph list items * the heading_callback_customize stuff ================================================== 1.12 Sat 15th February 2002 - removed heavily spammed email address from documentation and examples. 1.11 Fri 20th December 2002 - fixed bug in texthyper script which was giving warnings. 1.10 Wed 18th December 2002 - removed all dependency on AppConfig * all of the existing options now must use their full names. * However, one now has the choice between passing options as a hash, or the old way, as a reference to an array. - removed the do_help method; if you want the documentation of the module, use perldoc HTML::TextToHTML - moved the texthyper script into this distribution * It now uses Getopt::Long and Getopt::ArgvFile. * The format of .texthyperrc has changed to conform with Getopt::ArgvFile rather than AppConfig. * Changed the version number so that it was bigger than either the script or the module so that both could have the same version number (that's why the big jump). - the included system link dictionary (TextToHTML.dict) is now installed in /usr/share/txt2html as part of the install process. 0.09 Wed 20th November 2002 - improved the XHTML mode, so that open paragraphs get closed sooner. This fixed a bug related to paragraphs inside lists. 0.08 Wed 20th November 2002 - CPAN testers complained about a lack of explicitly stating all the dependencies of AppConfig, which either means that AppConfig has changed desperately, or their testing methods have changed, since I didn't think it was possible to get the AppConfig module without getting all its dependent modules, but, oh well. 0.07 Sun 17th November 2002 - fixed a bug in process_para to ensure that if one is using it standalone, any open lists will be closed - added --lower_case_tags option to force the tags to be output in lower-case - first pass at XHTML conformance; added --xhtml option. It isn't that pretty-looking, but the sample does pass the scrutiny of "tidy". When turned on it: * forces lower-case on * makes empty tags have the empty marker (eg


) * closes all open P and LI tags where they should be closed * table cell alignments are done as style attributes 0.06 Mon 2nd September 2002 - fine-tuned some of the links in the default links dictionary - some internal rewriting 0.05 Wed 5th June 2002 - fixed minor bugs 0.04 Sun 2nd June 2002 - fixed bug with detection of paragraphs by indentation - added --indent_par_break and --preserve_indent options - fixed error in documentation - fixed bug with nonexistant link dictionaries 0.03 Sun 26th May 2002 - documented the format of the Link Dictionary - added the do_help method, and changed the behaviour of --help and --manpage - added the --make_anchors option, which enables one to disable the making of anchors, so that if one prefers another method of anchor-making (such as that in HTML::GenToc) then one can use that instead. - altered the #bold# pattern in the link dictionary to only need one hash. This should still hopefully allow things like #1 without turning it bold, and being able to use ### as a separator. - gratuitous self-promotion: added HTML::GenToc to the sample links dictionary - removed the need for getline(), but rather pass the lines in to the methods, in order to parse by-paragraph and then by-line (mucho rewrite) which enabled me to: * implement the table-parsing from Gareth Rees's HTML::FromText module -- added the --make_tables option * now the links dictionary does multiline matches (useful for things like italics which break over lines) * enable converting passed-in strings rather than just files 0.02 Wed 15th May 2002 - fixed bug with link dictionary parsing - improved the tests - updated link dictionary to fix a few bugs (eg underlines) and add a few things (like using double # for ##bold## text). 0.01 Sun 12th May 2002 - conversion of Seth Golub's txt2html (version 1.28) to a module - made all global settings options (eg the location of the system link dictionary) - added "outfile" option - added use_mosaic_header option - changed the dynamic code generation completely. - removed the evil $* variable ----------------------------------------------------------------- ===================================================== (cvs log on Sourceforge) revision 1.35 date: 2002/12/03 03:47:46; author: suntong; state: Exp; lines: +14 -13 - Defines two CSS Style: quote_mail & quote_explicit - Mail quote mode and quote mode won't interfere with each other ---------------------------- revision 1.34 date: 2002/12/03 01:51:41; author: suntong; state: Exp; lines: +8 -7 - preformat should be dealed before other cases ---------------------------- revision 1.33 date: 2002/12/02 23:44:13; author: suntong; state: Exp; lines: +7 -7 Bug fixing (details in http://groups.yahoo.com/group/txt2html/message/89): - Changed incorrect entity names of "fraqfrac*" to "frac*". - redundant \| in [\||:] removed. - change misleading --style help to '--style ' ---------------------------- revision 1.32 date: 2002/12/01 19:59:09; author: suntong; state: Exp; lines: +39 -5 - Add Callback functions for HTML header handling so that users can customise their own heading, add horizon lines, change colors or write their own toc, etc - User can define/keep their callbacks locally without tampering main distribution - 'mailstuff' priority should be higher than 'preformat' ---------------------------- revision 1.31 date: 2002/12/01 18:59:30; author: suntong; state: Exp; lines: +5 -5 - solve the problem that txt2html can't html-ify its own anchor. ---------------------------- revision 1.30 date: 2002/12/01 18:51:20; author: suntong; state: Exp; lines: +53 -10 - All my previous patches are lost because yahoogroups doesn't keep my patch attachements. So, here they are in a big chunk. Major updates are: - Able to use a style sheet for the generated html file - Able to use body decoration for the generated html file customize your own background color/image/sound, etc... - Misc enhancements. ---------------------------- revision 1.29 date: 2002/12/01 18:28:35; author: suntong; state: Exp; lines: +3 -2 - Apply patch from http://groups.yahoo.com/group/txt2html/message/32 ,----- | I don't know when I'll get around to releasing a new version of | txt2html, but I have a few fixes I've been sitting on. I thought | I'd send them out on this list so people could take advantage of | them without having to wait until I finally package up a new release. | | * Changed incorrect entity names of "fraq*" to "frac*". | | * Allow paragraphs within lists by permitting blank lines within | list elements, as long as the following text has the same | indentation level. `----- ======================================================= 1.28 ---- - bugfix: reserved characters in titles created with --titlefirst are now escaped properly. - bugfix: when preformatting entire document, each line was getting its own
 container (introduced
  with explicit preformatting feature in 1.26).

- dict: added some characters to those allowed in http urls (=&;,).

- dict: added "-" to allowed characters within *emphasized-pattern*.

1.27
----

- Changed names of default link dictionaries to txt2html.dict


1.26 (not released)
-------------------

- Added -8 (for 8-bit-clean) to disable conversion of non-ASCII
  characters to their corresponding Latin-1 character entities.

- Added -pm to allow explicit marking of preformatted text in source

- Changes => to , in mapping, to stay compatible with Perl 4

- Added debug flag 4, for observing link rules in action

- Fixed length checking bug in header underline analysis

- Change a regexp so Perl 5.6 doesn't complain.

- No longer add space after 
  • tags - Allow unindented lists to start after CAPS lines - Use · as a bullet character - Fixed bug that dropped a character when certain actions were taken on the last line of input that didn't end with a newline. - Added more aggressive regexps for _underlined_ and *emphasized* text. - Improved character markup rules - Added link rule for news URLs. (This must have been accidentally deleted at some point.) - Added link rule for common explicit url markup: 1.25 ---- - Changed the official home page to (the old page will have a working redirect indefinitely.) - Added a LICENSE to the distribution. (modified BSD-style) - When no title is specified, an empty title element is inserted. (The old behavior was to omit the title element, which is forbidden by the spec.) - Made heading anchors appear inside the heading, rather than surrounding it (which is forbidden by the HTML spec) - Changed the DTD name - Added the --linkonly option so people can use the links dictionary feature without doing any other markup. This is useful for adding links to HTML fragments or documents. - Added the --prepend_body option for prepending HTML to the body. - Made in_link_context smarter so it won't link on attributes or tag names. (This is good for adding hyperlinks, but may screw up some clever uses of the linking code.) - Added link rules for _underlined text_ and *emphasized text* - Added --noescapechars to suppress converting "&" "<" and ">" into "&" "<" and ">" - Changed pattern rules to handle non-ascii letters properly in matching patterns. - Added conversion of non-ascii letters into character entities. - Lots of upgrades to the links dictionary patterns 1.24 ---- - Changed behavior of custom headers to something much more useful: Header levels are assigned by regex in order seen. When a line matches a custom header regex, it is tagged as a header. If it's the first time that particular regex has matched, the next available header level is associated with it and applied to the line. Any later matches of that regex will use the same header level. - Added the -EH / --explicit-headings option - Added some unnecessary initialization to avoid warnings when perl is run with the -w switch. 1.23 ---- - Added handling for when the consistent formatting of numbered lists is the position of the non-numeric character, not the amount of whitespace preceding the number. (The numbers grow to the left instead of the right.) 1.22 ---- - Fixed bug in unhyphenation - Changed HTML version in default doctype line to 3.2 1.21 ---- - Added 1.20 ---- - Added DOCTYPE tag and --doctype options. - Syntax change to get rid of Perl 5 warning - Added ability to use the first line of the text as the title - Fixed some (unused) grossness in links dict file 1.19 ---- - Added --append_head - Mail and News name anchor surrounds just the first word ("Newsgroups:" or "From"), and not the whole line. That way, newsgroup names and email addresses get HREF'd as normal. 1.18 ---- - Cleaned up nested list handling & fixed a bug under Perl 5. - Changed a couple minor things to get rid of some of the Perl 5 warnings. 1.17 ---- - Lists can start even when not indented and not preceded by a blank line if the previous line was short or a header. - New flag "o" added for dictionary entries. Specifies that the link should only be done the first time a match is found. 1.16 ---- - Added anchoring of custom headers - Took the changelog out of the script - Tweaked $line_indent in sub liststuff - Insert

    before each mail/news message 1.15 ---- - Fixed options handling for -e/+e , -r - Added "Newsgroups:" to trigger mail headers - Fixed anchor naming - took out -T option, since it isn't implemented yet. Whoops.. - Fixed bug in endpreformat 1.14 ---- - Fixed +l/--nolink option handling - Fixed major bug in dynamic_make_dictionary_links that allowed nested links under some circumstances. 1.13 ---- - Fixed usage message so it matches options. (whoops) - Added custom heading style feature 1.12 ---- - Fixed bug in heading regexp - Changed underline tolerance parameters from min & max length difference to length difference & offset difference - Centralized line reading, added handling of DOS carriage returns - Switched to heading style stack. Styles still very limited. - Changed heading anchor names from a simple count to a hierarchical section number. 1.11 ---- - Blank lines are never considered underlined - Shortline breaking slightly more intelligent (or at least different) - Paragraph breaks much more intelligent - Lowercased tags. Style is so fickle. - Added links dictionaries, link making, etc. - Allow repeated bullet chars for unordered lists. (Tiny mod to regexp) - switched order of caps & liststuff in main() - improved untabify() so it converts the whole line, not just beginning - split up all lines >79 characters to avoid common downloading error (people would sometimes copy the script off the display, inadvertently adding a few newlines in bad places in the code) - Handles option "--" now. - Accepts named files as input as alternative to stdin - Deals with stdin properly (no more extra EOFs needed) - Improved mail handling 1.10 ==== - Added --extract, etc. 1.9 --- - Changed from #!/usr/local/bin/perl to the more clever version in the man page. (How did I manage not to read this for so long?) - Swapped hrule & header back to handle double lines. Why should this order screw up headers? 1.8 --- - put mail_anchor back in. (Why did I take this out?) - Finally added handling of lettered lists (ordered lists marked with letters) - Added title option (--title, -t) - Shortline now looks at how long the line was before txt2html started adding tags. ($line_length) - Changed list references to scalars where appropriate. (@foo[0] -> $foo[0]) - Added untabify() to homogenize leading indentation for list prefixes and functions that use line length - Added "underline tolerance" for when underlines are not exactly the same length as what they underline. - Added error message for unrecognized options - removed \w matching on --capstag - Tagline now removes leading & trailing whitespace before tagging - swapped order of caps & heading in main loop - Cleaned up code for speed and to get rid of warnings - Added more restrictions to something being a mail header - Added indentation for lists, just to make the output more readable. - Fixed major bug in lists: $OL and $UL were never set, so when a list was ended "" was *always* used! - swapped order of hrule & header to properly handle long underlines 1.7 --- - Added to comments in options section - renamed blank to is_blank - Page break is converted to horizontal rule


    - moved usage subroutine up top so people who look through code see it sooner 1.6 --- - Creates anchors at each heading 1.5 --- - Fixed minor bug in Headers - Preformatting can be set to only start/stop when TWO lines of [non]formatted-looking-text are encountered. Old behavior is still possible through command line options (-pb 1 -pe 1). - Can preformat entire document (-pb 0) or disable preformatting completely (-pe 0). - Fixed minor bug in CAPS handling (paragraph breaks broke) - Puts paragraph tags *before* paragraphs, not just between them. 1.4 --- - Allow ':' for numbered lists (e.g. "1: Figs") - Whitespace at end of line will not start or end preformatting - Mailmode is now off by default - Doesn't break short lines if they are the first line in a list item. It *should* break them anyway if the next line is a continuation of the list item, but I haven't dealt with this yet. - Added action on lines that are all capital letters. You can change how these lines get tagged, as well as the minimum number of consecutive capital letters required to fire off this action. 1.3 --- - Tiny bugfix in unhyphenation 1.2 --- - Added unhyphenation seth@aigeek.com txt2html-2.53/DEVNOTES000066400000000000000000000047261352116237600144220ustar00rootroot00000000000000Developer Notes =============== This uses Dist::Zilla for building/testing/release. Changing the version -------------------- 1. Edit the dist.ini file to increment the version 2. Replace the old version number with the new version in the tfiles files. 3. "dzil test" Generating README -------------------------- Make the README changes in HTML/TextToHTML.pm Dist::Zilla will generate the README from that. Adding Options -------------- All new options need to be added in five places: - lib/HTML/TextToHTML.pm init_our_args(), to initialize the default - lib/HTML/TextToHTML.pm args() in the parse-the-array-ref part, unless it is a simple option-with-a-value. If it is a boolean option, it also needs to be added in its "no" form. - lib/HTML/TextToHTML.pm OPTIONS documentation - scripts/txt2html Getopt call, including its type and possible shortnames - scripts/txt2html OPTIONS documentation Changing the Global Link Dictionary ----------------------------------- The contents of the global link dictionary are kept inside lib/HTML/TextToHTML.pm in the __DATA__ section. Any changes or updates to it must be done there. Release Notes ============= Before releasing, don't forget to run dzil test dzil build # for a sanity check of the build dzil release (and usually "dzil install" as well) This bundle was released in three different external places in early: - CPAN - Sourceforge - FreshMeat Currently, txt2html is available in GitHub. CPAN Release ------------ Dist::Zilla will do the CPAN release as part of the release process. Sourceforge Release ------------------- Do a git push if you haven't already. Go to the Admin/Files section and follow the instructions. You will need to ftp upload the .tar.gz file to upload.sourceforge.net /incoming directory before doing certain steps. One also needs to update the web-page. Cd to txt2html/web/htdocs on your home machine, and edit index.html to update the version number. Then do make del_cpfiles make cpfiles make git add git commit git push cd .. make install (The last copies it over with rsync) One should also post a message to the txt2html mailing list. FreshMeat Release ----------------- Log in to freshmeat.net, and follow the instructions for new releases. The "changes this release" will need to be a summary of the changes. Since the file is on sourceforge, you won't need to alter the download URL. GitHub ------ Please, go to https://github.com/resurrecting-open-source-projects/txt2html txt2html-2.53/LICENSE000066400000000000000000000003621352116237600142450ustar00rootroot00000000000000Copyright 1994-2000 Seth Golub seth AT aigeek.com Copyright 2002-2013 Kathryn Andersen Copyright 2018-2019 Joao Eriberto Mota Filho This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. txt2html-2.53/MANIFEST000066400000000000000000000034751352116237600144010ustar00rootroot00000000000000Build.PL ChangeLog CONTRIBUTING.md DEVNOTES doc/UPDATE-CHECK LICENSE MANIFEST MANIFEST.SKIP META.yml README.md README.txt2html TODO lib/HTML/TextToHTML.pm scripts/txt2html t/00-compile.t t/10para.t t/20tfiles.t t/25handles.t t/30sample.t t/50xsample.t t/70bugs.t t/release-distmeta.t t/release-has-version.t t/release-pod-coverage.t t/release-pod-syntax.t t/release-portability.t tfiles/custom-headers.txt tfiles/custom-headers2.txt tfiles/empty.txt tfiles/good_custom-headers.html tfiles/good_custom-headers2.html tfiles/good_empty.html tfiles/good_heading1.html tfiles/good_hyphens.html tfiles/good_links.html tfiles/good_links2.html tfiles/good_links3.html tfiles/good_links4.html tfiles/good_list-2.html tfiles/good_list-3.html tfiles/good_list-4.html tfiles/good_list-5.html tfiles/good_list-advanced.html tfiles/good_list-custom.html tfiles/good_list-styles.html tfiles/good_list.html tfiles/good_mixed.html tfiles/good_news.html tfiles/good_pre.html tfiles/good_pre2.html tfiles/good_punct.html tfiles/good_robo.html tfiles/good_sample.html tfiles/good_table-align.html tfiles/good_table-border.html tfiles/good_table-delim.html tfiles/good_table-pgsql.html tfiles/good_table-pgsql2.html tfiles/good_umlauttest.html tfiles/good_utf8.html tfiles/good_xhtml_sample.html tfiles/heading1.txt tfiles/hyphens.txt tfiles/links.txt tfiles/links2.txt tfiles/links3.txt tfiles/links4.txt tfiles/list-2.txt tfiles/list-3.txt tfiles/list-4.txt tfiles/list-5.txt tfiles/list-advanced.txt tfiles/list-custom.txt tfiles/list-styles.txt tfiles/list.txt tfiles/mixed.txt tfiles/news.txt tfiles/pre.txt tfiles/pre2.txt tfiles/punct.txt tfiles/robo.txt tfiles/sample.foot tfiles/sample.foot2 tfiles/sample.txt tfiles/table-align.txt tfiles/table-border.txt tfiles/table-delim.txt tfiles/table-pgsql.txt tfiles/table-pgsql2.txt tfiles/umlauttest.txt tfiles/utf8.txt txt2html-2.53/MANIFEST.SKIP000066400000000000000000000005111352116237600151320ustar00rootroot00000000000000# version control files \bRCS\b \bCVS\b ,v$ \.svn\b # archives .*\.tar\.gz$ # the TODO file ^\.todo$ # other files # MakeMaker files ^Makefile$ ^blib/ ^MakeMaker-\d pm_to_blib # Module::Build files ^_build/ ^Build$ # development files ^dist.ini$ ^profiling/ # temp, old, backup files ~$ \.old$ \.bak$ \.tmp$ \.# \.swp$ ^#.*#$ txt2html-2.53/META.yml000066400000000000000000000011341352116237600145070ustar00rootroot00000000000000--- abstract: 'convert plain text file to HTML.' author: - 'Kathryn Andersen ' build_requires: File::Find: 0 File::Temp: 0 Module::Build: 0.3601 Test::More: 0 warnings: 0 configure_requires: Module::Build: 0.3601 dynamic_config: 0 generated_by: 'Dist::Zilla version 4.300034, CPAN::Meta::Converter version 2.120921' license: gpl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: txt2html requires: File::Basename: 0 Getopt::Long: 0 Pod::Usage: 0 YAML::Syck: 0 constant: 0 perl: v5.8.1 strict: 0 version: 2.53 txt2html-2.53/README.md000066400000000000000000000050671352116237600145260ustar00rootroot00000000000000# txt2html **Convert plain text file to HTML**

    **1. HELP THIS PROJECT**
    **2. WHAT IS TXT2HTML?**
    **3. WHAT IS TXT2HTML NOT?**
    **4. HOW TO INSTALL AND USE**
    -------------------- 1. HELP THIS PROJECT -------------------- txt2html needs your help. **If you are a Perl programmer** and if you wants to help a nice project, this is your opportunity. My name is Eriberto and **I am not a Perl developer**. I imported txt2html from its old repositories[1][2] to GitHub (the original developer is inactive[3]). After this, I applied all patches found in Debian project and other places for this program. All my work was registered in ChangeLog file (version 2.53 and later releases). I also maintain txt2html packaged in Debian[4]. If you are interested to help txt2html, read the [CONTRIBUTING.md](CONTRIBUTING.md) file. [1] http://txt2html.sourceforge.net [2] https://metacpan.org/release/txt2html [3] Kathryn Andersen (RUBYKAT) told me in a private email message that is inactive because a personal problem. So, txt2html needs help! [4] https://tracker.debian.org/pkg/txt2html -------------------- 2. WHAT IS TXT2HTML? -------------------- txt2html is a Perl program that converts plain text to HTML, using HTML::TextToHTML Perl module. It supports headings, 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. txt2html can also be used to aid in writing new HTML documents, but there are probably better ways of doing that. ------------------------ 3. WHAT IS TXT2HTML NOT? ------------------------ txt2html is not a program to convert wordprocessor files or other marked-up document formats. It is also not a program to convert HTML to text. Most HTML browsers do that. If you need to convert something other than plain text to HTML, or you need to convert from HTML, you should look for a more appropriate tool. txt2html is not a program for automatically generating a table-of-contents from a file. If you want that, then use txt2html to generate a HTML file, and then use htmltoc or hypertoc on the HTML file. ------------------------- 4. HOW TO INSTALL AND USE ------------------------- Please, read the README.txt2html file and generated manpages txt2html(1) and HTML::TextToHTML(3). txt2html-2.53/README.txt2html000066400000000000000000001300641352116237600157100ustar00rootroot00000000000000NAME HTML::TextToHTML - convert plain text file to HTML VERSION version 2.53 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) 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. 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. UPDATING: currently, the project is available on GitHub at https://github.com/resurrecting-open-source-projects/txt2html 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 a hash of arguments. Note that all option-names must match exactly -- no abbreviations are allowed. 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. 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 correct HTML. i.e. do not have things like: Mary Andersen but instead, have: Mary Andersen <kitty@example.com> (default: nothing) 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 correct HTML. i.e. do not have things like: Mary Andersen but instead, have: Mary Andersen <kitty@example.com> (default: nothing) 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'". 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: #) 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) 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) 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. custom_heading_regexp custom_heading_regexp=>\@custom_headings Add patterns for headings. Header levels are assigned by regexp in the order seen in the input text. 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: my @custom_headings = ('^ *\d+\. \w+', '^ *\d+\.\d+\. \w+', '^ *\d+\.\d+\.\d+\. \w+'); ... custom_heading_regexp=>\@custom_headings, ... 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 "explicit_headings" option. This expects a reference to an array of strings. (default: none) 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') demoronize demoronize=>1 Convert Microsoft-generated character codes that are non-ISO codes into something more reasonable. (default:true) doctype doctype=>I This gets put in the DOCTYPE field at the top of the document, unless it's empty. Default : '-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd' If xhtml is true, the contents of this is ignored, unless it's empty, in which case no DOCTYPE declaration is output. eight_bit_clean eight_bit_clean=>1 If false, convert Latin-1 characters to HTML entities. If true, this conversion is disabled; also "demoronize" is set to false, since this also changes 8-bit characters. (default: false) escape_HTML_chars escape_HTML_chars=>1 turn & < > into & > < (default: true) 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 custom_heading_regexp option. (default: false) 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) hrule_min hrule_min=>I Min number of ---s for an HRule. (default: 4) indent_width indent_width=>I Indents this many spaces for each level of a list. (default: 2) 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) infile infile=>\@my_files infile=>['chapter1.txt', 'chapter2.txt'] The name of the input file(s). This expects a reference to an array of filenames. The special filename '-' designates STDIN. See also "inhandle" and "instring". (default:-) inhandle inhandle=>\@my_handles inhandle=>[\*MYINHANDLE, \*STDIN] An array of input filehandles; use this instead of "infile" or "instring" to use a filehandle or filehandles as input. instring instring=>\@my_strings instring=>[$string1, $string2] An array of input strings; use this instead of "infile" or "inhandle" to use a string or strings as input. 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: *) underline_delimiter underline_delimiter=>I This defines what character (or string) is taken to be the delimiter of text which is to be interpreted as underlined (that is, to be given a U tag). If this is empty, no underlining of text will be done. (default: _) links_dictionaries links_dictionaries=>\@my_link_dicts links_dictionaries=>['url_links.dict', '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. This expects a reference to an array of filenames. 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) lower_case_tags lower_case_tags=>1 Force all tags to be in lower-case. 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) make_anchors make_anchors=>0 Should we try to make anchors in headings? (default: true) 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) make_tables make_tables=>1 Should we try to build tables? If true, spots tables and marks them up appropriately. See "Input File Format" 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) min_caps_length min_caps_length=>I min sequential CAPS for an all-caps line (default: 3) outfile outfile=>I The name of the output file. If it is "-" then the output goes to Standard Output. (default: - ) outhandle The output filehandle; if this is given then the output goes to this filehandle instead of to the file given in "outfile". par_indent par_indent=>I Minimum number of spaces indented in first lines of paragraphs. Only used when there's no blank line preceding the new paragraph. (default: 2) 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)
    
        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.
    
        preformat_start_marker
                preformat_start_marker=>I
    
            What flags the start of a preformatted section if
            --use_preformat_marker is true.
    
            (default: "^(:?(:?<)|<)PRE(:?(:?>)|>)\$")
    
        preformat_end_marker
                preformat_end_marker=>I
    
            What flags the end of a preformatted section if
            --use_preformat_marker is true.
    
            (default: "^(:?(:?<)|<)/PRE(:?(:?>)|>)\$")
    
        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 tab_width is 8 and this is 5, then one
            tab may be expanded to 8 spaces, which is enough to trigger
            preformatting. (default: 5)
    
        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 correct HTML.
    
            (default: nothing)
    
        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)
    
        short_line_length
                short_line_length=>I
    
            Lines this short (or shorter) must be intentionally broken and are
            kept that short. (default: 40)
    
        style_url
                style_url=>I
    
            This gives the URL of a stylesheet; a LINK tag will be added to the
            output.
    
        tab_width
                tab_width=>I
    
            How many spaces equal a tab? (default: 8)
    
        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)
    
        title
                title=>I
    
            You can specify a title. Otherwise it will use a blank one.
            (default: nothing)
    
        titlefirst
                titlefirst=>1
    
            Use the first non-blank line as the title. (See also "title")
    
        underline_length_tolerance
                underline_length_tolerance=>I<n>
    
            How much longer or shorter can underlines be and still be
            underlines? (default: 1)
    
        underline_offset_tolerance
                underline_offset_tolerance=>I<n>
    
            How far offset can underlines be and still be underlines? (default:
            1)
    
        unhyphenation
                unhyphenation=>0
    
            Enables unhyphenation of text. (default: true)
    
        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)
    
        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)
    
        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.
    
            (default: true)
    
    DEBUGGING
        There are global variables for setting types and levels of debugging.
        These should only be used by developers.
    
        $HTML::TextToHTML::Debug
            $HTML::TextToHTML::Debug = 1;
    
            Enable copious debugging output. (default: false)
    
        $HTML::TextToHTML::DictDebug
                $HTML::TextToHTML::DictDebug = I<n>;
    
            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)
    
    METHODS
      new
            $conv = new HTML::TextToHTML()
    
            $conv = new HTML::TextToHTML(titlefirst=>1,
                ...
            );
    
        Create a new object with new. If arguments are given, these arguments
        will be used in invocations of other methods.
    
        See "OPTIONS" for the possible values of the arguments.
    
      args
            $conv->args(short_line_length=>60,
                titlefirst=>1,
                ....
            );
    
        Updates the current arguments/options of the HTML::TextToHTML object.
        Takes hash of arguments, which will be used in invocations of other
        methods. See "OPTIONS" for the possible values of the arguments.
    
      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 "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 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.
    
      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
        "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 "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 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.
    
      txt2html
            $conv->txt2html(%args);
    
        Convert a text file to HTML. Takes a hash of arguments. See "OPTIONS"
        for the possible values of the arguments. Arguments which have already
        been set with new or args will remain as they are, unless they are
        overridden.
    
    PRIVATE METHODS
        These are methods used internally, only of interest to developers.
    
      init_our_data
        $self->init_our_data();
    
        Initializes the internal object data.
    
      deal_with_options
        $self->deal_with_options();
    
        do extra processing related to particular options
    
      escape
        $newtext = escape($text);
    
        Escape & < and >
    
      demoronize_char
        $newtext = demoronize_char($text);
    
        Convert Microsoft character entities into characters.
    
        Added by Alan Jackson, alan at ajackson dot org, and based on the
        demoronize script by John Walker, http://www.fourmilab.ch/
    
      demoronize_code
        $newtext = demoronize_code($text);
    
        convert Microsoft character entities into HTML code
    
      get_tag
        $tag = $self->get_tag($in_tag);
    
        $tag = $self->get_tag($in_tag, tag_type=>TAG_START, inside_tag=>'');
    
        output the tag wanted (add the <> and the / if necessary) - output in
        lower or upper case - do tag-related processing options:
        tag_type=>TAG_START | tag_type=>TAG_END | tag_type=>TAG_EMPTY (default
        start) inside_tag=>string (default empty)
    
      close_tag
        $tag = $self->close_tag($in_tag);
    
        close the open tag
    
      hrule
           $self->hrule(para_lines_ref=>$para_lines,
                     para_action_ref=>$para_action,
                     ind=>0);
    
        Deal with horizontal rules.
    
      shortline
            $self->shortline(line_ref=>$line_ref,
                             line_action_ref=>$line_action_ref,
                             prev_ref=>$prev_ref,
                             prev_action_ref=>$prev_action_ref,
                             prev_line_len=>$prev_line_len);
    
        Deal with short lines.
    
      is_mailheader
            if ($self->is_mailheader(rows_ref=>$rows_ref))
            {
                ...
            }
    
        Is this a mailheader line?
    
      mailheader
            $self->mailheader(rows_ref=>$rows_ref);
    
        Deal with a mailheader.
    
      mailquote
            $self->mailquote(line_ref=>$line_ref,
                             line_action_ref=>$line_action_ref,
                             prev_ref=>$prev_ref,
                             prev_action_ref=>$prev_action_ref,
                             next_ref=>$next_ref);
    
        Deal with quoted mail.
    
      subtract_modes
            $newvector = subtract_modes($vector, $mask);
    
        Subtracts modes listed in $mask from $vector.
    
      paragraph
            $self->paragraph(line_ref=>$line_ref,
                             line_action_ref=>$line_action_ref,
                             prev_ref=>$prev_ref,
                             prev_action_ref=>$prev_action_ref,
                             line_indent=>$line_indent,
                             prev_indent=>$prev_indent,
                             is_fragment=>$is_fragment,
                             ind=>$ind);
    
        Detect paragraph indentation.
    
      listprefix
            ($prefix, $number, $rawprefix, $term) = $self->listprefix($line);
    
        Detect and parse a list item.
    
      startlist
            $self->startlist(prefix=>$prefix,
                             number=>0,
                             rawprefix=>$rawprefix,
                             term=>$term,
                             para_lines_ref=>$para_lines_ref,
                             para_action_ref=>$para_action_ref,
                             ind=>0,
                             prev_ref=>$prev_ref,
                             total_prefix=>$total_prefix);
    
        Start a list.
    
      endlist
            $self->endlist(num_lists=>0,
                prev_ref=>$prev_ref,
                line_action_ref=>$line_action_ref);
    
        End N lists
    
      continuelist
            $self->continuelist(para_lines_ref=>$para_lines_ref,
                                para_action_ref=>$para_action_ref,
                                ind=>0,
                                term=>$term);
    
        Continue a list.
    
      liststuff
            $self->liststuff(para_lines_ref=>$para_lines_ref,
                             para_action_ref=>$para_action_ref,
                             para_line_indent_ref=>$para_line_indent_ref,
                             ind=>0,
                             prev_ref=>$prev_ref);
    
        Process a list (higher-level method).
    
      get_table_type
            $table_type = $self->get_table_type(rows_ref=>$rows_ref,
                                                para_len=>0);
    
        Figure out the table type of this table, if any
    
      is_aligned_table
            if ($self->is_aligned_table(rows_ref=>$rows_ref, para_len=>0))
            {
                ...
            }
    
        Check if the given paragraph-array is an aligned table
    
      is_pgsql_table
            if ($self->is_pgsql_table(rows_ref=>$rows_ref, para_len=>0))
            {
                ...
            }
    
        Check if the given paragraph-array is a Postgresql table (the ascii
        format produced by Postgresql)
    
        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)
    
      is_border_table
            if ($self->is_border_table(rows_ref=>$rows_ref, para_len=>0))
            {
                ...
            }
    
        Check if the given paragraph-array is a Border table.
    
        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 +------+-----+
    
      is_delim_table
            if ($self->is_delim_table(rows_ref=>$rows_ref, para_len=>0))
            {
                ...
            }
    
        Check if the given paragraph-array is a Delimited table.
    
        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 |
    
      tablestuff
            $self->tablestuff(table_type=>0,
                              rows_ref=>$rows_ref,
                              para_len=>0);
    
        Process a table.
    
      make_aligned_table
            $self->make_aligned_table(rows_ref=>$rows_ref,
                                      para_len=>0);
    
        Make an Aligned table.
    
      make_pgsql_table
            $self->make_pgsql_table(rows_ref=>$rows_ref,
                                      para_len=>0);
    
        Make a PGSQL table.
    
      make_border_table
            $self->make_border_table(rows_ref=>$rows_ref,
                                     para_len=>0);
    
        Make a BORDER table.
    
      make_delim_table
            $self->make_delim_table(rows_ref=>$rows_ref,
                                    para_len=>0);
    
        Make a Delimited table.
    
      is_preformatted
            if ($self->is_preformatted($line))
            {
                ...
            }
    
        Returns true if the passed string is considered to be preformatted.
    
      split_end_explicit_preformat
            $front = $self->split_end_explicit_preformat(para_ref=>$para_ref);
    
        Modifies the given string, and returns the front preformatted part.
    
      endpreformat
            $self->endpreformat(para_lines_ref=>$para_lines_ref,
                                para_action_ref=>$para_action_ref,
                                ind=>0,
                                prev_ref=>$prev_ref);
    
        End a preformatted section.
    
      preformat
            $self->preformat(mode_ref=>$mode_ref,
                             line_ref=>$line_ref,
                             line_action_ref=>$line_action_ref,
                             prev_ref=>$prev_ref,
                             next_ref=>$next_ref,
                             prev_action_ref);
    
        Detect and process a preformatted section.
    
      make_new_anchor
            $anchor = $self->make_new_anchor($heading_level);
    
        Make a new anchor.
    
      anchor_mail
            $self->anchor_mail($line_ref);
    
        Make an anchor for a mail section.
    
      anchor_heading
            $self->anchor_heading($heading_level, $line_ref);
    
        Make an anchor for a heading.
    
      heading_level
            $self->heading_level($style);
    
        Add a new heading style if this is a new heading style.
    
      is_ul_list_line
            if ($self->is_ul_list_line($line))
            {
                ...
            }
    
        Tests if this line starts a UL list item.
    
      is_heading
            if ($self->is_heading(line_ref=>$line_ref, next_ref=>$next_ref))
            {
                ...
            }
    
        Tests if this line is a heading. Needs to take account of the next line,
        because a standard heading is defined by "underlining" the text of the
        heading.
    
      heading
            $self->heading(line_ref=>$line_ref,
                next_ref=>$next_ref);
    
        Make a heading. Assumes is_heading is true.
    
      is_custom_heading
            if ($self->is_custom_heading($line))
            {
                ...
            }
    
        Check if the given line matches a custom heading.
    
      custom_heading
            $self->custom_heading(line_ref=>$line_ref);
    
        Make a custom heading. Assumes is_custom_heading is true.
    
      unhyphenate_para
            $self->unhyphenate_para($para_ref);
    
        Join up hyphenated words that are split across lines.
    
      tagline
            $self->tagline($tag, $line_ref);
    
        Put the given tag around the given line.
    
      iscaps
            if ($self->iscaps($line))
            {
                ...
            }
    
        Check if a line is all capitals.
    
      caps
            $self->caps(line_ref=>$line_ref,
                        line_action_ref=>$line_action_ref);
    
        Detect and deal with an all-caps line.
    
      do_delim
            $self->do_delim(line_ref=>$line_ref,
                            line_action_ref=>$line_action_ref,
                            delim=>'*',
                            tag=>'STRONG');
    
        Deal with a line which has words delimited by the given delimiter; this
        is used to deal with italics, bold and underline formatting.
    
      glob2regexp
            $regexp = glob2regexp($glob);
    
        Convert very simple globs to regexps
    
      add_regexp_to_links_table
            $self->add_regexp_to_links_table(label=>$label,
                                             pattern=>$pattern,
                                             url=>$url,
                                             switches=>$switches);
    
        Add the given regexp "link definition" to the links table.
    
      add_literal_to_links_table
            $self->add_literal_to_links_table(label=>$label,
                                              pattern=>$pattern,
                                              url=>$url,
                                              switches=>$switches);
    
        Add the given literal "link definition" to the links table.
    
      add_glob_to_links_table
            $self->add_glob_to_links_table(label=>$label,
                                           pattern=>$pattern,
                                           url=>$url,
                                           switches=>$switches);
    
        Add the given glob "link definition" to the links table.
    
      parse_dict
            $self->parse_dict($dictfile, $dict);
    
        Parse the dictionary file. (see also load_dictionary_links, for things
        that were stripped)
    
      setup_dict_checking
            $self->setup_dict_checking();
    
        Set up the dictionary checking.
    
      in_link_context
            if ($self->in_link_context($match, $before))
            {
                ...
            }
    
        Check if we are inside a link (<a ...>); certain kinds of substitution
        are not allowed here.
    
      apply_links
            $self->apply_links(para_ref=>$para_ref,
                               para_action_ref=>$para_action_ref);
    
        Apply links and formatting to this paragraph.
    
      check_dictionary_links
            $self->check_dictionary_links(line_ref=>$line_ref,
                                          line_action_ref=>$line_action_ref);
    
        Check (and alter if need be) the bits in this line matching the patterns
        in the link dictionary.
    
      load_dictionary_links
            $self->load_dictionary_links();
    
        Load the dictionary links.
    
      do_file_start
            $self->do_file_start($outhandle, $para);
    
        Extra stuff needed for the beginning: HTML headers, and prepending a
        file if desired.
    
      do_init_call
            $self->do_init_call();
    
        Certain things, like reading link dictionaries, need to be done only
        once.
    
    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.
    
      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 explicitly 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>
    
        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>
    
        The i flag
    
        This turns on ignore case in the pattern matching.
    
        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.
    
        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/
    
      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.
    
        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.
    
        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    |
            +---------+---------+
    
        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.
    
        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.
    
    EXAMPLES
            use HTML::TextToHTML;
    
      Create a new object
            my $conv = new HTML::TextToHTML();
    
            my $conv = new HTML::TextToHTML(title=>"Wonderful Things",
                                    default_link_dict=>$my_link_file,
              );
    
      Add further arguments
            $conv->args(short_line_length=>60,
                       preformat_trigger_lines=>4,
                       caps_tag=>"strong",
              );
    
      Convert a file
            $conv->txt2html(infile=>[$text_file],
                             outfile=>$html_file,
                             title=>"Wonderful Things",
                             mail=>1
              );
    
      Make a pipleline
            open(IN, "ls |") or die "could not open!";
            $conv->txt2html(inhandle=>[\*IN],
                             outfile=>'-',
              );
    
    NOTES
        *   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.
    
    REQUIRES
        HTML::TextToHTML requires Perl 5.8.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:
    
            YAML::Syck
    
    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.
    
    BUGS
        Please, send to
        https://github.com/resurrecting-open-source-projects/txt2html/issues
    
    SEE ALSO
        perl txt2html.
    
    AUTHOR
            Kathryn Andersen (RUBYKAT)
            perlkat AT katspace dot com
            http//www.katspace.com/
    
        based on txt2html by Seth Golub
    
        Current homepage is
        https://github.com/resurrecting-open-source-projects/txt2html
    
    COPYRIGHT AND LICENCE
        Original txt2html script copyright (c) 1994-2000 Seth Golub <seth AT
        aigeek.com>
    
        Copyright (c) 2002-2005 by Kathryn Andersen
    
        Copyright (c) 2018-2019 Joao Eriberto Mota Filho
    
        This program is free software; you can redistribute it and/or modify it
        under the same terms as Perl itself.
    
    ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/TODO����������������������������������������������������������������������������������0000664�0000000�0000000�00000002131�13521162376�0013724�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������TODO list for txt2html
    ======================
      5. try to make this more thread-safe
        Added:19/01/07, 09:29  Priority: high
    
      6. add in an "obfustcate email addresses" facility
        Added:08/11/04, 15:19  Priority: medium
    
      7. convert (c) (r) and (tm) to the correct entities (add to links)
        Added:08/11/04, 15:20  Priority: medium
    
      8. add optional "enhanced" definition lists detection, which does Term:
        Defintion
        Added:08/11/04, 15:20  Priority: medium
    
      9. recognise and reproduce different Ordered List styles.
        Added:08/11/04, 15:20  Priority: medium
    
     10. links-per-section
        Added:08/11/04, 15:21  Priority: medium
    
     11. tables with multi-line cells
        Added:08/11/04, 15:21  Priority: medium
    
     12. option to add section-numbers to headers (not just header anchors)
        Added:08/11/04, 15:22  Priority: medium
    
          1. allow starting section number to be user-defined
            Added:08/11/04, 15:22  Priority: medium
    
     13. make this more efficient
        Added:23/01/05, 14:42  Priority: medium
    
     14. make a proper CGI script as an example
        Added:17/05/05, 22:09  Priority: medium
    
    ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/doc/����������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13521162376�0014004�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/doc/UPDATE-CHECK����������������������������������������������������������������������0000664�0000000�0000000�00000000226�13521162376�0015524�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������When updating, change the following files (if needed):
    
    - ChangeLog
    - Change version in all needed files (use rpl)
    - Update MANIFEST
    - Test in Debian
    ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/lib/����������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13521162376�0014005�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/lib/HTML/�����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13521162376�0014551�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/lib/HTML/TextToHTML.pm����������������������������������������������������������������0000664�0000000�0000000�00000471264�13521162376�0017041�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������package HTML::TextToHTML;
    {
      $HTML::TextToHTML::VERSION = '2.53';
    }
    use 5.8.1;
    use strict;
    #------------------------------------------------------------------------
    
    =head1 NAME
    
    HTML::TextToHTML - convert plain text file to HTML.
    
    =head1 VERSION
    
    version 2.53
    
    =head1 SYNOPSIS
    
      From the command line:
    
        txt2html I<arguments>
    
      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. UPDATING: currently, the project is available on GitHub
    at https://github.com/resurrecting-open-source-projects/txt2html
    
    =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 a hash of arguments.
    
    Note that all option-names must match exactly -- no abbreviations are
    allowed.  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.
    
    =over
    
    =item append_file
    
        append_file=>I<filename>
    
    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 correct HTML.  i.e. do not have things like:
        Mary Andersen E<lt>kitty@example.comE<gt>
    but instead, have:
        Mary Andersen <kitty@example.com>
    
    (default: nothing)
    
    =item append_head
    
        append_head=>I<filename>
    
    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 correct HTML.  i.e. do not have things like:
        Mary Andersen E<lt>kitty@example.comE<gt>
    but instead, have:
        Mary Andersen <kitty@example.com>
    
    (default: nothing)
    
    =item body_deco
    
        body_deco=>I<string>
    
    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<string>
    
    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<string>
    
    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<string>
    
    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>
    
    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=>\@custom_headings
    
    Add patterns for headings.  Header levels are assigned by regexp in the
    order seen in the input text. 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:
    
        my @custom_headings = ('^ *\d+\. \w+',
    			   '^ *\d+\.\d+\. \w+',
    			   '^ *\d+\.\d+\.\d+\. \w+');
    
        ...
    	custom_heading_regexp=>\@custom_headings,
        ...
    
    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 "explicit_headings"
    option.
    
    This expects a reference to an array of strings.
    
    (default: none)
    
    =item default_link_dict
    
        default_link_dict=>I<filename>
    
    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 doctype
    
        doctype=>I<doctype>
    
    This gets put in the DOCTYPE field at the top of the document, unless it's
    empty.
    
    Default :
    '-//W3C//DTD HTML 4.01//EN"
    "http://www.w3.org/TR/html4/strict.dtd'
    
    If B<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
    
    If false, convert Latin-1 characters to HTML entities.
    If true, this conversion is disabled; also "demoronize" is set to
    false, since this also changes 8-bit characters.
    (default: false)
    
    =item escape_HTML_chars
    
        escape_HTML_chars=>1
    
    turn & E<lt> E<gt> 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 custom_heading_regexp option.
    (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<n>
    
    Min number of ---s for an HRule.
    (default: 4)
    
    =item indent_width
    
        indent_width=>I<n>
    
    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 <BR> and three non-breaking spaces instead.
    (see also --preserve_indent)
    (default: false)
    
    =item infile
    
        infile=>\@my_files
        infile=>['chapter1.txt', 'chapter2.txt']
    
    The name of the input file(s).  
    This expects a reference to an array of filenames.
    
    The special filename '-' designates STDIN.
    
    See also L</inhandle> and L</instring>.
    
    (default:-)
    
    =item inhandle
    
        inhandle=>\@my_handles
        inhandle=>[\*MYINHANDLE, \*STDIN]
    
    An array of input filehandles; use this instead of
    L</infile> or L</instring> 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</infile> or L</inhandle> to use a string or strings
    as input.
    
    =item italic_delimiter
    
        italic_delimiter=>I<string>
    
    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 underline_delimiter
    
        underline_delimiter=>I<string>
    
    This defines what character (or string) is taken to be the delimiter of
    text which is to be interpreted as underlined (that is, to be given a U
    tag).  If this is empty, no underlining of text will be done.
    (default: _)
    
    =item links_dictionaries
    
        links_dictionaries=>\@my_link_dicts
        links_dictionaries=>['url_links.dict', '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.  This expects a reference to an array of filenames.
    
    =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</Input File Format> 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<n>
    
    min sequential CAPS for an all-caps line
    (default: 3)
    
    =item outfile
    
        outfile=>I<filename>
    
    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</outfile>.
    
    =item par_indent
    
        par_indent=>I<n>
    
    Minimum 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<n>
    
    How many lines of preformatted-looking text are needed to switch to <PRE>
              <= 0 : Preformat entire document
                 1 : one line triggers
              >= 2 : two lines trigger
    
    (default: 2)
    
    =item endpreformat_trigger_lines
    
        endpreformat_trigger_lines=>I<n>
    
    How many lines of unpreformatted-looking text are needed to switch from <PRE>
               <= 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<regexp>
    
    What flags the start of a preformatted section if --use_preformat_marker
    is true.
    
    (default: "^(:?(:?<)|<)PRE(:?(:?>)|>)\$")
    
    =item preformat_end_marker
    
        preformat_end_marker=>I<regexp>
    
    What flags the end of a preformatted section if --use_preformat_marker
    is true.
    
    (default: "^(:?(:?<)|<)/PRE(:?(:?>)|>)\$")
    
    =item preformat_whitespace_min
    
        preformat_whitespace_min=>I<n>
    
    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<tab_width> 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<filename>
    
    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 correct 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<n>
    
    Lines this short (or shorter) must be intentionally broken and are kept
    that short.
    (default: 40)
    
    =item style_url
    
        style_url=>I<url>
    
    This gives the URL of a stylesheet; a LINK tag will be added to the
    output.
    
    =item tab_width
    
        tab_width=>I<n>
    
    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<title>
    
    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. (See also "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.
    
    (default: true)
    
    =back
    
    =head1 DEBUGGING
    
    There are global variables for setting types and levels
    of debugging.  These should only be used by developers.
    
    =over
    
    =item $HTML::TextToHTML::Debug
    
    $HTML::TextToHTML::Debug = 1;
        
    Enable copious debugging output.
    (default: false)
    
    =item $HTML::TextToHTML::DictDebug
    
        $HTML::TextToHTML::DictDebug = I<n>;
    
    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)
    
    =back
    
    =cut
    
    our $Debug = 0;
    our $DictDebug = 0;
    
    =head1 METHODS
    
    =cut
    
    #------------------------------------------------------------------------
    use YAML::Syck;
    
    our $PROG = 'HTML::TextToHTML';
    
    #------------------------------------------------------------------------
    
    ########################################
    # 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;
    
    # Constants for tags
    use constant {
        TAG_START	=> 1,
        TAG_END	=> 2,
        TAG_EMPTY	=> 3,
    };
    
    # 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 arguments are given, 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 hash of arguments, which will be used in invocations of other
    methods.
    See L</OPTIONS> for the possible values of the arguments.
    
    =cut
    
    sub args
    {
        my $self      = shift;
        my %args = @_;
    
        if (%args)
        {
            if ($Debug)
            {
                print STDERR "========args(hash)========\n";
                print STDERR Dump(%args);
            }
    	my $arg;
    	my $val;
    	while (($arg, $val) = each %args)
            {
                if (defined $val)
                {
                    if ($arg =~ /^-/)
                    {
                        $arg =~ s/^-//;    # get rid of first dash
                        $arg =~ s/^-//;    # get rid of possible second dash
                    }
                    if ($Debug)
                    {
                        print STDERR "--", $arg;
                    }
                    $self->{$arg} = $val;
                    if ($Debug)
                    {
                        print STDERR " ", $val, "\n";
                    }
                }
            }
        }
        $self->deal_with_options();
        if ($Debug)
        {
            print STDERR Dump($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 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 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/underline 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} && !$self->{eight_bit_clean})
        {
            $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.  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 ($DictDebug & 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;
    }
    
    =head1 PRIVATE METHODS
    
    These are methods used internally, only of interest to developers.
    
    =cut
    
    #---------------------------------------------------------------#
    # Init-related subroutines
    
    =head2 init_our_data
    
    $self->init_our_data();
    
    Initializes the internal object data.
    
    =cut
    sub init_our_data ($)
    {
        my $self = shift;
    
        #
        # 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->{doctype}                    = '-//W3C//DTD HTML 4.01//EN"
    "http://www.w3.org/TR/html4/strict.dtd';
        $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_delimiter}        = '_';
        $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}                      = 1;
    
        # accumulation variables
        $self->{__file}               = "";    # Current file being processed
        $self->{__heading_styles}     = {};
        $self->{__num_heading_styles} = 0;
        $self->{__links_table}        = {};
        $self->{__links_table_order}  = [];
        $self->{__links_table_patterns} = {};
        $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
        #
        my $system_dict = <<'EOT';
    #
    # 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\@)([[:alpha:]][\w\.+\-]+\.[[:alpha:]]{2,}):(\s*)([\w\d+\-/\.]+)|
      -h-> $1<A HREF="ftp://$2/$4">$2:$4</A>$3
    
    # ftp@<site>:<path>
    |(ftp\@)([[:alpha:]][\w\.+\-]+\.[[:alpha:]]{2,}):(\s*)([\w\d+\-/\.]+)|
      -h-> $1<A HREF="ftp://$2/$4">$2:$4</A>$3
    
    # Email address
    |[[:alnum:]_\+\-\.]+\@([[:alnum:]][\w\.+\-]+\.[[:alpha:]]{2,})|
      -> mailto:$&
    
    # <site>:<path>
    |([^\w\-/\.:\@>])([[:alpha:]][\w\.+\-]+\.[[:alpha:]]{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 ([[:alpha:]][\w+\-]+(\.[\w\.+\-]+)+\.[[:alpha:]]{2,})\s+(\d{2,4})|
      -h-> telnet <A HREF="telnet://$1:$3/">$1 $3</A>
    
    # ftp <site>
    |ftp ([[:alpha:]][\w+\-]+(\.[\w\.+\-]+)+\.[[:alpha:]]{2,})|
      -h-> ftp <A HREF="ftp://$1/">$1</A>
    
    # host with "ftp" in the machine name
    |\b([[:alpha:]][\w])*ftp[\w]*(\.[\w+\-]+){2,}| -h-> ftp <A HREF="ftp://$&/">$&</A>
    
    # ftp.foo.net/blah/
    |ftp(\.[\w\@:-]+)+/\S+| -> ftp://$&
    
    # www.thehouse.org/txt2html/
    |www(\.[\w\@:-]+)+/\S+| -> http://$&
    
    # host with "www" in the machine name
    |\b([[:alpha:]][\w])*www[\w]*(\.[\w+\-]+){2,}| -> http://$&/
    
    # <site> <port>
    |([[:alpha:]][\w+\-]+\.[\w+\-]+\.[[:alpha:]]{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
    
    # Mark _underlined stuff_ as <U>underlined stuff</U>
    # Don't mistake variable names for underlines, and
    # take account of possible trailing punctuation
    #/([ \t\n])_([[:alpha:]][[:alnum:]\s-]*[[:alpha:]])_([\s\.;:,\!\?])/ -h-> $1<U>$2</U>$3
    
    # Seth and his amazing conversion program    :-)
    
    "Seth Golub"  -o-> http://www.aigeek.com/
    "txt2html"    -o-> https://github.com/resurrecting-open-source-projects/txt2html
    
    # Kathryn and her amazing modules 8-)
    "Kathryn Andersen"  -o-> http://www.katspace.com/
    "HTML::TextToHTML"  -o-> http://www.katspace.com/tools/text_to_html/
    "hypertoc"          -o-> http://www.katspace.com/tools/hypertoc/
    "HTML::GenToc"      -o-> http://www.katspace.com/tools/hypertoc/
    
    # End of global dictionary
    EOT
    
        # pre-parse the above data by removing unwanted lines
        # skip lines that start with '#'
        $system_dict =~ s/^\#.*$//mg;
        # skip lines that end with unescaped ':'
        $system_dict =~ s/^.*[^\\]:\s*$//mg;
    
        $self->{__global_links_data} = $system_dict;
    
    }    # init_our_data
    
    #---------------------------------------------------------------#
    # txt2html-related subroutines
    
    =head2 deal_with_options
    
    $self->deal_with_options();
    
    do extra processing related to particular options
    
    =cut
    sub deal_with_options ($)
    {
        my $self = shift;
    
        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});
    }
    
    =head2 escape
    
    $newtext = escape($text);
    
    Escape & < and >
    
    =cut
    sub escape ($)
    {
        my ($text) = @_;
        $text =~ s/&/&/g;
        $text =~ s/>/>/g;
        $text =~ s/</</g;
        return $text;
    }
    
    =head2 demoronize_char
    
    $newtext = demoronize_char($text);
    
    Convert Microsoft character entities into characters.
    
    Added by Alan Jackson, alan at ajackson dot org, and based
    on the demoronize script by John Walker, http://www.fourmilab.ch/
    
    =cut
    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;
    }
    
    =head2 demoronize_code
    
    $newtext = demoronize_code($text);
    
    convert Microsoft character entities into HTML code
    
    =cut
    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;
    }
    
    =head2 get_tag
    
    $tag = $self->get_tag($in_tag);
    
    $tag = $self->get_tag($in_tag,
    	tag_type=>TAG_START,
    	inside_tag=>'');
    
    output the tag wanted (add the <> and the / if necessary)
    - output in lower or upper case
    - do tag-related processing
    options:
      tag_type=>TAG_START | tag_type=>TAG_END | tag_type=>TAG_EMPTY
      (default start)
      inside_tag=>string (default empty)
    
    =cut
    sub get_tag ($$;%)
    {
        my $self   = shift;
        my $in_tag = shift;
        my %args   = (
            tag_type   => TAG_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} != TAG_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} != TAG_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} == TAG_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} != TAG_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} != TAG_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} == TAG_END)
            {
                # close the DD before the list closes
                $tag_prefix = $self->close_tag('dd');
            }
        }
    
        my $out_tag = $in_tag;
        if ($args{tag_type} == TAG_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} == TAG_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 ($DictDebug & 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
    
    =head2 close_tag
    
    $tag = $self->close_tag($in_tag);
    
    close the open tag
    
    =cut
    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 ($DictDebug & 8)
        {
            print STDERR
    "close_tag: open_tag = '${open_tag}', in_tag = '${in_tag}', out_tag = '$out_tag'\n";
        }
    
        return $out_tag;
    }
    
    =head2 hrule
    
       $self->hrule(para_lines_ref=>$para_lines,
    	     para_action_ref=>$para_action,
    	     ind=>0);
    
    Deal with horizontal rules.
    
    =cut
    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 => TAG_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 => TAG_EMPTY);
            $para_lines_ref->[$ind] =~ s/\014/\n${tag}\n/g;
        }
    }
    
    =head2 shortline
    
        $self->shortline(line_ref=>$line_ref,
    		     line_action_ref=>$line_action_ref,
    		     prev_ref=>$prev_ref,
    		     prev_action_ref=>$prev_action_ref,
    		     prev_line_len=>$prev_line_len);
    
    Deal with short lines.
    
    =cut
    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 => TAG_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;
        }
    }
    
    =head2 is_mailheader
    
        if ($self->is_mailheader(rows_ref=>$rows_ref))
        {
    	...
        }
    
    Is this a mailheader line?
    
    =cut
    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
    
    =head2 mailheader
    
        $self->mailheader(rows_ref=>$rows_ref);
    
    Deal with a mailheader.
    
    =cut
    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 => TAG_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 => TAG_EMPTY);
                    chomp $rows[$rn];
                    $rows[$rn] =~ s/$/${tag}\n/;
                }
            }
        }
        @{$rows_ref} = @rows;
    
    }    # mailheader
    
    =head2 mailquote
    
        $self->mailquote(line_ref=>$line_ref,
    		     line_action_ref=>$line_action_ref,
    		     prev_ref=>$prev_ref,
    		     prev_action_ref=>$prev_action_ref,
    		     next_ref=>$next_ref);
    
    Deal with quoted mail.
    
    =cut
    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 => TAG_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;
            }
        }
    }
    
    =head2 subtract_modes
        
        $newvector = subtract_modes($vector, $mask);
    
    Subtracts modes listed in $mask from $vector.
    
    =cut
    sub subtract_modes ($$)
    {
        my ($vector, $mask) = @_;
        return ($vector | $mask) - $mask;
    }
    
    =head2 paragraph
    
        $self->paragraph(line_ref=>$line_ref,
    		     line_action_ref=>$line_action_ref,
    		     prev_ref=>$prev_ref,
    		     prev_action_ref=>$prev_action_ref,
    		     line_indent=>$line_indent,
    		     prev_indent=>$prev_indent,
    		     is_fragment=>$is_fragment,
    		     ind=>$ind);
    
    Detect paragraph indentation.
    
    =cut
    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 => TAG_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 => TAG_EMPTY);
            ${$prev_ref} .= $tag;
            ${$prev_ref} .= " " x $line_indent;
            ${$line_ref} =~ s/^ {$line_indent}//;
            ${$prev_action_ref} |= $BREAK;
            ${$line_action_ref} |= $IND_BREAK;
        }
    }
    
    =head2 listprefix
    
        ($prefix, $number, $rawprefix, $term) = $self->listprefix($line);
    
    Detect and parse a list item.
    
    =cut
    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+|[[:alpha:]]|[' . "${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
    
    =head2 startlist
    
        $self->startlist(prefix=>$prefix,
    		     number=>0,
    		     rawprefix=>$rawprefix,
    		     term=>$term,
    		     para_lines_ref=>$para_lines_ref,
    		     para_action_ref=>$para_action_ref,
    		     ind=>0,
    		     prev_ref=>$prev_ref,
    		     total_prefix=>$total_prefix);
    
    Start a list.
    
    =cut
    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
    
    =head2 endlist
    
        $self->endlist(num_lists=>0,
    	prev_ref=>$prev_ref,
    	line_action_ref=>$line_action_ref);
    
    End N lists
    
    =cut
    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 => TAG_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 => TAG_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 => TAG_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
    
    =head2 continuelist
    
        $self->continuelist(para_lines_ref=>$para_lines_ref,
    			para_action_ref=>$para_action_ref,
    			ind=>0,
    			term=>$term);
    
    Continue a list.
    
    =cut
    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 => TAG_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
    
    =head2 liststuff
    
        $self->liststuff(para_lines_ref=>$para_lines_ref,
    		     para_action_ref=>$para_action_ref,
    		     para_line_indent_ref=>$para_line_indent_ref,
    		     ind=>0,
    		     prev_ref=>$prev_ref);
    
    Process a list (higher-level method).
    
    =cut
    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
    
    =head2 get_table_type
    
        $table_type = $self->get_table_type(rows_ref=>$rows_ref,
    					para_len=>0);
    
    Figure out the table type of this table, if any
    
    =cut
    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;
    }
    
    =head2 is_aligned_table
    
        if ($self->is_aligned_table(rows_ref=>$rows_ref, para_len=>0))
        {
    	...
        }
    
    Check if the given paragraph-array is an aligned table
    
    =cut
    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;
        }
    }
    
    =head2 is_pgsql_table
    
        if ($self->is_pgsql_table(rows_ref=>$rows_ref, para_len=>0))
        {
    	...
        }
    
    Check if the given paragraph-array is a Postgresql table
    (the ascii format produced by Postgresql)
    
    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)
    
    =cut
    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 must have at least 4 rows (see above).
        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;
    }
    
    =head2 is_border_table
    
        if ($self->is_border_table(rows_ref=>$rows_ref, para_len=>0))
        {
    	...
        }
    
    Check if the given paragraph-array is a Border table.
    
    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 +------+-----+
    
    =cut
    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 must have at least 5 rows (see above)
        # 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
    
    =head2 is_delim_table
    
        if ($self->is_delim_table(rows_ref=>$rows_ref, para_len=>0))
        {
    	...
        }
    
    Check if the given paragraph-array is a Delimited table.
    
    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 |
    
    =cut
    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};
    
        #
        # 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*([^[:alnum:]])/)
        {
            $delim = $1;
            # have to get rid of ^ and [] and \
            $delim =~ s/\^//g;
            $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
    
    =head2 tablestuff
    
        $self->tablestuff(table_type=>0,
    		      rows_ref=>$rows_ref,
    		      para_len=>0);
    
    Process a table.
    
    =cut
    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
    
    =head2 make_aligned_table
    
        $self->make_aligned_table(rows_ref=>$rows_ref,
    			      para_len=>0);
    
    Make an Aligned table.
    
    =cut
    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 => TAG_END);
            $rows[$#rows] .= "\n${tag}";
            @{$rows_ref} = @rows;
            return 1;
        }
        else
        {
            return 0;
        }
    }    # make_aligned_table
    
    =head2 make_pgsql_table
    
        $self->make_pgsql_table(rows_ref=>$rows_ref,
    			      para_len=>0);
    
    Make a PGSQL table.
    
    =cut
    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 => TAG_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 => TAG_END);
            $tab_lines[$#tab_lines] =~ s/\n/${tag}\n/;
        }
    
        # replace the rows
        @{$rows_ref} = @tab_lines;
    }    # make_pgsql_table
    
    =head2 make_border_table
    
        $self->make_border_table(rows_ref=>$rows_ref,
    			     para_len=>0);
    
    Make a BORDER table.
    
    =cut
    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 => TAG_END);
        push @tab_lines, "$tag\n";
    
        # replace the rows
        @{$rows_ref} = @tab_lines;
    }    # make_border_table
    
    =head2 make_delim_table
    
        $self->make_delim_table(rows_ref=>$rows_ref,
    			    para_len=>0);
    
    Make a Delimited table.
    
    =cut
    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*([^[:alnum:]])/)
        {
            $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 => TAG_END);
        push @tab_lines, "$tag\n";
    
        # replace the rows
        @{$rows_ref} = @tab_lines;
    }    # make_delim_table
    
    =head2 is_preformatted
    
        if ($self->is_preformatted($line))
        {
    	...
        }
    
    Returns true if the passed string is considered to be preformatted.
    
    =cut
    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;
    }
    
    =head2 split_end_explicit_preformat
    
        $front = $self->split_end_explicit_preformat(para_ref=>$para_ref);
    
    Modifies the given string, and returns the front preformatted part.
    
    =cut
    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
    
    =head2 endpreformat
    
        $self->endpreformat(para_lines_ref=>$para_lines_ref,
    			para_action_ref=>$para_action_ref,
    			ind=>0,
    			prev_ref=>$prev_ref);
    
    End a preformatted section.
    
    =cut
    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
    
    =head2 preformat
    
        $self->preformat(mode_ref=>$mode_ref,
    		     line_ref=>$line_ref,
    		     line_action_ref=>$line_action_ref,
    		     prev_ref=>$prev_ref,
    		     next_ref=>$next_ref,
    		     prev_action_ref);
    
    Detect and process a preformatted section.
    
    =cut
    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
    
    =head2 make_new_anchor
    
        $anchor = $self->make_new_anchor($heading_level);
    
    Make a new anchor.
    
    =cut
    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
    
    =head2 anchor_mail
    
        $self->anchor_mail($line_ref);
    
    Make an anchor for a mail section.
    
    =cut
    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
    
    =head2 anchor_heading
    
        $self->anchor_heading($heading_level, $line_ref);
    
    Make an anchor for a heading.
    
    =cut
    sub anchor_heading ($$$)
    {
        my $self     = shift;
        my $level    = shift;
        my $line_ref = shift;
    
        if ($DictDebug & 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 ($DictDebug & 8)
        {
            print STDERR "anchor_heading(after): ", ${$line_ref}, "\n";
        }
    }    # anchor_heading
    
    =head2 heading_level
    
        $self->heading_level($style);
    
    Add a new heading style if this is a new heading style.
    
    =cut
    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
    
    =head2 is_ul_list_line
    
        if ($self->is_ul_list_line($line))
        {
    	...
        }
    
    Tests if this line starts a UL list item.
    
    =cut
    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;
    }
    
    =head2 is_heading
    
        if ($self->is_heading(line_ref=>$line_ref, next_ref=>$next_ref))
        {
    	...
        }
    
    Tests if this line is a heading.  Needs to take account of the
    next line, because a standard heading is defined by "underlining"
    the text of the heading.
    
    =cut
    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
    
    =head2 heading
        
        $self->heading(line_ref=>$line_ref,
    	next_ref=>$next_ref);
    
    Make a heading.
    Assumes is_heading is true.
    
    =cut
    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
    
    =head2 is_custom_heading
    
        if ($self->is_custom_heading($line))
        {
    	...
        }
    
    Check if the given line matches a custom heading.
    
    =cut
    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
    
    =head2 custom_heading
    
        $self->custom_heading(line_ref=>$line_ref);
    
    Make a custom heading.  Assumes is_custom_heading is true.
    
    =cut
    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
    
    =head2 unhyphenate_para
    
        $self->unhyphenate_para($para_ref);
    
    Join up hyphenated words that are split across lines.
    
    =cut
    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
    
    =head2 tagline
    
        $self->tagline($tag, $line_ref);
    
    Put the given tag around the given line.
    
    =cut
    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
    
    =head2 iscaps
    
        if ($self->iscaps($line))
        {
    	...
        }
    
    Check if a line is all capitals.
    
    =cut
    sub iscaps
    {
        my $self = shift;
        local ($_) = @_;
    
        my $min_caps_len = $self->{min_caps_length};
    
        /^[^[:lower:]<]*[[:upper:]]{$min_caps_len,}[^[:lower:]<]*$/;
    }    # iscaps
    
    =head2 caps
    
        $self->caps(line_ref=>$line_ref,
    		line_action_ref=>$line_action_ref);
    
    Detect and deal with an all-caps line.
    
    =cut
    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
    
    =head2 do_delim
    
        $self->do_delim(line_ref=>$line_ref,
    		    line_action_ref=>$line_action_ref,
    		    delim=>'*',
    		    tag=>'STRONG');
    
    Deal with a line which has words delimited by the given delimiter;
    this is used to deal with italics, bold and underline formatting.
    
    =cut
    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 '#')  
        {
            if (${$line_ref} =~ m/\B#([[:alpha:]])#\B/s)
    	{
    	    ${$line_ref} =~ s/\B#([[:alpha:]])#\B/<${tag}>$1<\/${tag}>/gs;
    	}
    	# special treatment of # for the #num case and the #link case
    	if (${$line_ref} !~ m/<[aA]/)
    	{
    	    ${$line_ref} =~
    s/#([^\d#](?![^#]*(?:<li>|<LI>|<P>|<p>))[^#]*[^# \t\n])#/<${tag}>$1<\/${tag}>/gs;
    	}
    	else
    	{
    	    my $line_with_links = '';
    	    my $linkme = '';
    	    my $unmatched = ${$line_ref};
    	    while ($unmatched =~ 
    		   m/#([^\d#](?![^#]*(?:<li>|<LI>|<P>|<p>))[^#]*[^# \t\n])#/s)
    	    {
    		$line_with_links .= $`;
    		$linkme = $&;
    		$unmatched = $';
    		if (!$self->in_link_context($linkme, $line_with_links))
    		{
    		    $linkme =~
    			s/#([^\d#](?![^#]*(?:<li>|<LI>|<P>|<p>))[^#]*[^# \t\n])#/<${tag}>$1<\/${tag}>/gs;
    		}
    		$line_with_links .= $linkme;
    	    }
    	    ${$line_ref} = $line_with_links . $unmatched;
    	}
        }
        elsif ($delim eq '^')
        {
            ${$line_ref} =~
    s/\^((?![^^]*(?:<li>|<LI>|<p>|<P>))(\w|["'<>])[^^]*)\^/<${tag}>$1<\/${tag}>/gs;
            ${$line_ref} =~ s/\B\^([[:alpha:]])\^\B/<${tag}>$1<\/${tag}>/gs;
        }
        elsif ($delim eq '_')
        {
            if (${$line_ref} =~ m/\B_([[:alpha:]])_\B/s)
    	{
    	    ${$line_ref} =~ s/\B_([[:alpha:]])_\B/<${tag}>$1<\/${tag}>/gs;
    	    ${$line_ref} =~
    		s#(?<![_[:alnum:]])_([^_]+?[[:alnum:]"'\.\?\&;:<>])_#<${tag}>$1</${tag}>#gs;
    	}
    	else
    	{
    	    # make sure we don't wallop links that have underscores
    	    # need to make sure that _ delimiters are not mistaken for
    	    # a_variable_name
    	    my $line_with_links = '';
    	    my $linkme = '';
    	    my $unmatched = ${$line_ref};
    	    while ($unmatched =~ 
    			m#(?<![_[:alnum:]])_([^_]+?[[:alnum:]"'\.\?\&;:<>])_#s)
    	    {
    		$line_with_links .= $`;
    		$linkme = $&;
    		$unmatched = $';
    		if (!$self->in_link_context($linkme, $line_with_links))
    		{
    		    $linkme =~
    			s#(?<![_[:alnum:]])_([^_]+?[[:alnum:]"'\.\?\&;:<>])_#<${tag}>$1</${tag}>#gs;
    		}
    		$line_with_links .= $linkme;
    	    }
    	    ${$line_ref} = $line_with_links . $unmatched;
    	}
        }
        elsif (length($delim) eq 1)    # one-character, general
        {
            if (${$line_ref} =~ m/\B[${delim}]([[:alpha:]])[${delim}]\B/s)
    	{
    	    ${$line_ref} =~ s/\B[${delim}]([[:alpha:]])[${delim}]\B/<${tag}>$1<\/${tag}>/gs;
    	}
            ${$line_ref} =~
    	    s#(?<![${delim}])[${delim}]([^${delim}]+?[[:alnum:][:punct:]\&<>])[${delim}]#<${tag}>$1</${tag}>#gs;
        }
        else
        {
            ${$line_ref} =~
    s/(?<!${delim})${delim}((\w|["'])(\w|[-\s[:punct:]])*[^\s])${delim}/<${tag}>$1<\/${tag}>/gs;
            ${$line_ref} =~ s/${delim}]([[:alpha:]])${delim}/<${tag}>$1<\/${tag}>/gs;
        }
    }    # do_delim
    
    =head2 glob2regexp
    
        $regexp = glob2regexp($glob);
    
    Convert very simple globs to regexps
    
    =cut
    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
    
    =head2 add_regexp_to_links_table
    
        $self->add_regexp_to_links_table(label=>$label,
    				     pattern=>$pattern,
    				     url=>$url,
    				     switches=>$switches);
    
    Add the given regexp "link definition" to the links table.
    
    =cut
    sub add_regexp_to_links_table ($%)
    {
        my $self = shift;
        my %args = (
            label => undef,
            pattern => undef,
            url => undef,
            switches => undef,
            @_
        );
        my $label = $args{label};
        my $pattern = $args{pattern};
        my $URL = $args{url};
        my $switches = $args{switches};
    
        # No sense adding a second one if it's already in there.
        # It would never get used.
        if (!$self->{__links_table}->{$label})
        {
    
            # Keep track of the order they were added so we can
            # look for matches in the same order
            push(@{$self->{__links_table_order}}, ($label));
    
    	$self->{__links_table_patterns}->{$label} = $pattern;
            $self->{__links_table}->{$label}        = $URL;      # Put it in The Table
            $self->{__links_switch_table}->{$label} = $switches;
            my $ind = @{$self->{__links_table_order}} - 1;
            print STDERR " (", $ind,
              ")\tLABEL: $label \tPATTERN: $pattern\n\tVALUE: $URL\n\tSWITCHES: $switches\n\n"
              if ($DictDebug & 1);
        }
        else
        {
            if ($DictDebug & 1)
            {
                print STDERR " Skipping entry.  Key already in table.\n";
                print STDERR "\tLABEL: $label \tPATTERN: $pattern\n\tVALUE: $URL\n\n";
            }
        }
    }    # add_regexp_to_links_table
    
    =head2 add_literal_to_links_table
    
        $self->add_literal_to_links_table(label=>$label,
    				      pattern=>$pattern,
    				      url=>$url,
    				      switches=>$switches);
    
    Add the given literal "link definition" to the links table.
    
    =cut
    sub add_literal_to_links_table ($%)
    {
        my $self = shift;
        my %args = (
            label => undef,
            pattern => undef,
            url => undef,
            switches => undef,
            @_
        );
        my $label = $args{label};
        my $pattern = $args{pattern};
        my $URL = $args{url};
        my $switches = $args{switches};
    
        $pattern =~ s/(\W)/\\$1/g;    # Escape non-alphanumeric chars
        $pattern = "\\b$pattern\\b";      # Make a regexp out of it
        $self->add_regexp_to_links_table(label=>$label, pattern=>$pattern, url=>$URL, switches=>$switches);
    }    # add_literal_to_links_table
    
    =head2 add_glob_to_links_table
    
        $self->add_glob_to_links_table(label=>$label,
    				   pattern=>$pattern,
    				   url=>$url,
    				   switches=>$switches);
    
    Add the given glob "link definition" to the links table.
    
    =cut
    sub add_glob_to_links_table ($%)
    {
        my $self = shift;
        my %args = (
            label => undef,
            pattern => undef,
            url => undef,
            switches => undef,
            @_
        );
        my $label = $args{label};
        my $pattern = $args{pattern};
        my $URL = $args{url};
        my $switches = $args{switches};
    
        $self->add_regexp_to_links_table(pattern=>glob2regexp($pattern),
    	label=>$label,
    	url=>$URL, switches=>$switches);
    }    # add_glob_to_links_table
    
    =head2 parse_dict
        
        $self->parse_dict($dictfile, $dict);
    
    Parse the dictionary file.
    (see also load_dictionary_links, for things that were stripped)
    
    =cut
    sub parse_dict ($$$)
    {
        my $self = shift;
    
        my ($dictfile, $dict) = @_;
    
        print STDERR "Parsing dictionary file $dictfile\n"
          if ($DictDebug & 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(pattern=>$key, label=>$key, url=>$URL, switches=>$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(pattern=>$key, label=>$key, url=>$URL, switches=>$switches);
            }
            elsif ($key =~ /\"/)
            {
                $key = substr($key, 1);
                $key =~ s/\"$//;      # Allow them to forget the closing "
                $self->add_literal_to_links_table(pattern=>$key, label=>$key, url=>$URL, switches=>$switches);
            }
            else
            {
                $self->add_glob_to_links_table(pattern=>$key, label=>$key, url=>$URL, switches=>$switches);
            }
        }
    
    }    # parse_dict
    
    =head2 setup_dict_checking
    
        $self->setup_dict_checking();
    
    Set up the dictionary checking.
    
    =cut
    sub setup_dict_checking ($)
    {
        my $self = shift;
    
        # now create the replace funcs and precomile the regexes
        my ($URL, $switches, $pattern, $options, $tag1, $tag2);
        my ($href, $r_sw);
        my @subs;
        my $i = 0;
        foreach my $label (@{$self->{__links_table_order}})
        {
            $switches = $self->{__links_switch_table}->{$label};
            $pattern = $self->{__links_table_patterns}->{$label};
    
            $href = $self->{__links_table}->{$label};
    
            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 ($DictDebug & 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
    
    =head2 in_link_context
    
        if ($self->in_link_context($match, $before))
        {
    	...
        }
    
    Check if we are inside a link (<a ...>); certain kinds of substitution are
    not allowed here.
    
    =cut
    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
    
    =head2 apply_links
    
        $self->apply_links(para_ref=>$para_ref,
    		       para_action_ref=>$para_action_ref);
    
    Apply links and formatting to this paragraph.
    
    =cut
    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
            );
        }
        if ($self->{underline_delimiter})
        {
            my $tag = ($self->{lower_case_tags} ? 'u' : 'U');
            $self->do_delim(
                line_ref        => $para_ref,
                line_action_ref => $para_action_ref,
                delim           => $self->{underline_delimiter},
                tag             => $tag
            );
        }
    
    }    # apply_links
    
    =head2 check_dictionary_links
    
        $self->check_dictionary_links(line_ref=>$line_ref,
    				  line_action_ref=>$line_action_ref);
    
    Check (and alter if need be) the bits in this line matching
    the patterns in the link dictionary.
    
    =cut
    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, $pattern, $options, $repl_func);
        my ($linkme, $line_with_links);
    
        # for each pattern, check and alter the line
        my $i = 0;
        foreach my $label (@{$self->{__links_table_order}})
        {
            $switches = $self->{__links_switch_table}->{$label};
            $pattern = $self->{__links_table_patterns}->{$label};
    
            # 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 ($DictDebug & 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 ($DictDebug & 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 ($DictDebug & 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
    
    =head2 load_dictionary_links
    
        $self->load_dictionary_links();
    
    Load the dictionary links.
    
    =cut
    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
    
    =head2 do_file_start
    
        $self->do_file_start($outhandle, $para);
    
    Extra stuff needed for the beginning:
    HTML headers, and prepending a file if desired.
    
    =cut
    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 Strict//EN"',
                      "\n";
                    print $outhandle
    		  '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
                      "\n";
    		print $outhandle $self->get_tag('html',
    		    inside_tag => ' xmlns="http://www.w3.org/1999/xhtml"'), "\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   => TAG_EMPTY,
                    inside_tag => " name=\"generator\" content=\"$PROG v$HTML::TextToHTML::VERSION\""
                  ),
                  "\n";
            }
            else
            {
                print $outhandle $self->get_tag(
                    'meta',
                    tag_type   => TAG_EMPTY,
                    inside_tag => " NAME=\"generator\" CONTENT=\"$PROG v$HTML::TextToHTML::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   => TAG_EMPTY,
                        inside_tag =>
    " rel=\"stylesheet\" type=\"text/css\" href=\"$style_url\""
                      ),
                      "\n";
                }
                else
                {
                    print $outhandle $self->get_tag(
                        'link',
                        tag_type   => TAG_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
    
    =head2 do_init_call
    
        $self->do_init_call();
    
    Certain things, like reading link dictionaries, need to be done only
    once.
    
    =cut
    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}));
    	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->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 explicitly 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 *
    
    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 REQUIRES
    
    HTML::TextToHTML requires Perl 5.8.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:
    
        YAML::Syck
    
    =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 BUGS
    
    Please, send to
    https://github.com/resurrecting-open-source-projects/txt2html/issues
    
    =head1 SEE ALSO
    
    perl
    L<txt2html>.
    
    =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
    
    Copyright (c) 2018-2019 Joao Eriberto Mota Filho
    
    This program is free software; you can redistribute it and/or
    modify it under the same terms as Perl itself.
    
    =cut
    
    #------------------------------------------------------------------------
    1;
    ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/scripts/������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13521162376�0014726�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/scripts/txt2html����������������������������������������������������������������������0000664�0000000�0000000�00000067476�13521162376�0016463�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/perl
    use 5.006_001;
    use strict;
    ##---------------------------------------------------------------------------##
    
    =head1 NAME
    
    txt2html - convert plain text file to HTML
    
    =head1 VERSION
    
    version 2.53
    
    =head1 SYNOPSIS
    
    txt2html --help | --manpage
    
    txt2html [ --append_file I<filename> ] [ --append_head I<filename> ]
        [ --body_deco I<string> ] [ --bold_delimiter I<string> ]
        [ --bullets I<string> ] [ --bullets_ordered I<string> ] [ --caps_tag I<tag> ]
        { --custom_heading_regexp I<regexp> } [ --debug ] [ --demoronize ]
        [ --default_link_dict I<filename> ] [ --dict_debug I<n> ]
        [ --doctype I<doctype> ] [ --eight_bit_clean ] [ --escape_HTML_chars ]
        [ --explicit_headings ] [ --extract ] [ --hrule_min I<n> ]
        [ --indent_width I<n> ] [ --indent_par_break ]
        { --infile I<filename> | --instring I<string> }
        [ --italic_delimiter I<string> ] { --links_dictionaries I<filename> }
        [ --link_only ] [ --lower_case_tags ] [ --mailmode ]
        [ --make_anchors ] [ --make_tables ] [ --min_caps_length I<n> ]
        [ --outfile I<filename> ] [ --par_indent I<n> ]
        [ --preformat_trigger_lines I<n> ] [ --endpreformat_trigger_lines I<n> ]
        [ --preformat_start_marker I<regexp> ] [ --preformat_end_marker I<regexp> ]
        [ --preformat_whitespace_min I<n> ] [ --prepend_file I<filename> ]
        [ --preserve_indent ] [ --short_line_length I<n> ]
        [ --style_url I<stylesheet_url> ] [ --tab_width I<n> ]
        [ --table_type I<type>=0/1 ] [ --title I<title> ] [ --titlefirst ]
        [ --underline_delimiter I<string> ] [ --underline_length_tolerance I<n> ]
        [ --underline_offset_tolerance I<n> ] [ --unhyphenation ]
        [ --use_mosaic_header ] [ --use_preformat_marker ] [ --xhtml ] [file ...]
    
    =head1 DESCRIPTION
    
    txt2html converts plain text files to HTML.
    
    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.
    
    One can use txt2html as a filter, outputting the result to STDOUT,
    or to a given file.
    
    One can define options in a config file as well as on the command-line.
    
    =head1 OPTIONS
    
    Option names can be abbreviated to the shortest unique name for that option.
    Options can start with "--" or "-". Boolean options can be negated
    by preceding them with "no"; options with hash or array values
    can be added to by giving the option again for each value.
    
    See L<Getopt::Long> for more information.
    
    If the Getopt::ArgvFile module is installed, then groups of options can
    be read from a file or files designated by the @ character preceding
    the name.  For example:
    
        txt2html @poem_options --outfile poem_glory.html  poem_glory.txt
    
    See L<Options Files> for more information.
    
    Help options:
    
    =over
    
    =item --help
    
    Display short help and exit.
    
    =item --manpage
    
    Display full documentation and exit.
    This requires perldoc to be installed.
    
    =back
    
    General options:
    
    =over
    
    =item --append_file I<filename> | --append I<filename> | --append_body I<filename>
    
    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 E<lt>kitty@example.comE<gt>
    but instead, have:
        Mary Andersen <kitty@example.com>
    
    (default: nothing)
    
    =item --append_head I<filename> | -ah I<filename>
    
    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 E<lt>kitty@example.comE<gt>
    but instead, have:
        Mary Andersen <kitty@example.com>
    
    (default: nothing)
    
    =item --body_deco I<string>
    
    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 I<string>
    
    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 I<string>
    
    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 I<string>
    
    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 I<tag> | --capstag I<tag> | -ct I<tag>
    
    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 I<regexp> | --heading I<regexp> | -H I<regexp>
    
    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
    
    Enable copious script debugging output (don't bother, this is for the
    developer)
    
    =item --default_link_dict I<filename>
    
    The name of the default "user" link dictionary.
    (default: "$ENV{'HOME'}/.txt2html.dict")
    
    =item --demoronize
    
    Convert Microsoft-generated character codes that are non-ISO codes into
    something more reasonable.
    (default:true)
    
    =item --dict_debug I<n> | -db I<n>
    
    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 I<doctype> | --dt I<doctype>
    
    This gets put in the DOCTYPE field at the top of the document, unless it's
    empty.
    
    Default :
    '-//W3C//DTD HTML 4.01//EN"
    "http://www.w3.org/TR/html4/strict.dtd'
    
    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 | -8
    
    If false, convert Latin-1 characters to HTML entities.
    If true, this conversion is disabled.
    (default: false)
    
    =item --escape_HTML_chars | --escapechars | -ec
    
    turn & E<lt> E<gt> into & > <
    (default: true)
    
    =item --explicit_headings | -EH
    
    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 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 I<n> | --hrule I<n> | -r I<n>
    
    Min number of ---s for an HRule.
    (default: 4)
    
    =item --indent_width I<n> | --indent I<n> | -iw I<n>
    
    Indents this many spaces for each level of a list.
    (default: 2)
    
    =item --indent_par_break | -ipb
    
    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 <BR> and three non-breaking spaces instead.
    (see also --preserve_indent)
    (default: false)
    
    =item --infile I<filename>
    
    The name of the input file.
    This is a cumulative list argument.  If you want to process more than
    one file, just add another --infile I<file> to the list of arguments.
    Or else just add the filename without the option, after all the options.
    Note that the special file name of '-' means standard input.
    
    (default:-)
    
    =item --instring I<string>
    
    An input string.  One can either have input files or input strings,
    not both.  If you want to process more than one string, just add
    another --instring I<string> to the list of arguments.
    
    =item --italic_delimiter I<string>
    
    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 I<filename> | --link I<filename> | -l I<filename>
    
    File to use as a link-dictionary.  There can be more than one of these.
    These are in addition to the System Link Dictionary and the User Link
    Dictionary.
    
    =item --link_only | --linkonly | -LO
    
    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
    
    Force all the tags to be in lower-case.
    
    =item --mailmode | -m
    
    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 | --anchors
    
    Should we try to make anchors in headings?
    (default: true)
    
    =item --make_links
    
    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 | --tables
    
    Should we try to build tables?  If true, spots tables and marks them up
    appropriately.  See L<Input File Format> 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 I<n> | --caps I<n> | -c I<n>
    
    min sequential CAPS for an all-caps line
    (default: 3)
    
    =item --outfile I<filename>
    
    The name of the output file.  If it is "-" then the output goes
    to Standard Output.
    (default: - )
    
    =item --par_indent I<n>
    
    Minimum 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 I<n> | --prebegin I<n> | -pb I<n>
    
    How many lines of preformatted-looking text are needed to switch to <PRE>
              <= 0 : Preformat entire document
                 1 : one line triggers
              >= 2 : two lines trigger
    
    (default: 2)
    
    =item --endpreformat_trigger_lines I<n> | --preend I<n> | -pe I<n>
    
    How many lines of unpreformatted-looking text are needed to switch from <PRE>
               <= 0 : Never preformat within document
                  1 : one line triggers
               >= 2 : two lines trigger
    (default: 2)
    
    NOTE for --prebegin and --preend:
    A zero takes precedence.  If one is zero, the other is ignored.
    If both are zero, entire document is preformatted.
    
    =item --preformat_start_marker I<regexp>
    
    What flags the start of a preformatted section if --use_preformat_marker
    is true.
    
    (default: "^(:?(:?<)|<)PRE(:?(:?>)|>)\$")
    
    =item --preformat_end_marker I<regexp>
    
    What flags the end of a preformatted section if --use_preformat_marker
    is true.
    
    (default: "^(:?(:?<)|<)/PRE(:?(:?>)|>)\$")
    
    =item --preformat_whitespace_min I<n> | --prewhite I<n> | -p I<n>
    
    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<tab_width> 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 I<filename> | --prepend_body I<filename> | --pp I<filename>
    
    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 | -pi
    
    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 I<n> | --shortline I<n> | -s I<n>
    
    Lines this short (or shorter) must be intentionally broken and are kept
    that short.
    (default: 40)
    
    =item --style_url I<stylesheet_url>
    
    This gives the URL of a stylesheet; a LINK tag will be added to the
    output.
    
    =item --tab_width I<n> | --tabwidth I<n> | -tw I<n>
    
    How many spaces equal a tab?
    (default: 8)
    
    =item --table_type I<type>=0/1
        
        --table_type ALIGN=1 --table_type BORDER=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 I<title> | -t I<title>
    
    You can specify a title.  Otherwise it will use a blank one.
    (default: nothing)
    
    =item --titlefirst | -tf
    
    Use the first non-blank line as the title.
    
    =item --underline_delimiter I<string>
    
    This defines what character (or string) is taken to be the delimiter of
    text which is to be interpreted as underlined (that is, to be given a <U>
    tag).  If this is empty, then no underlining of text will be done.
    This is NOT the same as the following "underline" options, which are
    about underlining of "header" sections.
    (default: _)
    
    =item --underline_length_tolerance I<n> | --ulength I<n> | -ul I<n>
    
    How much longer or shorter can header underlines be and still be header
    underlines?
    (default: 1)
    
    =item --underline_offset_tolerance I<n> | --uoffset I<n> | -uo I<n>
    
    How far offset can header underlines be and still be header underlines?
    (default: 1)
    
    =item --unhyphenation | --unhypnenate | -u
    
    Enables unhyphenation of text.
    (default: true)
    
    =item --use_mosaic_header | --mosaic | -mh
    
    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 | --preformat_marker | -pm
    
    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
    
    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.
    
    (default: true)
    
    =back
    
    =head1 FILE FORMATS
    
    =head2 Options Files
    
    Options can be given in files as well as on the command-line by
    flagging an option file with @I<filename> in the command-line.
    Also, the files ~/.txt2htmlrc and ./.txt2htmlrc are checked for options.
    
    The format is as follows:
    Lines starting with # are comments.  Lines enclosed in PoD markers are
    also comments.  Blank lines are ignored.  The options themselves
    should be given the way they would be on the command line, that is,
    the option name (I<including> the --) followed by its value (if any).
    
    For example:
    
        # set link dictionaries
        --default_link_dict /home/kat/.TextToHTML.dict
    
        # set options for poetry
        --titlefirst
        --short_line_length 60
    
    See L<Getopt::ArgvFile> for more information.
    
    =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 explicitly 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)
    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.example.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".
    
    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
    
    B<Convert one file to HTML>
    
        txt2html --infile thing.txt --outfile thing.html
    
    This will create a HTML file called C<thing.html> from the plain
    text file C<thing.txt>.
    
    =head1 BUGS
    
    Tell me about them.
    
    =head1 PREREQUISITES
    
        Pod::Usage
        HTML::TextToHTML
        Getopt::Long
        Getopt::ArgvFile
        File::Basename
        YAML::Syck
        perldoc
    
    =head1 SCRIPT CATEGORIES
    
    Web
    
    =head1 ENVIRONMENT
    
    =over
    
    =item HOME
    
    txt2html looks in the HOME directory for config files.
    
    =back
    
    =head1 FILES
    
    These files are only read if the Getopt::ArgvFile module is
    available on the system.
    
    =over
    
    =item C<~/.txt2htmlrc>
    
    User configuration file.
    
    =item C<.txt2htmlrc>
    
    Configuration file in the current working directory; overrides
    options in C<~/.txt2htmlrc> and is overridden by command-line options.
    
    =back
    
    =head1 SEE ALSO
    
    perl(1)
    htmltoc(1)
    HTML::TextToHTML
    Getopt::Long
    Getopt::ArgvFile
    
    =head1 AUTHOR
    
        Kathryn Andersen (RUBYKAT)
        perlkat AT katspace dot com
        http//www.katspace.com/
    
    based on txt2html by Seth Golub
    
    Current homepage is https://github.com/resurrecting-open-source-projects/txt2html
    
    =head1 COPYRIGHT
    
    Original txt2html script Copyright (c) 1994-2000 Seth Golub seth AT aigeek.com
    
    Copyright (c) 2002-2005 Kathryn Andersen
    
    Copyright (c) 2018-2019 Joao Eriberto Mota Filho
    
    This program is free software; you can redistribute it and/or
    modify it under the same terms as Perl itself.
    
    =cut
    
    #################################################################
    # Includes
    use Pod::Usage;
    use Getopt::Long;
    use File::Basename;
    use HTML::TextToHTML;
    
    #################################################################
    # Subroutines
    
    sub init_data ($) {
        my $data_ref = shift;
    
        my %args = ();
        $args{manpage} = 0;
        $args{debug} = 0;
        $args{version} = 0;
        $args{quiet} = 0;
        $args{help} = 0;
        $args{infile} = [];
        $args{instring} = [];
    
        $data_ref->{args} = \%args;
    }
    
    sub process_args ($) {
        my $data_ref = shift;
        my $args_ref = $data_ref->{args};
    
        my $ok = 1;
    
        # check the rc file if we can
        if (eval("require Getopt::ArgvFile")) {
    	no strict;
    	my $bn = basename($0, '');
    	my $rc_name = ".${bn}rc";
    	Getopt::ArgvFile::argvFile(
    	    startupFilename=>$rc_name,
    	    home=>1,
    	    current=>1);
        }
        $ok = GetOptions($args_ref,
    	'help',
    	'manpage|man_help',
    	'debug',
    	'version',
    	'verbose!',
    	'append_file|append_body|ab=s',
    	'append_head|ah=s',
    	'body_deco=s',
    	'bold_delimiter=s',
    	'bullets=s',
    	'bullets_ordered=s',
    	'caps_tag|capstag|ct=s',
    	'custom_heading_regexp|heading|H=s@',
    	'default_link_dict|dict=s',
    	'demoronize!',
    	'dict_debug|db=n',
    	'doctype|dt=s',
    	'eight_bit_clean|8!',
    	'escape_HTML_chars|escapechars|ec!',
    	'explicit_headings|EH!',
    	'extract!',
    	'hrule_min|r=n',
    	'indent_width|iw=n',
    	'indent_par_break|ipb!',
    	'infile=s@',
    	'instring=s@',
    	'italic_delimiter=s',
    	'links_dictionaries|link|l=s@',
    	'link_only|linkonly|LO!',
    	'lower_case_tags|lc_tags|LC!',
    	'mailmode|m!',
    	'make_anchors|anchors!',
    	'make_links!',
    	'make_tables|tables!',
    	'min_caps_length|caps|c=n',
    	'outfile|out|o=s',
    	'par_indent=n',
    	'preformat_trigger_lines|prebegin|pb=n',
    	'endpreformat_trigger_lines|preend|pe=n',
    	'preformat_start_marker=s',
    	'preformat_end_marker=s',
    	'preformat_whitespace_min|prewhite|p=n',
    	'prepend_file|prepend_body|pp=s',
    	'preserve_indent|pi!',
    	'short_line_length|shortline|s=n',
    	'style_url=s',
    	'tab_width|tabwidth|tw=n',
    	'table_type=n%',
    	'title|t=s',
    	'titlefirst|tf!',
    	'underline_delimiter=s',
    	'underline_length_tolerance|ulength|ul=n',
    	'underline_offset_tolerance|uoffset|uo=n',
    	'unhyphenation|unhyphenate!',
    	'utf8',
    	'use_mosaic_header|mosaic|mh!',
    	'use_preformat_marker|preformat_marker|pm!',
    	'xhtml!',
        );
        if (!$ok)
        {
    	pod2usage({ -message => "$0",
    		    -exitval => 1,
    		    -verbose => 0,
    	    });
        }
    
        if ($args_ref->{'version'})
        {
    	print STDERR "$0 version: $HTML::TextToHTML::VERSION\n";
    	exit 0;
        }
        if ($args_ref->{'manpage'})
        {
    	pod2usage({ -message => "$0 version $HTML::TextToHTML::VERSION",
    		    -exitval => 0,
    		    -verbose => 2,
    	    });
        }
        if ($args_ref->{'help'})
        {
    	pod2usage({ -message => "$0 version $HTML::TextToHTML::VERSION",
    		    -exitval => 0,
    		    -verbose => 1,
    	    });
        }
        # transfer script-only things to the data-ref
        undef $args_ref->{help};
        undef $args_ref->{manpage};
        undef $args_ref->{version};
        # make the object
        my $doc = HTML::TextToHTML->new(%{$args_ref});
        $data_ref->{doc} = $doc;
    }
    
    #################################################################
    # Main
    
    MAIN: {
        my %data = ();
        my $result = 0;
        init_data(\%data);
        process_args(\%data);
    
        # now the remainder must be input-files
        # Push the infiles onto the infile array,
        # because there might already have been infiles added with --infile.
        foreach my $df (@ARGV)
        {
    	if ($data{doc}->{debug}) {
    	    print STDERR "--infile $df\n";
    	}
    	push @{$data{doc}->{infile}}, $df;
        }
        # if we have no infile, and no instring
        # assume stdin, and mark that with '-'
        if (!@{$data{doc}->{infile}} and !@{$data{doc}->{instring}})
        {
    	if ($data{doc}->{debug}) {
    	    print STDERR "using STDIN\n";
    	}
    	push @{$data{doc}->{infile}}, '-';
        }
    
        $data{doc}->txt2html();
    }
    
    # vim: sw=4 sts=4 ai
    ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/t/������������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13521162376�0013502�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/t/00-compile.t������������������������������������������������������������������������0000664�0000000�0000000�00000003126�13521162376�0015536�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!perl
    
    use strict;
    use warnings;
    
    use Test::More;
    
    
    
    use File::Find;
    use File::Temp qw{ tempdir };
    
    my @modules;
    find(
      sub {
        return if $File::Find::name !~ /\.pm\z/;
        my $found = $File::Find::name;
        $found =~ s{^lib/}{};
        $found =~ s{[/\\]}{::}g;
        $found =~ s/\.pm$//;
        # nothing to skip
        push @modules, $found;
      },
      'lib',
    );
    
    sub _find_scripts {
        my $dir = shift @_;
    
        my @found_scripts = ();
        find(
          sub {
            return unless -f;
            my $found = $File::Find::name;
            # nothing to skip
            open my $FH, '<', $_ or do {
              note( "Unable to open $found in ( $! ), skipping" );
              return;
            };
            my $shebang = <$FH>;
            return unless $shebang =~ /^#!.*?\bperl\b\s*$/;
            push @found_scripts, $found;
          },
          $dir,
        );
    
        return @found_scripts;
    }
    
    my @scripts;
    do { push @scripts, _find_scripts($_) if -d $_ }
        for qw{ bin script scripts };
    
    my $plan = scalar(@modules) + scalar(@scripts);
    $plan ? (plan tests => $plan) : (plan skip_all => "no tests to run");
    
    {
        # fake home for cpan-testers
        # no fake requested ## local $ENV{HOME} = tempdir( CLEANUP => 1 );
    
        like( qx{ $^X -Ilib -e "require $_; print '$_ ok'" }, qr/^\s*$_ ok/s, "$_ loaded ok" )
            for sort @modules;
    
        SKIP: {
            eval "use Test::Script 1.05; 1;";
            skip "Test::Script needed to test script compilation", scalar(@scripts) if $@;
            foreach my $file ( @scripts ) {
                my $script = $file;
                $script =~ s!.*/!!;
                script_compiles( $file, "$script script compiles" );
            }
        }
    
    }
    ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/t/10para.t����������������������������������������������������������������������������0000664�0000000�0000000�00000010044�13521162376�0014752�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#########################
    
    use Test::More tests => 18;
    use HTML::TextToHTML;
    ok(1); # If we made it this far, we are ok.
    
    # Insert your test code below, the Test module is use()ed here so read
    # its man page ( perldoc Test ) for help writing this test script.
    
    my $conv = new HTML::TextToHTML();
    ok( defined $conv, 'new() returned something' );
    ok( $conv->isa('HTML::TextToHTML'), "  and it's the right class" );
    
    $conv->args(
    	system_link_dict=>'txt2html.dict',
    	default_link_dict=>'',
    	);
    
    #
    # test the process_para method alone
    #
    $test_str = "Matty had a little truck
    he drove it round and round
    and everywhere that Matty went
    the truck was *always* found.
    ";
    
    $ok_str = "<p>Matty had a little truck<br/>
    he drove it round and round<br/>
    and everywhere that Matty went<br/>
    the truck was <em>always</em> found.
    </p>";
    
    $out_str = $conv->process_para($test_str);
    ok($out_str, 'converted sample string');
    
    # compare the result
    is($out_str, $ok_str, 'compare converted string with OK string');
    
    #
    # test the process_chunk method with an ordered list
    #
    $test_str = "Here is my list:
    
    1. Spam
    2. Jam
    3. Ham
    4. Pickles
    ";
    
    $ok_str = "<p>Here is my list:
    </p><ol>
      <li>Spam
      </li><li>Jam
      </li><li>Ham
      </li><li>Pickles</li></ol>
    ";
    
    $out_str = $conv->process_chunk($test_str);
    ok($out_str, 'converted sample string with list');
    
    # compare the result
    is($out_str, $ok_str, 'compare converted list string with OK list string');
    
    #
    # test the process_chunk method with an empty string
    #
    $test_str = "";
    
    $ok_str = "";
    
    $out_str = $conv->process_chunk($test_str);
    # note we do not do an ok on this because it should be empty
    
    # compare the result
    is($out_str, $ok_str, 'compare converted empty string with OK empty string');
    
    #
    # test with is_fragment
    #
    $test_str = "Matty had a little truck
    he drove it round and round
    and everywhere that Matty went
    the truck was *always* found.
    ";
    
    $ok_str = "Matty had a little truck<br/>
    he drove it round and round<br/>
    and everywhere that Matty went<br/>
    the truck was <em>always</em> found.
    ";
    
    $out_str = $conv->process_chunk($test_str, is_fragment=>1);
    ok($out_str, 'converted sample string');
    
    # compare the result
    is($out_str, $ok_str, 'compare converted string with OK string');
    
    #
    # test the process_para method with a URL
    #
    $test_str = "I like to look at http://www.example.com a lot";
    
    $ok_str = 'I like to look at <a href="http://www.example.com">http://www.example.com</a> a lot';
    
    $out_str = $conv->process_para($test_str, is_fragment=>1);
    ok($out_str, 'converted sample string with URL');
    
    # compare the result
    is($out_str, $ok_str, 'compare converted URL string with OK URL string');
    
    #
    # test process_chunk with caps_tag turned off
    #
    $test_str = "We have a line alone
    FULL OF CAPS AND FURY
    ";
    
    $ok_str = "We have a line alone<br/>
    FULL OF CAPS AND FURY
    ";
    
    $conv->args(caps_tag=>'');
    $out_str = $conv->process_chunk($test_str, is_fragment=>1);
    ok($out_str, 'converted sample string with CAPS');
    
    # compare the result
    is($out_str, $ok_str, 'compare converted CAPS string with OK CAPS string');
    
    $conv->args(caps_tag=>'STRONG'); # restore caps to default
    
    #
    # Test with different italic/bold delimiters
    #
    $test_str = "I am ^bold^,
    You are --really krazy--.
    -----------------
    ";
    
    $ok_str = "I am <strong>bold</strong>,<br/>
    You are <em>really krazy</em>.
    <hr/>
    ";
    
    $conv->args(bold_delimiter=>'^',
    	italic_delimiter=>'--');
    $out_str = $conv->process_chunk($test_str, is_fragment=>1);
    ok($out_str, 'converted sample string with delimiters');
    
    # compare the result
    is($out_str, $ok_str, 'compare converted delimiter string with OK delimiter string');
    
    # 
    # test with no bolding or italic at all
    $test_str = "I am ^bold^,
    You are --really krazy--.
    -----------------
    ";
    
    $ok_str = "I am ^bold^,<br/>
    You are --really krazy--.
    <hr/>
    ";
    
    $conv->args(bold_delimiter=>'',
    	italic_delimiter=>'');
    $out_str = $conv->process_chunk($test_str, is_fragment=>1);
    ok($out_str, 'converted sample string with no bold');
    
    # compare the result
    is($out_str, $ok_str, 'compare converted no-bold string with OK no-bold string');
    
    # restore default
    $conv->args(bold_delimiter=>'#',
    	italic_delimiter=>'*');
    ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/t/20tfiles.t��������������������������������������������������������������������������0000664�0000000�0000000�00000032167�13521162376�0015330�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# miscelaneous tests in separate files
    
    #########################
    
    use Test::More tests => 50;
    use HTML::TextToHTML;
    
    #########################
    
    # compare two files
    sub compare {
        my $file1 = shift;
        my $file2 = shift;
    
        if (!open(F1, $file1))
        {
        	print "error - $file1 did not open\n";
    	return 0;
        }
        if (!open(F2, $file2))
        {
        	print "error - $file2 did not open\n";
    	return 0;
        }
    
        my $res = 1;
        my $count = 0;
        while (<F1>)
        {
    	$count++;
    	my $comp1 = $_;
    	# remove newline/carriage return (in case these aren't both Unix)
    	$comp1 =~ s/\n//;
    	$comp1 =~ s/\r//;
    
    	my $comp2 = <F2>;
    
    	# check if F2 has less lines than F1
    	if (!defined $comp2)
    	{
    	    print "error - line $count does not exist in $file2\n  $file1 : $comp1\n";
    	    close(F1);
    	    close(F2);
    	    return 0;
    	}
    
    	# remove newline/carriage return
    	$comp2 =~ s/\n//;
    	$comp2 =~ s/\r//;
    	if ($comp1 ne $comp2)
    	{
    	    print "error - line $count not equal\n  $file1 : $comp1\n  $file2 : $comp2\n";
    	    close(F1);
    	    close(F2);
    	    return 0;
    	}
        }
        close(F1);
    
        # check if F2 has more lines than F1
        if (defined($comp2 = <F2>))
        {
    	$comp2 =~ s/\n//;
    	$comp2 =~ s/\r//;
    	print "error - extra line in $file2 : '$comp2'\n";
    	$res = 0;
        }
    
        close(F2);
    
        return $res;
    }
    
    #-----------------------------------------------------------------
    
    my $conv = new HTML::TextToHTML();
    
    #
    # Custom headers 1
    #
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    infile=>["tfiles/custom-headers.txt"],
    outfile=>"custom-headers.html",
    custom_heading_regexp=>['^\d+\. +\w+', '^\d+\.\d+\. +\w+', '^\d+\.\d+\.\d+\. +\w+'],
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted custom-headers.txt');
    
    # compare the files
    $result = compare('tfiles/good_custom-headers.html', 'custom-headers.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('custom-headers.html');
    }
    
    #
    # Custom headers 2
    #
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    infile=>["tfiles/custom-headers2.txt"],
    outfile=>"custom-headers2.html",
    custom_heading_regexp=>['^What: '],
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted custom-headers2.txt');
    
    # compare the files
    $result = compare('tfiles/good_custom-headers2.html', 'custom-headers2.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('custom-headers2.html');
    }
    
    #
    # hyphens
    #
    $conv = undef;
    $conv = new HTML::TextToHTML();
    
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    infile=>["tfiles/hyphens.txt"],
    outfile=>"hyphens.html",
    custom_heading_regexp=>[],
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted hyphens.txt');
    
    # compare the files
    $result = compare('tfiles/good_hyphens.html', 'hyphens.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('hyphens.html');
    }
    
    #
    # links
    #
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    infile=>["tfiles/links.txt"],
    outfile=>"links.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted links.txt');
    
    # compare the files
    $result = compare('tfiles/good_links.html', 'links.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('links.html');
    }
    
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    infile=>["tfiles/links2.txt"],
    outfile=>"links2.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted links2.txt');
    
    # compare the files
    $result = compare('tfiles/good_links2.html', 'links2.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('links2.html');
    }
    
    #
    # Lists
    #
    $conv = undef;
    $conv = new HTML::TextToHTML();
    
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    infile=>["tfiles/list.txt"],
    outfile=>"list.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted list.txt');
    
    # compare the files
    $result = compare('tfiles/good_list.html', 'list.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('list.html');
    }
    
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    infile=>["tfiles/list-2.txt"],
    outfile=>"list-2.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted list-2.txt');
    
    # compare the files
    $result = compare('tfiles/good_list-2.html', 'list-2.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('list-2.html');
    }
    
    $conv = undef;
    $conv = new HTML::TextToHTML();
    
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    xhtml=>1,
    infile=>["tfiles/list-3.txt"],
    outfile=>"list-3.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted list-3.txt');
    
    # compare the files
    $result = compare('tfiles/good_list-3.html', 'list-3.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('list-3.html');
    }
    
    $conv = undef;
    $conv = new HTML::TextToHTML();
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>0,
    xhtml=>1,
    infile=>["tfiles/list-4.txt"],
    outfile=>"list-4.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted list-4.txt');
    
    # compare the files
    $result = compare('tfiles/good_list-4.html', 'list-4.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('list-4.html');
    }
    
    $conv = undef;
    $conv = new HTML::TextToHTML();
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>0,
    xhtml=>1,
    infile=>["tfiles/list-5.txt"],
    outfile=>"list-5.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted list-5.txt');
    
    # compare the files
    $result = compare('tfiles/good_list-5.html', 'list-5.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('list-5.html');
    }
    
    $conv = undef;
    $conv = new HTML::TextToHTML();
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    bullets=>'-=o+*',
    bullets_ordered=>'#',
    extract=>0,
    xhtml=>1,
    infile=>["tfiles/list-custom.txt"],
    outfile=>"list-custom.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted list-custom.txt');
    
    # compare the files
    $result = compare('tfiles/good_list-custom.html', 'list-custom.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('list-custom.html');
    }
    
    $conv = undef;
    $conv = new HTML::TextToHTML();
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>0,
    xhtml=>1,
    infile=>["tfiles/list-advanced.txt"],
    outfile=>"list-advanced.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted list-advanced.txt');
    
    # compare the files
    $result = compare('tfiles/good_list-advanced.html', 'list-advanced.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('list-advanced.html');
    }
    
    $conv = undef;
    $conv = new HTML::TextToHTML();
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>0,
    xhtml=>1,
    infile=>["tfiles/list-styles.txt"],
    outfile=>"list-styles.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted list-styles.txt');
    
    # compare the files
    $result = compare('tfiles/good_list-styles.html', 'list-styles.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('list-styles.html');
    }
    
    #
    # news
    #
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>0,
    mailmode=>1,
    infile=>["tfiles/news.txt"],
    outfile=>"news.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted news.txt');
    
    # compare the files
    $result = compare('tfiles/good_news.html', 'news.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('news.html');
    }
    
    #
    # pre
    #
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    use_preformat_marker=>1,
    infile=>["tfiles/pre.txt"],
    outfile=>"pre.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted pre.txt');
    
    # compare the files
    $result = compare('tfiles/good_pre.html', 'pre.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('pre.html');
    }
    
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    use_preformat_marker=>0,
    infile=>["tfiles/pre2.txt"],
    outfile=>"pre2.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted pre2.txt');
    
    # compare the files
    $result = compare('tfiles/good_pre2.html', 'pre2.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('pre2.html');
    }
    
    #
    # Tables
    #
    $conv = undef;
    $conv = new HTML::TextToHTML();
    
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    make_tables=>1,
    infile=>["tfiles/table-align.txt"],
    outfile=>"table-align.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted table-align.txt');
    
    # compare the files
    $result = compare('tfiles/good_table-align.html', 'table-align.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('table-align.html');
    }
    
    $conv = undef;
    $conv = new HTML::TextToHTML();
    
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    make_tables=>1,
    infile=>["tfiles/table-pgsql.txt"],
    outfile=>"table-pgsql.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted table-pgsql.txt');
    
    # compare the files
    $result = compare('tfiles/good_table-pgsql.html', 'table-pgsql.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('table-pgsql.html');
    }
    
    $conv = undef;
    $conv = new HTML::TextToHTML();
    
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    make_tables=>1,
    xhtml=>1,
    infile=>["tfiles/table-pgsql2.txt"],
    outfile=>"table-pgsql2.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted table-pgsql2.txt');
    
    # compare the files
    $result = compare('tfiles/good_table-pgsql2.html', 'table-pgsql2.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('table-pgsql2.html');
    }
    
    $conv = undef;
    $conv = new HTML::TextToHTML();
    
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    make_tables=>1,
    infile=>["tfiles/table-border.txt"],
    outfile=>"table-border.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted table-border.txt');
    
    # compare the files
    $result = compare('tfiles/good_table-border.html', 'table-border.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('table-border.html');
    }
    
    $conv = undef;
    $conv = new HTML::TextToHTML();
    
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    make_tables=>1,
    xhtml=>1,
    infile=>["tfiles/table-delim.txt"],
    outfile=>"table-delim.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted table-delim.txt');
    
    # compare the files
    $result = compare('tfiles/good_table-delim.html', 'table-delim.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('table-delim.html');
    }
    
    #
    # an EMPTY file (non-extracted)
    #
    $conv = undef;
    $conv = new HTML::TextToHTML();
    
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>0,
    xhtml=>0,
    infile=>["tfiles/empty.txt"],
    outfile=>"empty1.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted empty.txt (default)');
    
    # compare the files
    $result = compare('tfiles/good_empty.html', 'empty1.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('empty1.html');
    }
    
    #
    # an EMPTY file (non-extracted) (xhtml)
    #
    $conv = undef;
    $conv = new HTML::TextToHTML();
    
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>0,
    xhtml=>1,
    infile=>["tfiles/empty.txt"],
    outfile=>"empty2.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted empty.txt (xhtml)');
    
    # compare the files
    $result = compare('tfiles/good_empty.html', 'empty2.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('empty2.html');
    }
    
    #
    # an EMPTY file (extracted)
    #
    $conv = undef;
    $conv = new HTML::TextToHTML();
    
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    xhtml=>0,
    infile=>["tfiles/empty.txt"],
    outfile=>"empty3.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted empty.txt (extract)');
    
    # compare the files
    $result = compare('tfiles/good_empty.html', 'empty3.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('empty3.html');
    }
    
    #
    # an EMPTY file (extracted) (xhtml)
    #
    $conv = undef;
    $conv = new HTML::TextToHTML();
    
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    xhtml=>1,
    infile=>["tfiles/empty.txt"],
    outfile=>"empty4.html",
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted empty.txt (extract) (xhtml)');
    
    # compare the files
    $result = compare('tfiles/good_empty.html', 'empty4.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('empty4.html');
    }
    
    ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/t/25handles.t�������������������������������������������������������������������������0000664�0000000�0000000�00000006124�13521162376�0015457�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# miscelaneous tests for filehandles
    
    #########################
    
    use Test::More tests => 6;
    use HTML::TextToHTML;
    
    #########################
    
    # compare two files
    sub compare {
        my $file1 = shift;
        my $file2 = shift;
    
        if (!open(F1, $file1))
        {
        	print "error - $file1 did not open\n";
    	return 0;
        }
        if (!open(F2, $file2))
        {
        	print "error - $file2 did not open\n";
    	return 0;
        }
    
        my $res = 1;
        my $count = 0;
        while (<F1>)
        {
    	$count++;
    	my $comp1 = $_;
    	# remove newline/carriage return (in case these aren't both Unix)
    	$comp1 =~ s/\n//;
    	$comp1 =~ s/\r//;
    
    	my $comp2 = <F2>;
    
    	# check if F2 has less lines than F1
    	if (!defined $comp2)
    	{
    	    print "error - line $count does not exist in $file2\n  $file1 : $comp1\n";
    	    close(F1);
    	    close(F2);
    	    return 0;
    	}
    
    	# remove newline/carriage return
    	$comp2 =~ s/\n//;
    	$comp2 =~ s/\r//;
    	if ($comp1 ne $comp2)
    	{
    	    print "error - line $count not equal\n  $file1 : $comp1\n  $file2 : $comp2\n";
    	    close(F1);
    	    close(F2);
    	    return 0;
    	}
        }
        close(F1);
    
        # check if F2 has more lines than F1
        if (defined($comp2 = <F2>))
        {
    	$comp2 =~ s/\n//;
    	$comp2 =~ s/\r//;
    	print "error - extra line in $file2 : '$comp2'\n";
    	$res = 0;
        }
    
        close(F2);
    
        return $res;
    }
    
    #-----------------------------------------------------------------
    
    my $conv = new HTML::TextToHTML();
    
    #
    # FILEHANDLE
    #
    
    open (IN, "tfiles/hyphens.txt")
    or die "could not open tfiles/hyphens.txt";
    
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    inhandle=>[\*IN],
    outfile=>"fh_hyphens.html",
    custom_heading_regexp=>[],
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted (FH) hyphens.txt');
    
    # compare the files
    $result = compare('tfiles/good_hyphens.html', 'fh_hyphens.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('fh_hyphens.html');
    }
    
    #
    # filehandle variable
    #
    $conv = undef;
    $conv = new HTML::TextToHTML();
    
    my $fh;
    open ($fh, "tfiles/hyphens.txt")
    or die "could not open tfiles/hyphens.txt";
    
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    inhandle=>[$fh],
    outfile=>"fh2_hyphens.html",
    custom_heading_regexp=>[],
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted (FH 2) hyphens.txt');
    
    # compare the files
    $result = compare('tfiles/good_hyphens.html', 'fh2_hyphens.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('fh2_hyphens.html');
    }
    
    #
    # Output filehandle
    #
    $conv = undef;
    $conv = new HTML::TextToHTML();
    
    my $ofh;
    open ($ofh, ">", "fh3_hyphens.html")
    or die "could not open fh3_hyphens.html for writing";
    
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    extract=>1,
    infile=>['tfiles/hyphens.txt'],
    outhandle=>$ofh,
    custom_heading_regexp=>[],
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted (FH 3) hyphens.txt');
    
    # compare the files
    $result = compare('tfiles/good_hyphens.html', 'fh3_hyphens.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('fh3_hyphens.html');
    }
    
    ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/t/30sample.t��������������������������������������������������������������������������0000664�0000000�0000000�00000004174�13521162376�0015321�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Before `make install' is performed this script should be runnable with
    # `make test'. After `make install' it should work as `perl test.pl'
    
    #########################
    
    # change 'tests => 1' to 'tests => last_test_to_print';
    
    use Test::More tests => 5;
    use HTML::TextToHTML;
    ok(1); # If we made it this far, we're ok.
    
    #########################
    
    # compare two files
    sub compare {
        my $file1 = shift;
        my $file2 = shift;
    
        open(F1, $file1) || return 0;
        open(F2, $file2) || return 0;
    
        my $res = 1;
        my $count = 0;
        while (<F1>)
        {
    	$count++;
    	my $comp1 = $_;
    	# remove newline/carriage return (in case these aren't both Unix)
    	$comp1 =~ s/\n//;
    	$comp1 =~ s/\r//;
    
    	my $comp2 = <F2>;
    
    	# check if F2 has less lines than F1
    	if (!defined $comp2)
    	{
    	    print "error - line $count does not exist in $file2\n  $file1 : $comp1\n";
    	    close(F1);
    	    close(F2);
    	    return 0;
    	}
    
    	# remove newline/carriage return
    	$comp2 =~ s/\n//;
    	$comp2 =~ s/\r//;
    	if ($comp1 ne $comp2)
    	{
    	    print "error - line $count not equal\n  $file1 : $comp1\n  $file2 : $comp2\n";
    	    close(F1);
    	    close(F2);
    	    return 0;
    	}
        }
        close(F1);
    
        # check if F2 has more lines than F1
        if (defined($comp2 = <F2>))
        {
    	$comp2 =~ s/\n//;
    	$comp2 =~ s/\r//;
    	print "error - extra line in $file2 : '$comp2'\n";
    	$res = 0;
        }
    
        close(F2);
    
        return $res;
    }
    
    # Insert your test code below, the Test module is use()ed here so read
    # its man page ( perldoc Test ) for help writing this test script.
    
    my $conv = new HTML::TextToHTML(xhtml=>0);
    ok( defined $conv, 'new() returned something' );
    ok( $conv->isa('HTML::TextToHTML'), "  and it's the right class" );
    
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    infile=>["tfiles/sample.txt"],
    outfile=>"sample.html",
    append_file=>"tfiles/sample.foot",
    titlefirst=>1, mailmode=>1,
    custom_heading_regexp=>['^ *--[\w\s]+-- *$'],
    make_tables=>1,
    );
    ok($result, 'converted sample.txt');
    
    # compare the files
    $result = compare('tfiles/good_sample.html', 'sample.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('sample.html');
    }
    
    ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/t/50xsample.t�������������������������������������������������������������������������0000664�0000000�0000000�00000004474�13521162376�0015516�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Before `make install' is performed this script should be runnable with
    # `make test'. After `make install' it should work as `perl test.pl'
    
    #########################
    
    # change 'tests => 1' to 'tests => last_test_to_print';
    
    use Test::More tests => 5;
    use HTML::TextToHTML;
    ok(1); # If we made it this far, we're ok.
    
    #########################
    
    # compare two files
    sub compare {
        my $file1 = shift;
        my $file2 = shift;
    
        open(F1, $file1) || return 0;
        open(F2, $file2) || return 0;
    
        my $res = 1;
        my $count = 0;
        while (<F1>)
        {
    	$count++;
    	my $comp1 = $_;
    	# remove newline/carriage return (in case these aren't both Unix)
    	$comp1 =~ s/\n//;
    	$comp1 =~ s/\r//;
    
    	my $comp2 = <F2>;
    
    	# check if F2 has less lines than F1
    	if (!defined $comp2)
    	{
    	    print "error - line $count does not exist in $file2\n  $file1 : $comp1\n";
    	    close(F1);
    	    close(F2);
    	    return 0;
    	}
    
    	# remove newline/carriage return
    	$comp2 =~ s/\n//;
    	$comp2 =~ s/\r//;
    	if ($comp1 ne $comp2)
    	{
    	    print "error - line $count not equal\n  $file1 : $comp1\n  $file2 : $comp2\n";
    	    close(F1);
    	    close(F2);
    	    return 0;
    	}
        }
        close(F1);
    
        # check if F2 has more lines than F1
        if (defined($comp2 = <F2>))
        {
    	$comp2 =~ s/\n//;
    	$comp2 =~ s/\r//;
    	print "error - extra line in $file2 : '$comp2'\n";
    	$res = 0;
        }
    
        close(F2);
    
        return $res;
    }
    
    # Insert your test code below, the Test module is use()ed here so read
    # its man page ( perldoc Test ) for help writing this test script.
    
    my $conv = new HTML::TextToHTML();
    ok( defined $conv, 'new() returned something' );
    ok( $conv->isa('HTML::TextToHTML'), "  and it's the right class" );
    
    my %args = ();
    $args{system_link_dict} = "txt2html.dict";
    $args{default_link_dict} = "";
    $args{infile} = ["tfiles/sample.txt"];
    $args{append_file} = "tfiles/sample.foot2";
    $args{titlefirst} = 1;
    $args{mailmode} = 1;
    $args{custom_heading_regexp} = ['^ *--[\w\s]+-- *$'];
    $args{make_tables} = 1;
    $args{make_anchors} = 1;
    $args{xhtml} = 1; 
    $args{outfile} =  "xhtml_sample.html";
    $result = $conv->txt2html(%args);
    ok($result, 'converted xhtml sample.txt');
    
    # compare the files
    $result = compare('tfiles/good_xhtml_sample.html', 'xhtml_sample.html');
    ok($result, 'test file xhtml_sample.html matches original good_xhtml_sample.html exactly');
    
    if ($result) {
        unlink('xhtml_sample.html');
    }
    ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/t/70bugs.t����������������������������������������������������������������������������0000664�0000000�0000000�00000012442�13521162376�0015001�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# files which have triggered bugs
    
    #########################
    
    use Test::More tests => 16;
    use HTML::TextToHTML;
    
    #########################
    
    # compare two files
    sub compare {
        my $file1 = shift;
        my $file2 = shift;
    
        if (!open(F1, $file1))
        {
        	print "error - $file1 did not open\n";
    	return 0;
        }
        if (!open(F2, $file2))
        {
        	print "error - $file2 did not open\n";
    	return 0;
        }
    
        my $res = 1;
        my $count = 0;
        while (<F1>)
        {
    	$count++;
    	my $comp1 = $_;
    	# remove newline/carriage return (in case these are not both Unix)
    	$comp1 =~ s/\n//;
    	$comp1 =~ s/\r//;
    
    	my $comp2 = <F2>;
    
    	# check if F2 has less lines than F1
    	if (!defined $comp2)
    	{
    	    print "error - line $count does not exist in $file2\n  $file1 : $comp1\n";
    	    close(F1);
    	    close(F2);
    	    return 0;
    	}
    
    	# remove newline/carriage return
    	$comp2 =~ s/\n//;
    	$comp2 =~ s/\r//;
    	if ($comp1 ne $comp2)
    	{
    	    print "error - line $count not equal\n  $file1 : $comp1\n  $file2 : $comp2\n";
    	    close(F1);
    	    close(F2);
    	    return 0;
    	}
        }
        close(F1);
    
        # check if F2 has more lines than F1
        if (defined($comp2 = <F2>))
        {
    	$comp2 =~ s/\n//;
    	$comp2 =~ s/\r//;
    	print "error - extra line in $file2 : '$comp2'\n";
    	$res = 0;
        }
    
        close(F2);
    
        return $res;
    }
    
    #-----------------------------------------------------------------
    
    my $conv = new HTML::TextToHTML();
    
    #
    # bugs : make_tables
    #
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    make_tables=>1,
    infile=>["tfiles/robo.txt"],
    outfile=>"robo.html",
    custom_heading_regexp=>[],
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted robo.txt');
    
    # compare the files
    $result = compare('tfiles/good_robo.html', 'robo.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('robo.html');
    }
    
    #
    # bugs : list with bold chars
    #
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    make_tables=>0,
    infile=>["tfiles/mixed.txt"],
    outfile=>"mixed.html",
    custom_heading_regexp=>[],
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted mixed.txt');
    
    # compare the files
    $result = compare('tfiles/good_mixed.html', 'mixed.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('mixed.html');
    }
    
    #
    # bugs : dos file on unix platform not detecting headings
    #
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    make_tables=>0,
    infile=>["tfiles/heading1.txt"],
    outfile=>"heading1.html",
    custom_heading_regexp=>[],
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted heading1.txt');
    
    # compare the files
    $result = compare('tfiles/good_heading1.html', 'heading1.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('heading1.html');
    }
    
    #
    # bugs : link with # in it being replaced by <STRONG> tags
    #
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    make_tables=>0,
    infile=>["tfiles/links3.txt"],
    outfile=>"links3.html",
    custom_heading_regexp=>[],
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted links3.txt');
    
    # compare the files
    $result = compare('tfiles/good_links3.html', 'links3.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('links3.html');
    }
    
    $conv = new HTML::TextToHTML();
    #
    # bugs : file with umlauts not doing italics and unterlines correctly
    #
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    make_tables=>0,
    infile=>["tfiles/umlauttest.txt"],
    outfile=>"umlauttest.html",
    custom_heading_regexp=>[],
    xhtml=>1,
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted umlauttest.txt');
    
    # compare the files
    $result = compare('tfiles/good_umlauttest.html', 'umlauttest.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('umlauttest.html');
    }
    
    #
    # bugs : UTF-8 characters are being wrongly zapped
    #
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    make_anchors=>0,
    infile=>["tfiles/utf8.txt"],
    outfile=>"utf8.html",
    custom_heading_regexp=>[],
    xhtml=>1,
    extract=>1,
    eight_bit_clean=>1,
    #debug=>1,
    #dict_debug=>15,
    );
    ok($result, 'converted utf8.txt');
    
    # compare the files
    $result = compare('tfiles/good_utf8.html', 'utf8.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('utf8.html');
    }
    
    #
    # bugs : italics with punctuation characters , and ! not converted
    #
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    make_anchors=>0,
    infile=>["tfiles/punct.txt"],
    outfile=>"punct.html",
    custom_heading_regexp=>[],
    extract=>1,
    eight_bit_clean=>1,
    );
    ok($result, 'converted punct.txt');
    
    # compare the files
    $result = compare('tfiles/good_punct.html', 'punct.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('punct.html');
    }
    
    #
    # bugs : links with underscores
    #
    $result = $conv->txt2html(
    system_link_dict=>"txt2html.dict",
    default_link_dict=>"",
    make_anchors=>0,
    infile=>["tfiles/links4.txt"],
    outfile=>"links4.html",
    custom_heading_regexp=>[],
    extract=>1,
    eight_bit_clean=>1,
    );
    ok($result, 'converted links4.txt');
    
    # compare the files
    $result = compare('tfiles/good_links4.html', 'links4.html');
    ok($result, 'test file matches original example exactly');
    if ($result) {
        unlink('links4.html');
    }
    
    ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/t/release-distmeta.t������������������������������������������������������������������0000664�0000000�0000000�00000000455�13521162376�0017123�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!perl
    
    BEGIN {
      unless ($ENV{RELEASE_TESTING}) {
        require Test::More;
        Test::More::plan(skip_all => 'these tests are for release candidate testing');
      }
    }
    
    
    use Test::More;
    
    eval "use Test::CPAN::Meta";
    plan skip_all => "Test::CPAN::Meta required for testing META.yml" if $@;
    meta_yaml_ok();
    �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/t/release-has-version.t���������������������������������������������������������������0000664�0000000�0000000�00000000473�13521162376�0017547�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!perl
    
    BEGIN {
      unless ($ENV{RELEASE_TESTING}) {
        require Test::More;
        Test::More::plan(skip_all => 'these tests are for release candidate testing');
      }
    }
    
    
    use Test::More;
    
    eval "use Test::HasVersion";
    plan skip_all => "Test::HasVersion required for testing version numbers"
      if $@;
    all_pm_version_ok();
    �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/t/release-pod-coverage.t��������������������������������������������������������������0000664�0000000�0000000�00000000765�13521162376�0017670�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!perl
    
    BEGIN {
      unless ($ENV{RELEASE_TESTING}) {
        require Test::More;
        Test::More::plan(skip_all => 'these tests are for release candidate testing');
      }
    }
    
    
    use Test::More;
    
    eval "use Test::Pod::Coverage 1.08";
    plan skip_all => "Test::Pod::Coverage 1.08 required for testing POD coverage"
      if $@;
    
    eval "use Pod::Coverage::TrustPod";
    plan skip_all => "Pod::Coverage::TrustPod required for testing POD coverage"
      if $@;
    
    all_pod_coverage_ok({ coverage_class => 'Pod::Coverage::TrustPod' });
    �����������txt2html-2.53/t/release-pod-syntax.t����������������������������������������������������������������0000664�0000000�0000000�00000000450�13521162376�0017412�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!perl
    
    BEGIN {
      unless ($ENV{RELEASE_TESTING}) {
        require Test::More;
        Test::More::plan(skip_all => 'these tests are for release candidate testing');
      }
    }
    
    use Test::More;
    
    eval "use Test::Pod 1.41";
    plan skip_all => "Test::Pod 1.41 required for testing POD" if $@;
    
    all_pod_files_ok();
    ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/t/release-portability.t���������������������������������������������������������������0000664�0000000�0000000�00000000534�13521162376�0017651�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!perl
    
    BEGIN {
      unless ($ENV{RELEASE_TESTING}) {
        require Test::More;
        Test::More::plan(skip_all => 'these tests are for release candidate testing');
      }
    }
    
    
    use strict;
    use warnings;
    
    use Test::More;
    
    eval 'use Test::Portability::Files';
    plan skip_all => 'Test::Portability::Files required for testing portability'
        if $@;
    run_tests();
    ��������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/tfiles/�������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13521162376�0014525�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/tfiles/custom-headers.txt�������������������������������������������������������������0000664�0000000�0000000�00000001423�13521162376�0020211�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������1.  INTRODUCTION
    
    1.1.  SCOPE
    
         This standard specifies a syntax for text messages that  are
    sent  among  computer  users, within the framework of "electronic
    mail".  The standard supersedes  the  one  specified  in  ARPANET
    Request  for Comments #733, "Standard for the Format of ARPA Net-
    work Text Messages".
    
    1.2.  COMMUNICATION FRAMEWORK
    
         Messages consist of lines of text.   No  special  provisions
    are  made for encoding drawings, facsimile, speech, or structured
    text.  No significant consideration has been given  to  questions
    of  data  compression  or to transmission and storage efficiency,
    and the standard tends to be free with the number  of  bits  con-
    sumed.   For  example,  field  names  are specified as free text,
    rather than special terse codes.
    
    2. BLAH
    
    ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/tfiles/custom-headers2.txt������������������������������������������������������������0000664�0000000�0000000�00000000064�13521162376�0020273�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������What: A Bargain
    
    What: A Nuisance
    
    What: Am I Doing
    ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/tfiles/empty.txt����������������������������������������������������������������������0000664�0000000�0000000�00000000000�13521162376�0016412�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/tfiles/good_custom-headers.html�������������������������������������������������������0000664�0000000�0000000�00000001647�13521162376�0021356�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<h1><a name="section_1">1.  INTRODUCTION</a></h1>
    
    <h2><a name="section_1_1">1.1.  SCOPE</a></h2>
    
    <p>     This standard specifies a syntax for text messages that  are
    sent  among  computer  users, within the framework of "electronic
    mail".  The standard supersedes  the  one  specified  in  ARPANET
    Request  for Comments #733, "Standard for the Format of ARPA Network 
    Text Messages".
    </p>
    <h2><a name="section_1_2">1.2.  COMMUNICATION FRAMEWORK</a></h2>
    
    <p>     Messages consist of lines of text.   No  special  provisions
    are  made for encoding drawings, facsimile, speech, or structured
    text.  No significant consideration has been given  to  questions
    of  data  compression  or to transmission and storage efficiency,
    and the standard tends to be free with the number  of  bits  consumed.   
    For  example,  field  names  are specified as free text,
    rather than special terse codes.
    </p>
    <h1><a name="section_2">2. BLAH</a></h1>
    
    �����������������������������������������������������������������������������������������txt2html-2.53/tfiles/good_custom-headers2.html������������������������������������������������������0000664�0000000�0000000�00000000230�13521162376�0021423�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<h1><a name="section_3">What: A Bargain</a></h1>
    
    <h1><a name="section_4">What: A Nuisance</a></h1>
    
    <h1><a name="section_5">What: Am I Doing</a></h1>
    
    ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/tfiles/good_empty.html����������������������������������������������������������������0000664�0000000�0000000�00000000000�13521162376�0017547�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������txt2html-2.53/tfiles/good_heading1.html�������������������������������������������������������������0000664�0000000�0000000�00000050172�13521162376�0020110�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title>
    
    
    
    

    Doctor Who New Adventures

    The Left-Handed Hummingbird by Kate Orman

    (an attempt at a spoiler-free review by Kathryn Andersen)

    This novel is right up there with Love & War in the best NA category, I think. Why? Hmmm. Many of the NA's are "okay". They have nothing wrong with them. But to be an outstanding story, it needs something extra; some character insight or development which changes the relationship of the major characters, an original plot/twist/adversary, an excellent turn of phrase - and LHH had all of these. Here, the Doctor is put in a position he has never been in before, hoist on his own petard, a victim of his own way of doing things, caught in a trap that travels with him.

    (I am reminded of the Blake's 7 quote:
    "When you know an enemy's strengths, and can use them against them, they become weaknesses."
    -- Servalan, to Travis (Blake's 7: Weapon [B3]) )

    There are some good insights about him and Ace, wondering if they are more alike than they like to admit... And finally, those turning phrases, made me want to write again. It's not often you get some lovely stuff you'd like to quote - my quotes file has many gems from "Transit", but hardly anything from the other NA's. This one doesn't have as many quotable jewels, but a number of places that made you sit up and take notice. My favourite is:
    "Ashes to nothing. Dust to nothing. Live fast, die young, and leave a beautiful empty space where you used to be." (p220)


    This story stood out because, as I said above, this is the first time that the Doctor has been a victim. There have been times when he has been helpless to help others. There have been times when he has been at the losing end, but he has been in control, able to play for time. There has even been the time, with the Timewyrm, where half the time he hasn't been in control, but he has always been playing his game, fencing with the enemy. This time he couldn't fence at all. The quote from Nietzsche at the start is doubly fitting now that I know what happened. Because that's what happened. He gazed into the Abyss, and became a monster. This is a good follow-on from The Dimension Riders, because the stakes have upped. In The Dimension Riders, for the first time, the Doctor's clever plan didn't work, and someone else's clever plan did. He was helped by someone else. And in The Left-Handed Hummingbird, the Doctor was up against something too big for him to handle; he hardly had a plan at all (no great plan involves suicide...), and that didn't work either.
    The Doctor is so used to being more capable than everyone else he meets, is he incapable of accepting help from others? I mean real help, not directed assistance to fight the enemy. He got into this trouble because he went looking for it.

    Sid & Nancy scale: a thunderstorm wrapped in blue


    First Frontier

    an attempt at a spoiler-free review by Kathryn Andersen

    So, here's the latest NA to pass through my hands. I'm wondering if the inverse-cover-rule applies to this one: the cover is great, the book isn't. But actually, the book was okay, even if not terrific. I can understand why the author said he did it for fun. Strangely enough, it picked up in the latter half of the book - or else I merely changed my mood and decided I wanted to read it.

    The Ace characterisation harked back to the earlier Ace - or perhaps I was reminded of her because this was, in its own way, a sequel to "Survival", and that part of it it did well. I tip my hat to the author that I did not suspect who Kreer really was until it was revealed, even though enough clues were left around for someone more astute than I to figure it out, maybe. If I were more up with UFO-ology, I might also tip my hat to the author about his UFO research, but I don't know enough to know if he did it well.

    Benny doesn't seem to have much to do, and the Doctor doesn't feature as much as he might - there seems to be an abundance of supporting characters being suspicious of each other, following orders, or being victims.

    It was readable, but I'm keeping it for the cover. 8-)

    Sid & Nancy scale: a model kit of a flying saucer


    Falls The Shadow

    reviewed by Kathryn Andersen

    Well, I finally read this one, months after I got it.

    I can see why someone compared this with "Strange England", though in one sense, "Strange England" was more vividly horrible. There was more horror in those singing insects than there was in the two villains. Yet another NA with a surreal landscape. I wonder if it's a requirement. No, I don't dislike surreal landscapes, it's just that you start to get weary of them when they happen a lot. Which NA's didn't have a surreal landscape in there somewhere?

    Am I becoming jaded, or are the NAs all running into each other in ordinariness?

    Okay spoiler warning time. Discussion time.


    The cover didn't help. Hard to think of Gabriel and Tanith as perfect in beauty when the pictures of them on the cover weren't very beautiful at all. Gabriel and Tanith were just violent. Continuously and sadistically violent.

    But the most interesting question, and here's for the discussion time: who is the grey man? I mean the author seems to be proposing a change in the metaphysical nature of the Whoniverse, but there are several things that don't make sense about it.

    • Grey. With white as Good and Black as Evil, Grey seems to style himself as Doubt. But on the other hand, he seems to style himself as Chaos. Now, I agree that Order and Chaos are neither good nor evil (since things like Nazi dictatorships can be very evil and very orderly). But... aw, I think part of my problem here is that I disagree with the standing metaphysical order of the Whoniverse with the Black and White Guardians being equal and opposite, so trying to slot a Grey Guardian in there is adding to my confusion. But still, I don't really understand what he's supposed to stand for. Doubt? (and how would doubt apply to Evil?) Chaos? (and doesn't Evil want to create chaos as well as order?) Freedom? (but doesn't Good want to create freedom?)
    • His people. Who are his people? Are the Black Guardian and the White Guardian of his people, or something else? And if they are, then who are the rest, or are there only three of them? Who are they?

    I think I had some more questions, but I can't remember what they were.

    Kathryn Andersen
    (now I can read Set Piece! Yay!)

    Later, on Thu, 30 Mar 1995...

    Ah, I remember now. The other query/problem I had with "Falls the Shadow". And it was the most important one too.

    Whoniversal metaphysics warning

    Falls The Shadow spoiler warning

    Okay, so Gabriel and Tanith were born out of the pain of the universe, a wounding of the universe, the pain of destroyed potential futures, such as the one that Jane Page came from. And the Doctor felt guilty because such pain was caused by him and other time travellers. Am I right, or did I completely miss what was happening?

    Because, if that's the case, however poetically appealing it is, it doesn't make any sense. Because time travel isn't the only thing that destroys potential futures. If time travel was never invented, millions of potential futures are destroyed every second, every time someone makes a decision. Is the author trying to tell me that the natural order of the universe (that is, a universe supposing time travel had never been invented, an untampered-with universe) causes a wounding of the universe? Where is the logic in that, the design?

    I am assuming that the Darvil-Evans structure of the Whoniverse is the one that needs to be used: the one which sets the Doctor's Gallifrey way way back in (to us) the past, which is actually the Present. And the nature of time travel is such that it is impossible to travel into the Past, into a point before the Present (thus nobody goes back in time to have a chat to Rassillon etc), but it is possible to travel into the future, but the act of travelling into the future and observing and participating in it, makes that future certain (or almost certain) to occur. It crystalizes it, so to speak. That there is only one universe; parallel universes take a great deal of energy to create and they are only temporary. It is not impossible to change history, but it is difficult, destructive, and a very Bad Thing.

    So, in all this, why is there pain at the wiping out of possible futures? It's not as if they had a right to exist: there can be only one history-of-the-universe in the end. What exists, exists. What might have existed does not exist, and should not exist.

    Is it because these potential futures were wiped out "sooner" than they might have been? Because the actions/decisions that wiped them out happened before the Present moment actually arrived there? But what does "before" mean in that context? We're talking about meta-time here, and that's so hairy I think I'll leave it.

    (sigh)

    Sid & Nancy scale: a Ken Done painting


    Set Piece by Kate Orman

    Date - June 5th 1995

    reviewed by Kathryn Andersen

    The obvious book to compare "Set Piece" to would be the previous excursion of Kate Orman into the realms of the New Adventures - "The Left-Handed Hummingbird" (otherwise known in fannish shorthand as "Hummer"). Oddly enough, I think "Set Piece" was both better and not as good as Hummer. Better, because I can think of not a thing to point to that was a problem (on the other hand, maybe I just wasn't looking carefully enough?). Not as good simply because it wasn't the same kind of rollercoaster ride that Hummer was, not as much of the sheer angstiness that was in Hummer. Not the same psychological torture - here I was more worried about Ace than the Doctor. But maybe that's just that it's a different book. And it would be only half a point difference anyway. I did really like Set Piece. Action and characterisation in even amounts, a few surprises, and a few not-surprises. 8.5 or 9 out of 10.

    This story is really Ace's story, not really surprising since this is the book in which she is written out of the series. The Doctor and Benny have their parts to play, but Ace is the emotional heart of the tale. The three time travellers are cast adrift through history when a rescue attempt goes awry, and the three have to survive in different eras while something living in a crack in space-time preys on people from the past, present and future.

    Here, Ace is all alone, in the alien (to her) culture of Ancient Egypt, with only her own resources to fall back on, surviving and waiting, waiting, waiting for the Doctor to turn up and tell her the sneaky plan he had been preparing all this while. But the last time she saw the Doctor, "Benny was stooped over the Doctor, frantically trying to get a response out of him. Blood was trickling from his mouth and nose, sluggishly. His eyes had flicked shut. Ace wished she could tell Benny that the Doctor was dead." Isolated, despairing, Ace is in danger of losing her soul, of making the worst mistake in her life...

    Again, Kate Orman has sprinkled the work with sharp pieces of prose: "Suddenly the Doctor did not walk up and say hello." (p50) about Ace's loneliness. "When you're short of everything except the enemy, you know you're in combat." (p138) was another good example. And touches of humour here and there. One might make a complaint, though, that the Whoniverse is becoming cluttered with metaphysical constructs; previous New Adventures have dream-encounters with Death and Time - here we meet Pain, with the Doctor as Time's butterfly. I guess that depends on how much one enjoys symbolism. There are some very good character moments - for Ace and the Doctor particularly. Ace faces herself, and the Doctor wins by losing.

    The plot as a whole comes together piece by piece, jumping about from time and place (with a flashback and a red herring or two to stop it from being too straightforward), becoming clearer as it goes along, and tieing itself together very satisfactorily. No megalomaniacs, no 'fixed up in the last five minutes with the wave of a gizmo', and not even a 'I've been subtly planning this behind the scenes for months' which tends to happen with the 7th Doctor.

    The way in which Ace departs the series had me cheering. I couldn't have asked for a better way for her to go. And I'd better not say any more about that for fear of letting slip hints about what happens.

    If you are reading the New Adventures at all, there are no excuses for not reading this one, except perhaps putting it off until you've read all the previous ones by Paul Cornell, Ben Aaronovich and Kate Orman.

    Sid & Nancy scale: chocolate cake with ice cream


    Sky Pirates by Dave Stone

    note on rec.arts.drwho on Thu Aug 17 1995 from kat

    I only have two things to say about this NA: 1. I expect that persons will have similar attitudes towards this as they had about The Highest Science.
    2. It made me laugh.

    Kathryn Andersen

    (who hasn't read radw for months...)

    Sid & Nancy scale: Mystery Science Theatre 3000


    The Room With No Doors by Kate Orman

    a rambling rave by Kathryn Andersen

    Whee! She did it again! So I couldn't put it down, what's the surprise in that?

    First warning - ignore the back cover blurb. It's misleading. It tells you too much about the wrong things.

    Okay, what did we get?

    The Zen - that was cool.

    An angst-guilty Chris - of course since I haven't read an NA since... too long - I don't know what he was referring back to, except that it's presumably spoiled a previous NA, probably the one just before, "Eternity Weeps", yes?

    Fanboy-Joel returns! And drops in a few fannish references, B5 included... Not to mention references back to "Return of the Living Dad" and "Sleepy". Probably other ones that I missed, too.

    And the Doctor... his torture is on the inside, this time. Sort of.

    Plus assorted "demons", legends, fighting, and codes of honour. And how many ways can one pronounce "Chris"?

    And I love it how it all came together. Practically driving us nuts with not knowing what this ruddy pod is! Even though every man and his dog is fighting over it... typical, neh. And of course, driving us nuts wondering what the Room With No Doors is too. And What Does It All Mean? Read the book, and find out.

    Can a house stand, if it is divided among itself? Can a Doctor stand, if he is not at peace? This does a bit of foreshadowing about the 8th Doctor's genesis, which is cool too. Hmmm, can you call it foreshadowing if we all know what it is referring to already?

    This is a happening book - and not a happening book. The universe is not at stake, but that just brings it down to a level we can comprehend. People. There's certainly a lot of running around. And a lot of thinking, too.

    Oh, look, I don't know how it compares with her others, I just enjoyed it. I liked it better than Sleepy, but then that was the one of Kate's that I liked the least.

    Oh, and now that R.J. Anderson's "Sacrifice" is now officially quoted in an NA, I'll just have to mention that you'd better go off and read all of
    <http://www.pobox.com/~rebeccaj/:R.J. Anderson>'s 11th Doctor stories, too.
    (Two of which appeared in
    <http://www.katspace.com/enarrare/e09.html:Enarrare 9>).


    So Vile A Sin by Ben Aaronvich and Kate Orman

    reviewed by Kathryn Andersen

    They did it again! Another one of those "Huh, what the hell is going on?" books, from the now-team of Ben Aaronvich and Kate Orman, where it does all make sense in the end. And here, when we thought everything was fine, we knew it couldn't be, because the book wasn't over yet. And again, got to a point where one was thinking, "How on earth are they going to get out of this?" and they did anyway. Surely it must be hard to think of yet more universe-threatening threats, and yet they did it. And very sensibly, they put the body on page one. Since everybody knew she was dead already, might as well take advantage of that, and still manage to leave us in suspense.

    And of course, the in-jokes and past-adventures references - noticed the Tara reference - sneaky! And Kate(?) put in more "guns and frocks" jokes, um, in-jokes. I dunno, I can't see a reference to guns and frocks in Kate's books any more without smiling.

    But the title still looks like an anagram to me.

    A silver-dusted Rubic's Cube that someone does for you, on the Sid & Nancy scale.


    Lungbarrow by Marc Platt

    reviewed by Kathryn Andersen

    Well, I had gotten the impression from comments by other people that I would find this one confusing, that it would raise more questions than it answered, but I don't think so. It answered quite a few questions, or, strictly speaking, dropped the broadest of hints, hints which followed up the intriguing hints about the Doctor's past which had been dropped in COLD FUSION. Tied up quite a few loose ends, really. It even explained the return of the sonic screwdriver! In atmosphere, it reminded me somewhat of STRANGE ENGLAND, but more, really, of GHOST LIGHT.

    After I read this, I realized something about many of the New Adventures. Much of the TV Who was dedicated to de-mystifying things. Gods are just aliens, faith as a weapon against haemeovores, human culture as a result of alien interference, and so on. But the New Adventures are bringing the Mystery back - and I don't just mean making the Doctor more mysterious, Leela's comment in LUNGBARROW about the Doctor notwithstanding. All the bits about Death and Time and Pain, the "gods" of Gallifrey, are bringing back the Otherness (and I don't mean the Other!), bringing the Mythic into Doctor Who. And I like it.

    Sid & Nancy scale: a giant's house


    The Dying Days by Lance Parkin

    reviewed by Kathryn Andersen

    Here we are - the first of the New Adventures to feature the 8th Doctor instead of the seventh; the end of an era, and the beginning of a new one; ushered in by another on of the NA authors that I admire.

    Whee! This one was more slow-moving than the others I had read in my recent Who-thon. It was also more straightforward. I was tempted to complain that there wasn't enough of the Doctor and too much of Benny (if one could really have too much of a well-written Benny), that I didn't get to see the 8th Doctor shine in his own unique Doctorish way, but I was wrong. It just took a while, that's all. I kept on looking at the cover to remind myself of him. I'm looking forward to the BBCNA's simply because I want more 8th Doctor. But don't let me give you the impression that the Doctor and Benny are the only decent characters there. The Brigadier's there as well, and gets in his own thoughtful moments. Plus other supporting decent characters; particularly the little bits with Doug and Oswald. (grin) I have a suspicion that there are some in-jokes there that I missed. Oh well, didn't stop me from enjoying it. Particularly the end.

    Sid & Nancy scale: roast beef

    txt2html-2.53/tfiles/good_hyphens.html000066400000000000000000000001171352116237600201000ustar00rootroot00000000000000

    Blah blah blah blah blah blah. This paragraph has a hyphenated word.

    txt2html-2.53/tfiles/good_links.html000066400000000000000000000002731352116237600175450ustar00rootroot00000000000000

    This is a test of txt2html.

    testing txt2html in a header

    nu?

    txt2html-2.53/tfiles/good_links2.html000066400000000000000000000040001352116237600176170ustar00rootroot00000000000000

    This is a test file with some bizzare lines

    These get converted:

    I'm going to ftp ftp.howdy.com     yay!!
    I'm going to ftp abbaftp.howdy.com     yay!!
    I'm going to ftp ftpabba.howdy.com     yay!!
    I'm going to ftp abftpba.howdy.com     yay!!
    I'm going to ftp a_ftp_a.howdy.com     yay!!
    I'm going to ***ftp a_ftp_a.howdy.com***     yay!!
    

    These are correctly not converted:

    I'm going to 9bftpba.howdy.com     yay!!
    I'm going to -bftpba.howdy.com     yay!!
    I'm going to ***-bftpba.howdy.com***     yay!!
    

    These test beginning and end of line conversions:

    ftp ftp.howdy.com yay!!
    I'm going to ftp ftp.howdy.com
    ftp ftp.howdy.com

    The same jazz but with www in the name:

    These get converted:

    I'm going to www.howdy.com     yay!!
    I'm going to abbawww.howdy.com     yay!!
    I'm going to wwwabba.howdy.com     yay!!
    I'm going to abwwwba.howdy.com     yay!!
    I'm going to a_www_a.howdy.com     yay!!
    I'm going to ***a_www_a.howdy.com***     yay!!
    

    These are correctly not converted:

    I'm going to 9bwwwba.howdy.com     yay!!
    I'm going to -bwwwba.howdy.com     yay!!
    I'm going to ***-bwwwba.howdy.com***     yay!!
    

    These test beginning and end of line conversions:

    www.howdy.com yay!!
    I'm going to www.howdy.com
    www.howdy.com

    txt2html-2.53/tfiles/good_links3.html000066400000000000000000000011511352116237600176240ustar00rootroot00000000000000

    This is a link with a sub-anchor in it.

    (http://www.steelypips.org/nethack/id_faq.html#general)

    This should not be bolded.

    But this should be. And <http://www.example.com> should be linked.

    txt2html-2.53/tfiles/good_links4.html000066400000000000000000000003701352116237600176270ustar00rootroot00000000000000

    This is to test links with underscores in them.

    http://rapidshare.com/files/78582195/Futurama_-_S05E01_-_Crimes_Of_The_Hot.part1.rar

    txt2html-2.53/tfiles/good_list-2.html000066400000000000000000000017101352116237600175340ustar00rootroot00000000000000

    Simple Unordered

    This is just an unordered list.

    • Background to building a jump start/install server.
    • Extra setup required for district servers (Modem Ports)
    • Extra setup required for district servers (External Modems)

    Simple Ordered

    This is just an ordered list.

    1. First
    2. Second
    3. Third

    Mixed Lists

    This list is mixed. Each ordered item contains an unordered list.

    1. Bureau Server
      • Sun Sparcstation 20
      • Dual processor upgrade
    2. Bureau Contingency Server
      • Sun Sparcstation 20
      • Dual processor upgrade
    3. PC access Server (read only)
      • Sun Sparcstation 5/110Mhz
      • 96Meg of RAM
      • 4 X SCSI SBUS cards
    txt2html-2.53/tfiles/good_list-3.html000066400000000000000000000006041352116237600175360ustar00rootroot00000000000000

    some random text here.

    • part 1
      1. blah
      2. blah blah...

    some random text here.

    • part 2
      1. blah
      2. blah blah...

    some random text here.

    • part 3
      1. blah
      2. blah blah...

    some random text here.

    txt2html-2.53/tfiles/good_list-4.html000066400000000000000000000026201352116237600175370ustar00rootroot00000000000000

    Header

    • Item 1: works but looks ugly in text

      This is list item 1 which I will pad with asdashjk kjashdkajsh kjhaskjahs kajshkajsdh kajshkajshd

      This is another paragraph of list item 1 which I will pad with asdashjk kjashdkajsh kjhaskjahs kajshkajsdh kajshkajshd

    • Item 2: doesn't work but is readable as text

    This is list item 2 which I will pad with asdashjk kjashdkajsh kjhaskjahs kajshkajsdh kajshkajshd

    This is another paragraph of list item 2 which I will pad with asdashjk kjashdkajsh kjhaskjahs kajshkajsdh kajshkajshd

    • Item 3: does work and is readable as text

      This is list item 3 which I will pad with asdashjk kjashdkajsh kjhaskjahs kajshkajsdh kajshkajshd

      This is another paragraph of list item 3 which I will pad with asdashjk kjashdkajsh kjhaskjahs kajshkajsdh kajshkajshd

    • Item 4:

      This item explains the 2 test cases below:

      1. This is case 1
      2. This is case 2
    • Item 5: does indent to the previous level
    txt2html-2.53/tfiles/good_list-5.html000066400000000000000000000026261352116237600175460ustar00rootroot00000000000000

    Definition Lists

    A definition list comprises the following:

    Term
    The term part of a DL item is a word on a line by itself, ending with a colon.
    Definition
    The definition part of a DL item is at least one paragraph following the term.

    If one has more than one paragraph in the definition, the first line of the next paragraph needs to be indented two spaces from where the term starts, otherwise we don't know that it belongs to the definition.

    This is a new, separate paragraph.

    Mixed Lists

    Yadda Yadda
    1. a meaningless term
    2. something which Fred Flinstone says
    3. something with lawn in it

    Just to be clear, this is a paragraph.

    • Here's some unordered things.
      Unordered
      Something without order.
    • Item 2 in the unordered list.
      Ordered
      Something with order.
    • This should be item 3 in the unordered list.
    txt2html-2.53/tfiles/good_list-advanced.html000066400000000000000000000055551352116237600211530ustar00rootroot00000000000000

    For Grand Falls E1 events (loss of service for a long time) huge LOG files (200-300 thousand of lines) is a very typical and complicating characteristics. Many process (SWERRs, TRAPs, INFOs, etc) run in parallel and it is very important to understand what caused what. I want to suggest some tips that can make easier analysis of such log files.

    1. First of all learn ALL logs AT THE BEGINNING of the event. It is very important to understand what process began first. You should understand the meaning of EVERY log here.
    2. Unix tool awk could be very useful for logs files processing. Here are some simplest examples of its using.
      1. Cutting all logs of some definite type:
                   awk '/PM189/,length < 2' inp_file > out_file
                           ^           ^
                           |           |
          Where:    Pattern in the   End condition
                  first line of log  of log (empty string)
    

    b) Cutting all lines BEFORE lines with some pattern:

    awk '/INV CLASS/{print str;next}{str=$0}' inp_file > out_file

                  ^          ^       ^      ^
           Where: |          |       |      |
                  |     Output prev  |    Save full line
               Pattern     line    Go to
                                  next line
    

    c) Cutting all lines TWO lines BEFORE lines with some pattern:

    awk '/cp 35/{print str1;next}{str1=str;str=$0}' inp_file > out_file

    d) Prepare exec for site in the form: QDN dn

                                           QDN dn
                                           . . .
    

    awk '/ DN /{print "QDN " $8}' inp_file | sort | uniq > out_file

              ^                 ^
     Where:   |                 |
              |           Field number in line
    

    Selection pattern that contains dn

    3. If you need to answer question like that:

    "What dn's that appear in logs of type A appear in logs of type B too ?" (For example, how many dn's that appear in AUDT203 logs appear in logs of TPTSWER cp 35 - inter integrity lost ?)

    you could use the next procedure:

    1. Use 2a) for cutting all AUDT203 logs into one file and cp 35 logs into another.
    2. Use 2d) for producing of sorted list of dn's from these two new files.
    3. Use tool comm in the form:

    comm dn_list1_file dn_list2_file > out_file

           and in the out_file you will see three columns - in the
           third one common dn's will appear.
    
    txt2html-2.53/tfiles/good_list-custom.html000066400000000000000000000012051352116237600207040ustar00rootroot00000000000000

    Testing Different Bullets

    1. Is this an ordered list item?
    2. Because somebody did something.
    3. And added another!

    And then we'll have an unordered list.

    • with a pluss
    • as the new bullet, man.
      • and another indent, why not?
    • bask up
    txt2html-2.53/tfiles/good_list-styles.html000066400000000000000000000060221352116237600207170ustar00rootroot00000000000000

    STRATEGISKA BESLUTSSTÖDSSYSTEM

    Syfte

    Syftet med detta examensarbete är att studera vilka behov av beslutsunderlag som finns samt att i detta sammanhang undersöka vilka krav man bör ställa på informationssystem för beslutsstöd.

    Avgränsningar

    Vi kommer endast att rikta in oss på stödet för företags strategiska beslut i samband med expansion på främmande länders marknader. Vi avser endast att studera dessa behov och krav ur beslutsfattarens synvinkel.

    Innehåll

    • Människan
      • Beslutsprocessen
      • Perception
        • Läshastighet
      • Hur tolkas informationen
      • Parametermängd
    • Organisationen
      • Informationsflödet
      • Förändringar
    • Marknaden
      • Hur ser dagens informationssystem ut?
      • Effektivitet
      • Dagens tillvägagångssätt
    • Tekniken
      • Medium för spridning
      • Statisk respektive dynamisk information
      • Databaser
      • Säkerhet
        • Affärshemligheter
      • Agenter (robotar)

    Bakgrund

    I dagens samhälle av allt intensivare produktion av information och även behov av information måste beslutsfattarna allt snabbare fatta viktiga beslut. Med marknadernas utveckling mot allt snabbare faktorrörelser på det internationella planet måste även de strategiska besluten ofta fattas mycket snabbt. Man måste trots detta skaffa sig ett adekvat beslutsunderlag, vilket naturligtvis tar en viss tid, tid som man kanske inte har!

    Beslutsfattare behöver alltså hjälp från automatiserade verktyg. Frågor man ställs inför i detta sammanhang är bl.a. hur bör beslutsunderlagen utformas och vilka krav bör ställas på informationssystemen som förser beslutsfattarna med beslutsunderlagen.

    Tillvägagångssätt

    Kvalitativ undersökning genom intervjuer med företags beslutsfattare på olika nivåer, främst ansvariga för internationella marknader. Kvantitativ studie genom att undersöka vidtagna åtgärder vi olika företags etableringar utomlands, samt försöka relatera dessa till de uppnådda resultaten och sedan jämföra med hemmamarknaden.

    txt2html-2.53/tfiles/good_list.html000066400000000000000000000000601352116237600173720ustar00rootroot00000000000000
    • foo
      blah blah blah
    txt2html-2.53/tfiles/good_mixed.html000066400000000000000000000012211352116237600175250ustar00rootroot00000000000000

    This is an example of mixed input, with a list with what shouldn't be bold.

    • The '#' character can be used to introduce comment lines. Comments and lines that are empty or contain only whitespace are ignored.
    • Pipe characters and newlines within fields and '#' at the begin of the first field of an entry must be escaped with a backslash ('\').
    txt2html-2.53/tfiles/good_news.html000066400000000000000000000346411352116237600174070ustar00rootroot00000000000000

    From: force10ten@some.where.com (Force10Ten)
    Newsgroups: alt.archery
    Subject: Re: Binocular Purchase - Advice
    Date: 14 Jan 1996 02:03:01 -0500
    Reply-To: force10ten@some.where.com (Force10Ten)

    Because I'm looking for binoculars for use at the Olympic Games, I just spent quite a bit of time talking about this very subject with Jim Dougherty, Dave Myers, Jay Barrs and Dick Tone, all of whom have the opinion that the really good binoculars show their stuff in twilight. Myers told me this story at the Bowhunting Trade Show.

    He and his buddies were sheep hunting. There were 5 or 6 guys. One of them told the others "there's a sheep in this hollow" several hundred yards off. It was dusk. Nobody but this guy could see the sheep. Everybody had binoculars in the 100-300 dollar price range. Except this guy who had a set of Zeiss 10 x 50's. As he passed the glasses around every one of these guys could see the sheep perfectly clearly. Nobody could see it with the cheaper glasses.

    I chose a pair of Leica 10 x 42's for my task at the Olympics, which will be to do TV and venue play by play coverage of archery. I need to be able to call the arrows in the head-to-head instantly. These glasses are perfect for the job, which will really involve several weeks of looking through binoculars this year, what with test tournaments and my own shooting.

    My "A" list after shopping around is in the 700 to 1600 dollar price range as follows:

    1. Leica 10 x 42
    2. Bausch & Lomb Elite 10 x 42
    3. Zeiss 10 x 42
    4. Svarovski
    5. Docter Optik

    george t.

    From: bowbuff@some.where.com (Bowbuff)
    Newsgroups: alt.archery
    Subject: Re: Binocular Purchase - Advice
    Date: 16 Jan 1996 06:37:05 -0500

    Randy, just reread your question and it may be that the answers you received didn't answer your question about 8 vs 10 power in low light. Considering magnification alone the higher the power the worse it is likely to be in very low light. More important is the "exit pupil" of the binocs: The second number divided by the first. For example a 10x50 binoc has an exit pupil of 5, the same as a 7x35 or 8x40. This is the measure of light gathering ability of the unit. Ignoring power, quality of the optical elements, and lens coatings, an e.p. of 5 is the optimum. At least, I read somewhere that this is the maximum the human eye can process. All I know is that a top quality pair of 10x50, 8x40, or 7x35 glasses will pick up more light at dark than you can see with your naked eyes. Seriously, I was watching two bull elk fighting at dark in Rocky Mtn Nat'l Park and it became too dark to see them although they were in the open only 75 yards away. With my Swarovskis I could watch them for about another half hour when I got tired and gave up. The higher the e.p. the larger the binocs are physically, of course, as this means a bigger diameter exit lens and focal length as well.

    The lower the e.p., the worse your binocs will let you down in low light. This is why all the compacts are only useful during good light. The finest 8x24s or 10x25s will fit in your shirt pocket really neat....and you'll soon be leaving them there unless it is the middle of the day...or unless you really don't need to see very much.

    Optics and coatings are no less important for extended use, especially at very long ranges in the daylight. Unfortunately you cant sort this out by looking through them in a store or looking down the street in front of a store. The best way is to take them-and all the others you can beg, bum, or borrow out to the tallest mountain you know and compare them for hours, especially as it gets dark. The next best way is to follow the advice of the Rocky Mountain Bighorn Society: figure out what is the maximum you can spend on the finest optics - and then spend 25% more!

    Good Luck!

    From: abqkelly@some.where.netcom.com(John Kelly )
    Newsgroups: alt.archery
    Subject: Re: Binocular Purchase - Warsaw Pact Binocs
    Date: 16 Jan 1996 16:52:11 GMT

    >Optics and coatings are no less important for extended use, especially
    at

    >very long ranges in the daylight. Unfortunately you cant sort this
    out by

    >looking through them in a store or looking down the street in front of
    a
    >store.

    I had an opportunity to compare Leica, Swarkkkovyjowskiiskiskzsky, Zeiss, and "Warsaw Pact" 8X50s last year at a Rockey Mt Elk Camp event. You CAN make certain interesting and useful appraisals in that sort of situation. For example, you can evaluate color and contrast. You can look right into backlit areas, right at objects next to bright lights in the trade show ceiling, and judge internal refraction, contrast, and glare. IMHO the Leicas "looked" prettiest overall, I'd have loved a pair, were I a successful cocaine dealer or Phil Gramm.

    But a bowhunting pal bought WARSAW PACT "cheapies" ($500..widely advertised in hunting magazines) there, since they were MUCH brighter (apparently the equivalent of maybe two f-stops) and more contrasty than ANY of the others (not to mention, ahem, AFFORDABLE). They were VASTLY SUPERIOR in those respects.

    In the woods I later found you can look into deep shadows and they are lit as if they were video amplified. You can look directly into scenes involving the setting sun and still see clearly, FAR better than with the naked eye.

    There IS one BIG drawback: everything is a sickly greenish orange or yellow. The damned things are color blind. Otherwise they are exceptional at picking out shapes, movement etc under extremely difficult lighting conditions. That is exactly what they were designed for, of course, being military equipment, not bird watching equipment. NOTHING looks pretty through them. Is that a sacrifice that makes sense? Hmmm. Maybe that depends on your reasons for hunting.

    I've got Pentax and Nikon, under $200ea, and they have to fill the bill for now. I'm waiting for money from heaven. Maybe I'll go for better Nikons.

    JK

    From: Perry Ratcliff <ratcliff@some.where.trw.com>
    Newsgroups: alt.archery
    Subject: Re: Binocular Purchase - Advice
    Date: Sun, 14 Jan 96 07:36:28 PDT

    > I plan on purchasing a new pair of binoculars next hunting season and
    > would like some help. Let me know what you like or dislike. Also can
    > anyone tell what difference I might expect between an 8X and 10X
    > binocular. How does light conditions affect either one?
    >
    I also have Swarovskis 10x50 but haven't used them for a couple of years because they are so heavy. I'm now using Pentax 12x42 binoculars and am extremely pleased with them. They are very light for the size and have good light gathering capabilities. They are nitrogen filled and have never fogged up on me. I believe they cost me around $300 and feel that they are an outstanding value.

    If you are on a more modest budget there are some very good compact binoculars in the $150 range. Make sure that they are nitrogen filled to prevent fogging in the rain. If you wear glasses make certain that the binoculars have a long eye relief or you will lose a lot of light through the binoculars.

    Good Luck,

    Perry

    From: ap941@some.where.ysu.edu (Mark W. Thurm)
    Newsgroups: alt.archery
    Subject: Re: Binocular Purchase - Advice
    Date: 16 Jan 1996 17:07:13 GMT
    Reply-To: ap941@some.where.ysu.edu (Mark W. Thurm)

    >I plan on purchasing a new pair of binoculars next hunting season and
    >would like some help. Let me know what you like or dislike. Also can
    >anyone tell what difference I might expect between an 8X and 10X
    >binocular. How does light conditions affect either one?

    I have a pair of Cabellas compacts, 8 power, nitrogen filled, long eye relief. For the money ($100) they're a good deal (IMHO). I've looked at Ziess, Swarvoski. Brunton, etc. and they were excellent but with my constrants (married with children) my wife wouldn't authorize er... I couldn't justfy the 6-10 times price diferential.

    A 10 power compact will not gather much light and will be harder to hold steady. I hunt in the west and the 8x has worked well fo me.

    MT

    --

                It's not the bible that's filled with contradictions,
                     It's our brains that are filled with them.
                                 J. Vernon McGee
    

    Newsgroups: alt.archery
    From: jwf20@some.where.ccc.amdahl.com (Jim Flenniken)
    Subject: Re: Binocular Purchase - Advice
    Date: Tue, 16 Jan 1996 18:14:09 GMT

    Randy Ross <randyr@some.where.com> wrote:

    >I plan on purchasing a new pair of binoculars next hunting season and
    >would like some help. Let me know what you like or dislike. Also can
    >anyone tell what difference I might expect between an 8X and 10X
    >binocular. How does light conditions affect either one?

    >Thanks.

    >Randy

    Bushnell makes a pair of 'glasses on' binoculars that are excellent for those of us that wear glasses. the long eye-relief is a blessing when scanning a field while wearing glasses and the price is about $125.

    From: Alex Hoover <alexh>
    Newsgroups: alt.archery
    Subject: Re: Binocular Purchase - Advice
    Date: 16 Jan 1996 22:17:34 GMT

    I love my Pentax 10x24 UCF compact binocs. Small and lightweight, so I don't hesitate to take them everywhere. They are with me 100% of the time that I hunt. Bigger binocs are nicer, but can get in the way (especially if primary use will be while bowhunting).

    In the Fall 95 issue of the Gander Mountain catalog, the 10x cost $155, the 8x cost $140.

    There's some kind of formula about exit pupil that give guidelines on best magnification power. The gist is that unless you have a very large objective diameter (for the 10x24's, the objective is 24mm, which is relatively small), light will be transmitted bettter with a lower magnification. If I had it to do over, I would buy the Pentax compact binocs again, but I would get an 8x24 instead of 10x24.

    Regards,
    alex.hoover@some.where.com
    Denver, CO

    From: Alex Hoover <alexh>
    Newsgroups: alt.archery
    Subject: Re: Binocular Purchase - Advice
    Date: 16 Jan 1996 22:18:10 GMT

    I love my Pentax 10x24 UCF compact binocs. Small and lightweight, so I don't hesitate to take them everywhere. They are with me 100% of the time that I hunt. Bigger binocs are nicer, but can get in the way (especially if primary use will be while bowhunting).

    In the Fall 95 issue of the Gander Mountain catalog, the 10x cost $155, the 8x cost $140.

    There's some kind of formula about exit pupil that give guidelines on best magnification power. The gist is that unless you have a very large objective diameter (for the 10x24's, the objective is 24mm, which is relatively small), light will be transmitted bettter with a lower magnification. If I had it to do over, I would buy the Pentax compact binocs again, but I would get an 8x24 instead of 10x24.

    Regards,
    alex.hoover@some.where.com
    Denver, CO

    From: Alex Hoover <alexh>
    Newsgroups: alt.archery
    Subject: Re: Binocular Purchase - Advice
    Date: 16 Jan 1996 22:18:19 GMT

    I love my Pentax 10x24 UCF compact binocs. Small and lightweight, so I don't hesitate to take them everywhere. They are with me 100% of the time that I hunt. Bigger binocs are nicer, but can get in the way (especially if primary use will be while bowhunting).

    In the Fall 95 issue of the Gander Mountain catalog, the 10x cost $155, the 8x cost $140.

    There's some kind of formula about exit pupil that give guidelines on best magnification power. The gist is that unless you have a very large objective diameter (for the 10x24's, the objective is 24mm, which is relatively small), light will be transmitted bettter with a lower magnification. If I had it to do over, I would buy the Pentax compact binocs again, but I would get an 8x24 instead of 10x24.

    Regards,
    alex.hoover@some.where.com
    Denver, CO

    The following should be treated as mail quote, not as pre-formatted

    > 1 more
    > 2 more
    > 3 more
    > 4 more
    > 5 more

    Back to normal again. more and more, make it a long line, not a short one.

    > 1 more and more, make it a long line, not a short one.
    > 2 more and more, make it a long line, not a short one.
    > 3 more and more, make it a long line, not a short one.

    txt2html-2.53/tfiles/good_pre.html000066400000000000000000000011111352116237600172030ustar00rootroot00000000000000

    ## Test on pre-in-list

    txt2html.pl -p 7 -pb 1

    Here is an example bad file:

    1. text (should be translated as <LI>) (there should be no </OL> tag at this point)

      preformatted text.. ... and more

    2. this should be translated as <LI>

    ## Test on mail_quote-in-pre_explicit

    Here is the actuall file content. 
    Maybe more lines.
    > 1      more
    > 2      more
    
    txt2html-2.53/tfiles/good_pre2.html000066400000000000000000000002151352116237600172710ustar00rootroot00000000000000

    This is a text file.

            The text file ends with a block of preformatted text.
            This is the end of the file.
    
    txt2html-2.53/tfiles/good_punct.html000066400000000000000000000016021352116237600175530ustar00rootroot00000000000000

    Why do I keep on having these bright ideas? Miles wondered as he crawled through the service tunnel. It gave him uncomfortable flashbacks to the time he'd crawled through the ducting on Aslund station. Though at least this time he didn't have Gregor to worry about. No, just lizard things, and the Doctor. Now there was an unknown quantity. Sharp, yes, and knew too much about the wrong things, but... You are supposed to be a good judge of character, Miles, he thought to himself. It's a bit late to be second-guessing now.

    Miles sat up straighter in the chair and checked the settings again. The earbud in his ear had warmed to body-temperature, but it was still a hard lump. Part of him was gibbering Aliens! You're going to be talking to aliens! while another part of him was just getting impatient, waiting for the Doctor to return.

    txt2html-2.53/tfiles/good_robo.html000066400000000000000000000036321352116237600173700ustar00rootroot00000000000000

    Type: cmu.cs.robotics
    Topic: Robotics Seminar, Prof. John Canny, Friday Oct 11, 3:30, Adamson Wing, Baker Hall Dates: 11-Oct-91
    Time: 3:30
    Place: Adamson Wing, Baker Hall
    PostedBy: me on 11-Oct-91 at 01:39 from H.GP.CS.CMU.EDU (Michael Erdmann) Abstract:

    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    ***** Friendly Reminder: Robotics Seminar Today!! ***** ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    Date:11-Oct-91
    Time:3:30 (Refreshments at 3:15)
    Place:Adamson Wing, Baker Hall

    RISC-Robotics

                                  John Canny
                                U.C. Berkeley
    

    RISC in a robotics context stands for Reduced Intricacy in Sensing and Control. But it shares the same philosophy as RISC computer design. The idea is to replace complicated manipulation and sensing steps with combinations of simple ones. Industrial robotics research has focussed on anthropomorphism in the hope that once robots become sufficiently human-like, they will be able to solve all the tasks that they are currently incapable of doing. This approach is seductive and has led researchers further and further away from the real problems that hinder the proliferation of robots in manufacturing. The enthusiasm for robotics in industry which reached a peak in the mid 80's has all but disappeared after a protracted lack of progress on these problems.

    txt2html-2.53/tfiles/good_sample.html000066400000000000000000000276021352116237600177130ustar00rootroot00000000000000 txt2html/HTML::TextToHTML Sample Conversion

    txt2html/HTML::TextToHTML Sample Conversion

    This sample is based hugely on the original sample.txt produced by Seth Golub for txt2html.

    I used the following options to convert this document:

         -titlefirst -mailmode -make_tables
         --custom_heading_regexp '^ *--[\w\s]+-- *$'
         --system_link_dict txt2html.dict
         --append_body sample.foot --infile sample.txt --outfile sample.html
    

    This has either been done at the command line with:

    perl -MHTML::TextToHTML -e run_txt2html -- options

    or using the script

    txt2html options

    or from a (test) perl script with:

            use HTML::TextToHTML;
            my $conv = new HTML::TextToHTML();
            $conv->txt2html([options]);
    

    From bozo@clown.wustl.edu
    Return-Path: <bozo@clown.wustl.edu>
    Message-Id: <9405102200.AA04736@clown.wustl.edu>
    Content-Length: 1070
    From: bozo@clown.wustl.edu (Bozo the Clown)
    To: kitty@example.com (Kathryn Andersen)
    Subject: Re: HTML::TextToHTML
    Date: Sun, 12 May 2002 10:01:10 -0500

    Bozo wrote:

    BtC> Can you post an example text file with its html'ed output?
    BtC> That would provide a much better first glance at what it does
    BtC> without having to look through and see what the perl code does.

    Good idea. I'll write something up.


    The header lines were kept separate because they looked like mail headers and I have mailmode on. The same thing applies to Bozo's quoted text. Mailmode doesn't screw things up very often, but since most people are usually converting non-mail, it's off by default.

    Paragraphs are handled ok. In fact, this one is here just to demonstrate that.

    THIS LINE IS VERY IMPORTANT!
    (Ok, it wasn't that important)

    EXAMPLE HEADER

    Since this is the first header noticed (all caps, underlined with an "="), it will be a level 1 header. It gets an anchor named "section_1".

    Another example

    This is the second type of header (not all caps, underlined with "="). It gets an anchor named "section_1_1".

    Yet another example

    This header was in the same style, so it was assigned the same header tag. Note the anchor names in the HTML. (You probably can't see them in your current document view.) Its anchor is named "section_1_2". Get the picture?

    -- This is a custom header --

    You can define your own custom header patterns if you know what your documents look like.

    Features of HTML::TextToHTML

    • Handles different kinds of lists
      1. Bulleted
      2. Numbered
        • You can nest them as far as you want.
        • It's pretty decent about figuring out which level of list it is supposed to be on.
          • You don't need to change bullet markers to start a new list.
      3. Lettered
        1. Finally handles lettered lists
        2. Upper and lower case both work
          1. Here's an example
          2. I've been meaning to add this for some time.
        3. HTML without CSS can't specify how ordered lists should be indicated, so it will be a numbered list in most browsers.
      4. Definition lists (see below)
    • Doesn't screw up mail-ish things
    • Spots preformated text
                     It just needs to have enough whitespace in the line.
            Surrounding blank lines aren't necessary.  If it sees enough
            whitespace in a line, it preformats it.  How much is enough?
            Set it yourself at command line if you want.
    
    • You can append a file automatically to all converted files. This is handy for adding signatures to your documents.
    • Deals with paragraphs decently.

      Looks for short lines in the middle of paragraphs and keeps them short with the use of breaks (<BR>). How short the lines need to be is configurable.

      Unhyphenates split words that are in the middle of paragraphs. Let me know if trailing punctuation isn't handled "properly". It should be.

      One can also have multi-paragraph list items, like this one.

    • Puts anchors at all headers and, if you're using the mail header features, at the beginning of each mail message. The anchor names for headings are based on guessed section numbers.
      • You can turn off this option too, if you don't like it.
    • Groks Mosaic-style "formatted text" headers (like the one below)
    • Can hyperlink things according to a dictionary file. The sample dictionary handles URLs like http://www.aigeek.com/ and <http://www.katspace.com/> and also shows how to do simpler things such as linking the word txt2html the first time it appeared.
    • One can also use the link-dictionary to define custom tags, for example using the star character to indicate italics.
    • Recognises and parses tables of different types:
      • DELIM: A table determined by delimiters.
      • ALIGN: No need for fancy delimiters, this figures out a table by looking at the layout, the spacing of the cells.
      • BORDER: has a nice border around the table
      • PGSQL: the same format as Postgresql query results.
    • Also with XHTML! Turn on the --xhtml option and it will ensure that all paragraphs and list items have end-tags, all tags are in lower-case, and the doctype is for XHTML.

    Example of short lines

    We're the knights of the round table
    We dance whene'er we're able
    We do routines and chorus scenes
    With footwork impeccable.
    We dine well here in Camelot
    We eat ham and jam and spam a lot.

    Example of varied formatting

    If I want to emphasize something, then I'd use stars to wrap around the words, even if there were more than one, that's what I'd do. But I could also underline words, so long as the darn thing was not a_variable_name, in which case I wouldn't want to lose the underscores in something which thought it was underlining. Though we might want to underline more than one word in a sentence. Especially if it is The Title Of A Book. For another kind of emphasis, let's go and put something in bold.

    But it doesn't even need to be that simple. Something which is really exciting is coping with italics and similar things spread across multiple lines.

    Example of Long Preformatting

    (extract from Let It Rain by Kristen Hall)

            I have given, I have given and got none
            Still I'm driven by something I can't explain
            It's not a cross, it is a choice
            I cannot help but hear his voice
            I only wish that I could listen without shame
    
            Let it rain, let it rain, on me
            Let it rain, oh let it rain,
            Let it rain, on me
    
            I have been a witness to the perfect crime
            Wipe the grin off of my face to hide the pain
            It isn't worth the tears you cry
            To have a perfect alibi
            Now I'm beaten at the hands of my own game
    
            Let it rain, let it rain, on me
            Let it rain, oh let it rain,
            Let it rain, on me
    

    Definition Lists

    A definition list comprises the following:

    Term
    The term part of a DL item is a word on a line by itself, ending with a colon.
    Definition
    The definition part of a DL item is at least one paragraph following the term.

    If one has more than one paragraph in the definition, the first line of the next paragraph needs to be indented two spaces from where the term starts, otherwise we don't know that it belongs to the definition.

    Examples of Tables

    ALIGN

    Here is a simple ALIGN table:
    -eFile exists.
    -zFile has zero size.
    -sFile has nonzero size (returns size).

    Here are some of the conditions of ALIGN tables:
    Context:A table needs to be surrounded by blank lines.
    Length:A table must contain at least two rows.
    Width:A table must contain at least two columns.
    Spacing:There needs to be at least two spaces between the columns,
    otherwise there might be some random paragraph which
    could have inter-word spacing that lined up by accident.
    Cell Size:If you have more than one line (as just above) then
    you will simply get empty cells where the other column is empty.
    Alignment:Alignment of cells is attempted to be preserved.

    BORDER

    This is a table with a border.
    FoodQty
    Bread1
    Milk1
    Oranges3
    Apples6

    PGSQL

    This is the same table like Postgresql would make it.
    FoodQty
    Bread1
    Milk1
    Oranges3
    Apples6

    (4 rows)

    DELIM

    A delimited table needs to have its delimiters at the start and end, just to be sure that this is a table.
    FredNurk58
    GeorgeWashington62
    MaryQuant35

    And one can have almost any delimiter one wishes.
    Darcy, Fitzwilliamhero
    Bennet, Elizabethheroine
    Wickham, Georgevillain

    THINGS TO DO

    There are some things which this module doesn't handle yet which I would like to implement.

    1. I would like to be able to preserve lettered lists, that is:
      1. recognise that they are letters and not numbers (which it already does)
      2. display the correct OL properties with CSS so as to preserve that information.

    The footer is everything from the end of this sentence to the </BODY> tag.


    KatSpace
    txt2html-2.53/tfiles/good_table-align.html000066400000000000000000000012431352116237600206020ustar00rootroot00000000000000

    This is for testing a table which is regognised by its alignment.

    FruitVegetable
    BananaCarrot
    AppleCelery

    The following is not a table because there aren't enough spaces between items.

    Fred Nurk ate
    Mary Norton slept
    Hugh Jackman snarled

    But this one is.

    FredNurkate
    MaryNortonslept
    HughJackmansnarled
    txt2html-2.53/tfiles/good_table-border.html000066400000000000000000000037341352116237600207740ustar00rootroot00000000000000
    SchemaNameTypeOwner
    publicactor_episodesviewkat
    publicactorstablekat
    publiccopyableviewkat
    publicepisode_recordingviewkat
    publicepisodestablekat
    publicepisodes_title_id_seqsequencekat
    publicpal_recordingsviewkat
    publicrecordingstablekat
    publicsorted_epsviewkat
    publictapestablekat
    publicunrecordedviewkat
    publicwantingviewkat

    And the same table could be indented.

    SchemaNameTypeOwner
    publicactor_episodesviewkat
    publicactorstablekat
    publiccopyableviewkat
    publicepisode_recordingviewkat
    publicepisodestablekat
    publicepisodes_title_id_seqsequencekat
    publicpal_recordingsviewkat
    publicrecordingstablekat
    publicsorted_epsviewkat
    publictapestablekat
    publicunrecordedviewkat
    publicwantingviewkat
    txt2html-2.53/tfiles/good_table-delim.html000066400000000000000000000032311352116237600206010ustar00rootroot00000000000000

    Delimited Table

    This one was a border table from which I removed the divider lines.

    SchemaNameTypeOwner
    publicactor_episodesviewkat
    publicactorstablekat
    publiccopyableviewkat
    publicepisode_recordingviewkat
    publicepisodestablekat
    publicepisodes_title_id_seqsequencekat
    publicpal_recordingsviewkat
    publicrecordingstablekat
    publicsorted_epsviewkat
    publictapestablekat
    publicunrecordedviewkat
    publicwantingviewkat

    And this is a homegrown one.

    FredNurklives
    KerrAvonis wonderfule
     Servalanhas no first name

    And the next one has a caption, and a possibly tricky delimiter.

    Actors
    PaulDarrow
    JackiePierce

    Note that a CSV table doesn't work for delimiter stuff, because it isn't bounded by commas.

    Fred,Nurk
    Joe,Schmoe

    txt2html-2.53/tfiles/good_table-pgsql.html000066400000000000000000000020161352116237600206350ustar00rootroot00000000000000
    List of relations
    SchemaNameTypeOwner
    publicactor_episodesviewkat
    publicactorstablekat
    publiccopyableviewkat
    publicepisode_recordingviewkat
    publicepisodestablekat
    publicepisodes_title_id_seqsequencekat
    publicpal_recordingsviewkat
    publicrecordingstablekat
    publicsorted_epsviewkat
    publictapestablekat
    publicunrecordedviewkat
    publicwantingviewkat

    (12 rows)

    txt2html-2.53/tfiles/good_table-pgsql2.html000066400000000000000000000457561352116237600207410ustar00rootroot00000000000000
    titlesub_titletitle_idcategoryseries_titleepisode_positionseasonseason_positionepisode_codewanting
    Gathering, The 687SERIESHighlander111  
    Innocent Man 689SERIESHighlander212  
    Road Not Taken 694SERIESHighlander313  
    Bad Day In Building A 677SERIESHighlander414  
    Free Fall 686SERIESHighlander515  
    Deadly Medicine 680SERIESHighlander616  
    Mountain Men 691SERIESHighlander717  
    Revenge Is Sweet 693SERIESHighlander818  
    Sea Witch, The 696SERIESHighlander919  
    Eye Witness 681SERIESHighlander10110  
    Family Tree 683SERIESHighlander11111  
    See No Evil 697SERIESHighlander12112  
    Band of Brothers 678SERIESHighlander13113  
    For Evil's Sake 684SERIESHighlander14114  
    For Tomorrow We Die 685SERIESHighlander15115  
    Beast Below, The 679SERIESHighlander16116  
    Saving Grace 695SERIESHighlander17117  
    Lady and the Tiger, The 690SERIESHighlander18118  
    Avenging Angel 676SERIESHighlander19119  
    Eye of the Beholder 682SERIESHighlander20120  
    Nowhere To Run 692SERIESHighlander21121  
    Hunters, The 688SERIESHighlander22122  
    Watchers, The 698SERIESHighlander2321  
    Studies in Light 2820SERIESHighlander2422  
    Turnabout 2821SERIESHighlander2523  
    Darkness, The 2822SERIESHighlander2624  
    Eye For An Eye 2823SERIESHighlander2725  
    Zone, The 2824SERIESHighlander2826  
    Return of Amanda, The 2825SERIESHighlander2927  
    Revenge of The Sword 2826SERIESHighlander3028  
    Run For Your Life 2827SERIESHighlander3129  
    Epitaph For Tommy 2828SERIESHighlander32210  
    Bless The Child 2829SERIESHighlander33211  
    Fighter, The 2830SERIESHighlander34212  
    Under Color of Authority 2831SERIESHighlander35213  
    Unholy Alliance (1) 2832SERIESHighlander36214  
    Unholy Alliance (2) 2833SERIESHighlander37215  
    Vampire, The 2834SERIESHighlander38216  
    Warmonger 2835SERIESHighlander39217  
    Pharaoh's Daughter 2836SERIESHighlander40218  
    Legacy 2837SERIESHighlander41219  
    Prodigal Son 2838SERIESHighlander42220  
    Counterfeit (1) 2839SERIESHighlander43221  
    Counterfiet (2) 2840SERIESHighlander44222  
    Samurai, The 2875SERIESHighlander4531  
    Line of Fire 2876SERIESHighlander4632  
    Revolutionary, The 2877SERIESHighlander4733  
    Cross of St. Antoine 2878SERIESHighlander4834  
    Rite of Passage 2879SERIESHighlander4935  
    Courage 2880SERIESHighlander5036  
    Lamb, The 2881SERIESHighlander5137  
    Obsession 2882SERIESHighlander5238  
    Shadows 2883SERIESHighlander5339  
    BlackmailSwords, Lies & Videotape2884SERIESHighlander54310  
    Vendetta 2885SERIESHighlander55311  
    They Also Serve 2886SERIESHighlander56312  
    Blind Faith 2887SERIESHighlander57313  
    Song of the Executioner 3002SERIESHighlander58314  
    Star Crossed 3003SERIESHighlander59315  
    Methos 3004SERIESHighlander60316  
    Take Back the Night 3005SERIESHighlander61317  
    Testimony 3006SERIESHighlander62318  
    Mortal Sins 3007SERIESHighlander63319  
    Reasonable Doubt 3163SERIESHighlander 320  
    Finale 3164SERIESHighlander 321  
    Finale II 3165SERIESHighlander 322  
    Homeland 3166SERIESHighlander 41  
    Brothers In Arms 3167SERIESHighlander 42  
    Innocent, The 3168SERIESHighlander 43  
    Leader of the Pack 3169SERIESHighlander 44  
    Double Eagle 3170SERIESHighlander 45  
    Reunion 3171SERIESHighlander 46  
    Colonel, The 3172SERIESHighlander 47  
    Reluctant Heroes 3173SERIESHighlander 48  
    Wrath of Kali, The 3174SERIESHighlander 49  
    Chivalry 3175SERIESHighlander 410  
    Timeless 3176SERIESHighlander 411  
    Blitz, The 3177SERIESHighlander 412  
    Something WickedHakoya3261SERIESHighlander 413  
    DeliveranceLeap of Faith3262SERIESHighlander 414  
    Promises 3180SERIESHighlander 415  
    Methuselah's Gift 3426SERIESHighlander 416  
    Immortal Cimoli, The 3263SERIESHighlander 417  
    Through a Glass Darkly 3427SERIESHighlander 418  
    Double Jeopardy 3453SERIESHighlander 419  
    Till Death 3428SERIESHighlander 420  
    Judgement Day 3429SERIESHighlander 421  
    One Minute To Midnight 3430SERIESHighlander 422  
    Prophecy 3454SERIESHighlander 51  
    End of Innocence, The 3455SERIESHighlander 52  
    Manhunt 3456SERIESHighlander 53  
    Glory Days 3457SERIESHighlander 54  
    Dramatic Licence 3458SERIESHighlander 55  
    Money's No Object 3459SERIESHighlander 56  
    Haunted 3460SERIESHighlander 57  
    Little Tin God 3461SERIESHighlander 58  
    Messenger, The 3462SERIESHighlander 59  
    Valkyrie, The 3463SERIESHighlander 510  
    Comes A Horseman 3464SERIESHighlander 511  
    Revelations 6:8 3465SERIESHighlander 512  
    Ransom of Richard Redstone, The 3466SERIESHighlander 513  
    Duende 3467SERIESHighlander 514  
    Stone of Scone, The 3468SERIESHighlander 515  
    Forgive Us Our Trespasses 3469SERIESHighlander 516  
    Modern Prometheus, The 3470SERIESHighlander 517  
    Archangel 3471SERIESHighlander 518  
    Avatar 3624SERIESHighlander 61  
    Armageddon 3625SERIESHighlander 62  
    Sins of the Father 3626SERIESHighlander 63  
    Diplomatic Immunity 3888SERIESHighlander 64  
    Patient Number 7 3889SERIESHighlander 65  
    Black Tower 3936SERIESHighlander 66  
    Unusual Suspects 3904SERIESHighlander 67  
    Justice 3905SERIESHighlander 68  
    Deadly Exposure 3906SERIESHighlander 69  
    Two of Hearts 3937SERIESHighlander 610  
    Indiscretions 3938SERIESHighlander 611  
    To Be 3939SERIESHighlander 612  
    Not To Be 3940SERIESHighlander 613  
    Highlander 3105MOVIEHighlander     
    bloopers 3523SERIESHighlander     

    (121 rows)

    txt2html-2.53/tfiles/good_umlauttest.html000066400000000000000000000011561352116237600206350ustar00rootroot00000000000000

    Es geht darum, sie zu verändern zu ändern zu Ändern. Es geht darum, sie zu verändern zu ändern zu Ändern. Es geht darum, sie zu verändern zu ändern zu Ändern.

    ÄNDERN

    txt2html-2.53/tfiles/good_utf8.html000066400000000000000000000001471352116237600173130ustar00rootroot00000000000000

    Some UTF-8 characters

    $ echo 門牌號碼規劃

    Perhaps just tip of iceberg.

    txt2html-2.53/tfiles/good_xhtml_sample.html000066400000000000000000000307031352116237600211230ustar00rootroot00000000000000 txt2html/HTML::TextToHTML Sample Conversion

    txt2html/HTML::TextToHTML Sample Conversion

    This sample is based hugely on the original sample.txt produced by Seth Golub for txt2html.

    I used the following options to convert this document:

         -titlefirst -mailmode -make_tables
         --custom_heading_regexp '^ *--[\w\s]+-- *$'
         --system_link_dict txt2html.dict
         --append_body sample.foot --infile sample.txt --outfile sample.html
    

    This has either been done at the command line with:

    perl -MHTML::TextToHTML -e run_txt2html -- options

    or using the script

    txt2html options

    or from a (test) perl script with:

            use HTML::TextToHTML;
            my $conv = new HTML::TextToHTML();
            $conv->txt2html([options]);
    

    From bozo@clown.wustl.edu
    Return-Path: <bozo@clown.wustl.edu>
    Message-Id: <9405102200.AA04736@clown.wustl.edu>
    Content-Length: 1070
    From: bozo@clown.wustl.edu (Bozo the Clown)
    To: kitty@example.com (Kathryn Andersen)
    Subject: Re: HTML::TextToHTML
    Date: Sun, 12 May 2002 10:01:10 -0500

    Bozo wrote:

    BtC> Can you post an example text file with its html'ed output?
    BtC> That would provide a much better first glance at what it does
    BtC> without having to look through and see what the perl code does.

    Good idea. I'll write something up.


    The header lines were kept separate because they looked like mail headers and I have mailmode on. The same thing applies to Bozo's quoted text. Mailmode doesn't screw things up very often, but since most people are usually converting non-mail, it's off by default.

    Paragraphs are handled ok. In fact, this one is here just to demonstrate that.

    THIS LINE IS VERY IMPORTANT!
    (Ok, it wasn't that important)

    EXAMPLE HEADER

    Since this is the first header noticed (all caps, underlined with an "="), it will be a level 1 header. It gets an anchor named "section_1".

    Another example

    This is the second type of header (not all caps, underlined with "="). It gets an anchor named "section_1_1".

    Yet another example

    This header was in the same style, so it was assigned the same header tag. Note the anchor names in the HTML. (You probably can't see them in your current document view.) Its anchor is named "section_1_2". Get the picture?

    -- This is a custom header --

    You can define your own custom header patterns if you know what your documents look like.

    Features of HTML::TextToHTML

    • Handles different kinds of lists
      1. Bulleted
      2. Numbered
        • You can nest them as far as you want.
        • It's pretty decent about figuring out which level of list it is supposed to be on.
          • You don't need to change bullet markers to start a new list.
      3. Lettered
        1. Finally handles lettered lists
        2. Upper and lower case both work
          1. Here's an example
          2. I've been meaning to add this for some time.
        3. HTML without CSS can't specify how ordered lists should be indicated, so it will be a numbered list in most browsers.
      4. Definition lists (see below)
    • Doesn't screw up mail-ish things
    • Spots preformated text
                     It just needs to have enough whitespace in the line.
            Surrounding blank lines aren't necessary.  If it sees enough
            whitespace in a line, it preformats it.  How much is enough?
            Set it yourself at command line if you want.
    
    • You can append a file automatically to all converted files. This is handy for adding signatures to your documents.
    • Deals with paragraphs decently.

      Looks for short lines in the middle of paragraphs and keeps them short with the use of breaks (<BR>). How short the lines need to be is configurable.

      Unhyphenates split words that are in the middle of paragraphs. Let me know if trailing punctuation isn't handled "properly". It should be.

      One can also have multi-paragraph list items, like this one.

    • Puts anchors at all headers and, if you're using the mail header features, at the beginning of each mail message. The anchor names for headings are based on guessed section numbers.
      • You can turn off this option too, if you don't like it.
    • Groks Mosaic-style "formatted text" headers (like the one below)
    • Can hyperlink things according to a dictionary file. The sample dictionary handles URLs like http://www.aigeek.com/ and <http://www.katspace.com/> and also shows how to do simpler things such as linking the word txt2html the first time it appeared.
    • One can also use the link-dictionary to define custom tags, for example using the star character to indicate italics.
    • Recognises and parses tables of different types:
      • DELIM: A table determined by delimiters.
      • ALIGN: No need for fancy delimiters, this figures out a table by looking at the layout, the spacing of the cells.
      • BORDER: has a nice border around the table
      • PGSQL: the same format as Postgresql query results.
    • Also with XHTML! Turn on the --xhtml option and it will ensure that all paragraphs and list items have end-tags, all tags are in lower-case, and the doctype is for XHTML.

    Example of short lines

    We're the knights of the round table
    We dance whene'er we're able
    We do routines and chorus scenes
    With footwork impeccable.
    We dine well here in Camelot
    We eat ham and jam and spam a lot.

    Example of varied formatting

    If I want to emphasize something, then I'd use stars to wrap around the words, even if there were more than one, that's what I'd do. But I could also underline words, so long as the darn thing was not a_variable_name, in which case I wouldn't want to lose the underscores in something which thought it was underlining. Though we might want to underline more than one word in a sentence. Especially if it is The Title Of A Book. For another kind of emphasis, let's go and put something in bold.

    But it doesn't even need to be that simple. Something which is really exciting is coping with italics and similar things spread across multiple lines.

    Example of Long Preformatting

    (extract from Let It Rain by Kristen Hall)

            I have given, I have given and got none
            Still I'm driven by something I can't explain
            It's not a cross, it is a choice
            I cannot help but hear his voice
            I only wish that I could listen without shame
    
            Let it rain, let it rain, on me
            Let it rain, oh let it rain,
            Let it rain, on me
    
            I have been a witness to the perfect crime
            Wipe the grin off of my face to hide the pain
            It isn't worth the tears you cry
            To have a perfect alibi
            Now I'm beaten at the hands of my own game
    
            Let it rain, let it rain, on me
            Let it rain, oh let it rain,
            Let it rain, on me
    

    Definition Lists

    A definition list comprises the following:

    Term
    The term part of a DL item is a word on a line by itself, ending with a colon.
    Definition
    The definition part of a DL item is at least one paragraph following the term.

    If one has more than one paragraph in the definition, the first line of the next paragraph needs to be indented two spaces from where the term starts, otherwise we don't know that it belongs to the definition.

    Examples of Tables

    ALIGN

    Here is a simple ALIGN table:

    -eFile exists.
    -zFile has zero size.
    -sFile has nonzero size (returns size).

    Here are some of the conditions of ALIGN tables:

    Context:A table needs to be surrounded by blank lines.
    Length:A table must contain at least two rows.
    Width:A table must contain at least two columns.
    Spacing:There needs to be at least two spaces between the columns,
    otherwise there might be some random paragraph which
    could have inter-word spacing that lined up by accident.
    Cell Size:If you have more than one line (as just above) then
    you will simply get empty cells where the other column is empty.
    Alignment:Alignment of cells is attempted to be preserved.
    BORDER

    This is a table with a border.

    FoodQty
    Bread1
    Milk1
    Oranges3
    Apples6
    PGSQL

    This is the same table like Postgresql would make it.

    FoodQty
    Bread1
    Milk1
    Oranges3
    Apples6

    (4 rows)

    DELIM

    A delimited table needs to have its delimiters at the start and end, just to be sure that this is a table.

    FredNurk58
    GeorgeWashington62
    MaryQuant35

    And one can have almost any delimiter one wishes.

    Darcy, Fitzwilliamhero
    Bennet, Elizabethheroine
    Wickham, Georgevillain

    THINGS TO DO

    There are some things which this module doesn't handle yet which I would like to implement.

    1. I would like to be able to preserve lettered lists, that is:
      1. recognise that they are letters and not numbers (which it already does)
      2. display the correct OL properties with CSS so as to preserve that information.

    The footer is everything from the end of this sentence to the </BODY> tag.


    KatSpace
    txt2html-2.53/tfiles/heading1.txt000066400000000000000000000475321352116237600167610ustar00rootroot00000000000000Doctor Who New Adventures ************************* *The Left-Handed Hummingbird* by Kate Orman =========================================== (an attempt at a spoiler-free review by Kathryn Andersen) This novel is right up there with Love & War in the best NA category, I think. Why? Hmmm. Many of the NA's are "okay". They have nothing *wrong* with them. But to be an outstanding story, it needs something extra; some character insight or development which changes the relationship of the major characters, an original plot/twist/adversary, an excellent turn of phrase - and LHH had all of these. Here, the Doctor is put in a position he has never been in before, hoist on his own petard, a victim of his own way of doing things, caught in a trap that travels with him. (I am reminded of the Blake's 7 quote: *"When you know an enemy's strengths, and can use them against them, they become weaknesses."* -- Servalan, to Travis (Blake's 7: Weapon [B3]) ) There are some good insights about him and Ace, wondering if they are more alike than they like to admit... And finally, those turning phrases, made me want to write again. It's not often you get some lovely stuff you'd like to quote - my quotes file has many gems from "Transit", but hardly anything from the other NA's. This one doesn't have as many quotable jewels, but a number of places that made you sit up and take notice. My favourite is: "Ashes to nothing. Dust to nothing. Live fast, die young, and leave a beautiful empty space where you used to be." (p220) ------------------------------------------------------------- This story stood out because, as I said above, this is the first time that the *Doctor* has been a victim. There have been times when he has been helpless to help others. There have been times when he has been at the losing end, but he has been in control, able to play for time. There has even been the time, with the Timewyrm, where half the time he hasn't been in control, but he has always been playing his game, fencing with the enemy. This time he couldn't fence at all. The quote from Nietzsche at the start is doubly fitting now that I know what happened. Because that's what happened. He gazed into the Abyss, and became a monster. This is a good follow-on from The Dimension Riders, because the stakes have upped. In The Dimension Riders, for the first time, the Doctor's clever plan didn't work, and someone else's clever plan did. He was helped by someone else. And in The Left-Handed Hummingbird, the Doctor was up against something too big for him to handle; he hardly had a plan at all (no great plan involves suicide...), and that didn't work either. The Doctor is so used to being more capable than everyone else he meets, is he incapable of accepting help from others? I mean real help, not directed assistance to fight the enemy. He got into this trouble because he went looking for it. Sid & Nancy scale: a thunderstorm wrapped in blue ------------------------------------------------------------- *First Frontier* ================ an attempt at a spoiler-free review by Kathryn Andersen So, here's the latest NA to pass through my hands. I'm wondering if the inverse-cover-rule applies to this one: the cover is great, the book isn't. But actually, the book was okay, even if not terrific. I can understand why the author said he did it for fun. Strangely enough, it picked up in the latter half of the book - or else I merely changed my mood and decided I wanted to read it. The Ace characterisation harked back to the earlier Ace - or perhaps I was reminded of her because this was, in its own way, a sequel to "Survival", and that part of it it did well. I tip my hat to the author that I did not suspect who Kreer really was until it was revealed, even though enough clues were left around for someone more astute than I to figure it out, maybe. If I were more up with UFO-ology, I might also tip my hat to the author about his UFO research, but I don't know enough to know if he did it well. Benny doesn't seem to have much to do, and the Doctor doesn't feature as much as he might - there seems to be an abundance of supporting characters being suspicious of each other, following orders, or being victims. It was readable, but I'm keeping it for the cover. 8-) Sid & Nancy scale: a model kit of a flying saucer ------------------------------------------------------------- *Falls The Shadow* ================== reviewed by Kathryn Andersen Well, I finally read this one, months after I got it. I can see why someone compared this with "Strange England", though in one sense, "Strange England" was more vividly horrible. There was more horror in those singing insects than there was in the two villains. Yet another NA with a surreal landscape. I wonder if it's a requirement. No, I don't *dislike* surreal landscapes, it's just that you start to get weary of them when they happen a lot. Which NA's *didn't* have a surreal landscape in there somewhere? Am I becoming jaded, or are the NAs all running into each other in ordinariness? Okay spoiler warning time. Discussion time. The cover didn't help. Hard to think of Gabriel and Tanith as perfect in beauty when the pictures of them on the cover weren't very beautiful at all. Gabriel and Tanith were just violent. Continuously and sadistically violent. But the most interesting question, and here's for the discussion time: who *is* the grey man? I mean the author seems to be proposing a change in the metaphysical nature of the Whoniverse, but there are several things that don't make sense about it. - Grey. With white as Good and Black as Evil, Grey seems to style himself as Doubt. But on the other hand, he seems to style himself as Chaos. Now, I agree that Order and Chaos are neither good nor evil (since things like Nazi dictatorships can be very evil and very orderly). But... aw, I think part of my problem here is that I disagree with the standing metaphysical order of the Whoniverse with the Black and White Guardians being *equal* and opposite, so trying to slot a Grey Guardian in there is adding to my confusion. But still, I don't really understand what he's supposed to stand for. Doubt? (and how would doubt apply to Evil?) Chaos? (and doesn't Evil want to create chaos as well as order?) Freedom? (but doesn't Good want to create freedom?) - His people. Who are his people? Are the Black Guardian and the White Guardian of his people, or something else? And if they are, then who are the rest, or are there only three of them? Who are they? I think I had some more questions, but I can't remember what they were. Kathryn Andersen (now I can read Set Piece! Yay!) Later, on Thu, 30 Mar 1995... Ah, I remember now. The other query/problem I had with "Falls the Shadow". And it was the most important one too. #Whoniversal metaphysics warning# #Falls The Shadow spoiler warning# Okay, so Gabriel and Tanith were born out of the pain of the universe, a wounding of the universe, the pain of destroyed potential futures, such as the one that Jane Page came from. And the Doctor felt guilty because such pain was caused by him and other time travellers. Am I right, or did I completely miss what was happening? Because, if that's the case, however poetically appealing it is, it doesn't make any sense. Because time travel isn't the only thing that destroys potential futures. If time travel was never invented, millions of potential futures are destroyed every second, every time someone makes a decision. Is the author trying to tell me that the *natural* order of the universe (that is, a universe supposing time travel had never been invented, an untampered-with universe) causes a wounding of the universe? Where is the logic in that, the design? I am assuming that the Darvil-Evans structure of the Whoniverse is the one that needs to be used: the one which sets the Doctor's Gallifrey way way back in (to us) the past, which is actually the Present. And the nature of time travel is such that it is impossible to travel into the Past, into a point before the Present (thus nobody goes back in time to have a chat to Rassillon etc), but it is possible to travel into the future, but the act of travelling into the future and observing and participating in it, makes that future certain (or almost certain) to occur. It crystalizes it, so to speak. That there is only one universe; parallel universes take a great deal of energy to create and they are only temporary. It is not impossible to change history, but it is difficult, destructive, and a very Bad Thing. So, in all this, why is there pain at the wiping out of possible futures? It's not as if they had a *right* to exist: there can be only one history-of-the-universe in the end. What exists, exists. What might have existed does *not* exist, and should not exist. Is it because these potential futures were wiped out "sooner" than they might have been? Because the actions/decisions that wiped them out happened before the Present moment actually arrived there? But what does "before" mean in that context? We're talking about meta-time here, and that's so hairy I think I'll leave it. (sigh) Sid & Nancy scale: a Ken Done painting ------------------------------------------------------------- *Set Piece* by Kate Orman ========================= Date - June 5th 1995 reviewed by Kathryn Andersen The obvious book to compare "Set Piece" to would be the previous excursion of Kate Orman into the realms of the New Adventures - "The Left-Handed Hummingbird" (otherwise known in fannish shorthand as "Hummer"). Oddly enough, I think "Set Piece" was both better and not as good as Hummer. Better, because I can think of not a thing to point to that was a problem (on the other hand, maybe I just wasn't looking carefully enough?). Not as good simply because it wasn't the same kind of rollercoaster ride that Hummer was, not as much of the sheer *angstiness* that was in Hummer. Not the same psychological torture - here I was more worried about Ace than the Doctor. But maybe that's just that it's a different book. And it would be only half a point difference anyway. I did really like Set Piece. Action and characterisation in even amounts, a few surprises, and a few not-surprises. 8.5 or 9 out of 10. This story is really Ace's story, not really surprising since this is the book in which she is written out of the series. The Doctor and Benny have their parts to play, but Ace is the emotional heart of the tale. The three time travellers are cast adrift through history when a rescue attempt goes awry, and the three have to survive in different eras while *something* living in a crack in space-time preys on people from the past, present and future. Here, Ace is all alone, in the alien (to her) culture of Ancient Egypt, with only her own resources to fall back on, surviving and waiting, waiting, waiting for the Doctor to turn up and tell her the sneaky plan he had been preparing all this while. But the last time she saw the Doctor, "Benny was stooped over the Doctor, frantically trying to get a response out of him. Blood was trickling from his mouth and nose, sluggishly. His eyes had flicked shut. Ace wished she could tell Benny that the Doctor was dead." Isolated, despairing, Ace is in danger of losing her soul, of making the worst mistake in her life... Again, Kate Orman has sprinkled the work with sharp pieces of prose: "Suddenly the Doctor did not walk up and say hello." (p50) about Ace's loneliness. "When you're short of everything except the enemy, you know you're in combat." (p138) was another good example. And touches of humour here and there. One might make a complaint, though, that the Whoniverse is becoming cluttered with metaphysical constructs; previous New Adventures have dream-encounters with Death and Time - here we meet Pain, with the Doctor as Time's butterfly. I guess that depends on how much one enjoys symbolism. There are some very good character moments - for Ace and the Doctor particularly. Ace faces herself, and the Doctor wins by losing. The plot as a whole comes together piece by piece, jumping about from time and place (with a flashback and a red herring or two to stop it from being too straightforward), becoming clearer as it goes along, and tieing itself together very satisfactorily. No megalomaniacs, no 'fixed up in the last five minutes with the wave of a gizmo', and not even a 'I've been subtly planning this behind the scenes for months' which tends to happen with the 7th Doctor. The way in which Ace departs the series had me cheering. I couldn't have asked for a better way for her to go. And I'd better not say any more about that for fear of letting slip hints about what happens. If you are reading the New Adventures at all, there are no excuses for not reading this one, except perhaps putting it off until you've read all the previous ones by Paul Cornell, Ben Aaronovich and Kate Orman. Sid & Nancy scale: chocolate cake with ice cream ------------------------------------------------------------------- *Sky Pirates* by Dave Stone =========================== note on rec.arts.drwho on Thu Aug 17 1995 from kat I only have two things to say about this NA: 1. I expect that persons will have similar attitudes towards this as they had about The Highest Science. 2. It made *me* laugh. Kathryn Andersen (who hasn't read radw for months...) Sid & Nancy scale: Mystery Science Theatre 3000 ----------------------------------------------------------------------- *The Room With No Doors* by Kate Orman ====================================== a rambling rave by Kathryn Andersen Whee! She did it again! So I couldn't put it down, what's the surprise in that? First warning - ignore the back cover blurb. It's misleading. It tells you too much about the wrong things. Okay, what did we get? The Zen - that was cool. An angst-guilty Chris - of course since I haven't read an NA since... too long - I don't know what he was referring back to, except that it's presumably spoiled a previous NA, probably the one just before, "Eternity Weeps", yes? Fanboy-Joel returns! And drops in a few fannish references, B5 included... Not to mention references back to "Return of the Living Dad" and "Sleepy". Probably other ones that I missed, too. And the Doctor... his torture is on the inside, this time. Sort of. Plus assorted "demons", legends, fighting, and codes of honour. And how many ways can one pronounce "Chris"? And I love it how it all came together. Practically driving us nuts with not knowing what this ruddy pod *is*! Even though every man and his dog is fighting over it... typical, neh. *And* of course, driving us nuts wondering what the Room With No Doors is too. And What Does It All Mean? Read the book, and find out. Can a house stand, if it is divided among itself? Can a Doctor stand, if he is not at peace? This does a bit of foreshadowing about the 8th Doctor's genesis, which is cool too. Hmmm, can you call it foreshadowing if we all know what it is referring to already? This is a happening book - and not a happening book. The universe is not at stake, but that just brings it down to a level we can comprehend. People. There's certainly a lot of running around. And a lot of thinking, too. Oh, look, I don't know how it compares with her others, I just enjoyed it. I liked it better than Sleepy, but then that was the one of Kate's that I liked the least. Oh, and now that R.J. Anderson's "Sacrifice" is now officially quoted in an NA, I'll just have to mention that you'd better go off and read all of 's 11th Doctor stories, too. (Two of which appeared in ). ------------------------------------------------------------------- *So Vile A Sin* by Ben Aaronvich and Kate Orman =============================================== reviewed by Kathryn Andersen They did it again! Another one of those "Huh, what the hell is going on?" books, from the now-team of Ben Aaronvich and Kate Orman, where it *does* all make sense in the end. And here, when we thought everything was fine, we knew it couldn't be, because the book wasn't over yet. And again, got to a point where one was thinking, "How on earth are they going to get out of *this*?" and they did anyway. Surely it must be hard to think of yet more universe-threatening threats, and yet they did it. And very sensibly, they put the body on page one. Since everybody knew she was dead already, might as well take advantage of that, and still manage to leave us in suspense. And of course, the in-jokes and past-adventures references - noticed the Tara reference - sneaky! And Kate(?) put in more "guns and frocks" jokes, um, in-jokes. I dunno, I can't see a reference to guns and frocks in Kate's books any more without smiling. But the title *still* looks like an anagram to me. A silver-dusted Rubic's Cube that someone does for you, on the Sid & Nancy scale. --------------------------------------------------------------------- *Lungbarrow* by Marc Platt ========================== reviewed by Kathryn Andersen Well, I had gotten the impression from comments by other people that I would find this one confusing, that it would raise more questions than it answered, but I don't think so. It answered quite a few questions, or, strictly speaking, dropped the broadest of hints, hints which followed up the intriguing hints about the Doctor's past which had been dropped in COLD FUSION. Tied up quite a few loose ends, really. It even explained the return of the sonic screwdriver! In atmosphere, it reminded me somewhat of STRANGE ENGLAND, but more, really, of GHOST LIGHT. After I read this, I realized something about many of the New Adventures. Much of the TV Who was dedicated to de-mystifying things. Gods are just aliens, faith as a weapon against haemeovores, human culture as a result of alien interference, and so on. But the New Adventures are bringing the Mystery back - and I don't just mean making the Doctor more mysterious, Leela's comment in LUNGBARROW about the Doctor notwithstanding. All the bits about Death and Time and Pain, the "gods" of Gallifrey, are bringing back the Otherness (and I don't mean the Other!), bringing the Mythic into Doctor Who. And I like it. Sid & Nancy scale: a giant's house --------------------------------------------------------------------- *The Dying Days* by Lance Parkin ================================ reviewed by Kathryn Andersen Here we are - the first of the New Adventures to feature the 8th Doctor instead of the seventh; the end of an era, and the beginning of a new one; ushered in by another on of the NA authors that I admire. Whee! This one was more slow-moving than the others I had read in my recent Who-thon. It was also more straightforward. I was tempted to complain that there wasn't enough of the Doctor and too much of Benny (if one could really have too much of a well-written Benny), that I didn't get to see the 8th Doctor shine in his own unique Doctorish way, but I was wrong. It just took a while, that's all. I kept on looking at the cover to remind myself of him. I'm looking forward to the BBCNA's simply because I want more 8th Doctor. But don't let me give you the impression that the Doctor and Benny are the only decent characters there. The Brigadier's there as well, and gets in his own thoughtful moments. Plus other supporting decent characters; particularly the little bits with Doug and Oswald. (grin) I have a suspicion that there are some in-jokes there that I missed. Oh well, didn't stop me from enjoying it. Particularly the end. Sid & Nancy scale: roast beef txt2html-2.53/tfiles/hyphens.txt000066400000000000000000000001111352116237600167350ustar00rootroot00000000000000Blah blah blah blah blah blah. This paragraph has a hyphen- ated word. txt2html-2.53/tfiles/links.txt000066400000000000000000000001351352116237600164050ustar00rootroot00000000000000This is a test of txt2html. testing txt2html in a header ---------------------------- nu? txt2html-2.53/tfiles/links2.txt000066400000000000000000000022531352116237600164720ustar00rootroot00000000000000This is a test file with some bizzare lines These get converted: I'm going to ftp.howdy.com yay!! I'm going to abbaftp.howdy.com yay!! I'm going to ftpabba.howdy.com yay!! I'm going to abftpba.howdy.com yay!! I'm going to a_ftp_a.howdy.com yay!! I'm going to ***a_ftp_a.howdy.com*** yay!! These are correctly not converted: I'm going to 9bftpba.howdy.com yay!! I'm going to -bftpba.howdy.com yay!! I'm going to ***-bftpba.howdy.com*** yay!! These test beginning and end of line conversions: ftp.howdy.com yay!! I'm going to ftp.howdy.com ftp.howdy.com The same jazz but with www in the name: These get converted: I'm going to www.howdy.com yay!! I'm going to abbawww.howdy.com yay!! I'm going to wwwabba.howdy.com yay!! I'm going to abwwwba.howdy.com yay!! I'm going to a_www_a.howdy.com yay!! I'm going to ***a_www_a.howdy.com*** yay!! These are correctly not converted: I'm going to 9bwwwba.howdy.com yay!! I'm going to -bwwwba.howdy.com yay!! I'm going to ***-bwwwba.howdy.com*** yay!! These test beginning and end of line conversions: www.howdy.com yay!! I'm going to www.howdy.com www.howdy.com txt2html-2.53/tfiles/links3.txt000066400000000000000000000003041352116237600164660ustar00rootroot00000000000000This is a link with a sub-anchor in it. (http://www.steelypips.org/nethack/id_faq.html#general) This should not be bolded. But #this# should be. And should be linked. txt2html-2.53/tfiles/links4.txt000066400000000000000000000002071352116237600164710ustar00rootroot00000000000000This is to test links with underscores in them. http://rapidshare.com/files/78582195/Futurama_-_S05E01_-_Crimes_Of_The_Hot.part1.rar txt2html-2.53/tfiles/list-2.txt000066400000000000000000000013371352116237600164040ustar00rootroot00000000000000Simple Unordered ---------------- This is just an unordered list. - Background to building a jump start/install server. - Extra setup required for district servers (Modem Ports) - Extra setup required for district servers (External Modems) Simple Ordered -------------- This is just an ordered list. 1. First 2. Second 3. Third Mixed Lists ----------- This list is mixed. Each ordered item contains an unordered list. 1. Bureau Server - Sun Sparcstation 20 - Dual processor upgrade 2. Bureau Contingency Server - Sun Sparcstation 20 - Dual processor upgrade 3. PC access Server (read only) - Sun Sparcstation 5/110Mhz - 96Meg of RAM - 4 X SCSI SBUS cards txt2html-2.53/tfiles/list-3.txt000066400000000000000000000003231352116237600163770ustar00rootroot00000000000000 some random text here. * part 1 1. blah 2. blah blah... some random text here. * part 2 1. blah 2. blah blah... some random text here. * part 3 1. blah 2. blah blah... some random text here. txt2html-2.53/tfiles/list-4.txt000066400000000000000000000017411352116237600164050ustar00rootroot00000000000000Header ----- * Item 1: works but looks ugly in text This is list item 1 which I will pad with asdashjk kjashdkajsh kjhaskjahs kajshkajsdh kajshkajshd This is another paragraph of list item 1 which I will pad with asdashjk kjashdkajsh kjhaskjahs kajshkajsdh kajshkajshd * Item 2: doesn't work but is readable as text This is list item 2 which I will pad with asdashjk kjashdkajsh kjhaskjahs kajshkajsdh kajshkajshd This is another paragraph of list item 2 which I will pad with asdashjk kjashdkajsh kjhaskjahs kajshkajsdh kajshkajshd * Item 3: does work and is readable as text This is list item 3 which I will pad with asdashjk kjashdkajsh kjhaskjahs kajshkajsdh kajshkajshd This is another paragraph of list item 3 which I will pad with asdashjk kjashdkajsh kjhaskjahs kajshkajsdh kajshkajshd * Item 4: This item explains the 2 test cases below: 1) This is case 1 2) This is case 2 * Item 5: does indent to the previous level txt2html-2.53/tfiles/list-5.txt000066400000000000000000000015561352116237600164120ustar00rootroot00000000000000Definition Lists ================= A definition list comprises the following: Term: The term part of a DL item is a word on a line by itself, ending with a colon. Definition: The definition part of a DL item is at least one paragraph following the term. If one has more than one paragraph in the definition, the first line of the next paragraph needs to be indented two spaces from where the term starts, otherwise we don't know that it belongs to the definition. This is a new, separate paragraph. Mixed Lists ----------- Yadda_Yadda: a) a meaningless term b) something which Fred Flinstone says c) something with lawn in it Just to be clear, this is a paragraph. * Here's some unordered things. Unordered: Something without order. * Item 2 in the unordered list. Ordered: Something with order. * This should be item 3 in the unordered list. txt2html-2.53/tfiles/list-advanced.txt000066400000000000000000000045631352116237600200140ustar00rootroot00000000000000 For Grand Falls E1 events (loss of service for a long time) huge LOG files (200-300 thousand of lines) is a very typical and complicating characteristics. Many process (SWERRs, TRAPs, INFOs, etc) run in parallel and it is very important to understand what caused what. I want to suggest some tips that can make easier analysis of such log files. 1. First of all learn ALL logs AT THE BEGINNING of the event. It is very important to understand what process began first. You should understand the meaning of EVERY log here. 2. Unix tool awk could be very useful for logs files processing. Here are some simplest examples of its using. a) Cutting all logs of some definite type: awk '/PM189/,length < 2' inp_file > out_file ^ ^ | | Where: Pattern in the End condition first line of log of log (empty string) b) Cutting all lines BEFORE lines with some pattern: awk '/INV CLASS/{print str;next}{str=$0}' inp_file > out_file ^ ^ ^ ^ Where: | | | | | Output prev | Save full line Pattern line Go to next line c) Cutting all lines TWO lines BEFORE lines with some pattern: awk '/cp 35/{print str1;next}{str1=str;str=$0}' inp_file > out_file d) Prepare exec for site in the form: QDN dn QDN dn . . . awk '/ DN /{print "QDN " $8}' inp_file | sort | uniq > out_file ^ ^ Where: | | | Field number in line Selection pattern that contains dn 3. If you need to answer question like that: "What dn's that appear in logs of type A appear in logs of type B too ?" (For example, how many dn's that appear in AUDT203 logs appear in logs of TPTSWER cp 35 - inter integrity lost ?) you could use the next procedure: a) Use 2a) for cutting all AUDT203 logs into one file and cp 35 logs into another. b) Use 2d) for producing of sorted list of dn's from these two new files. c) Use tool comm in the form: comm dn_list1_file dn_list2_file > out_file and in the out_file you will see three columns - in the third one common dn's will appear. txt2html-2.53/tfiles/list-custom.txt000066400000000000000000000004141352116237600175500ustar00rootroot00000000000000Testing Different Bullets ========================= #) Is this an ordered list item? #) Because somebody did something. #) And added another! And then we'll have an unordered list. + with a pluss + as the new bullet, man. - and another indent, why not? + bask up txt2html-2.53/tfiles/list-styles.txt000066400000000000000000000037301352116237600175650ustar00rootroot00000000000000STRATEGISKA BESLUTSSTDSSYSTEM ============================== Syfte ===== Syftet med detta examensarbete r att studera vilka behov av beslutsunderlag som finns samt att i detta sammanhang underska vilka krav man br stlla p informationssystem fr beslutsstd. Avgrnsningar ============= Vi kommer endast att rikta in oss p stdet fr fretags strategiska beslut i samband med expansion p frmmande lnders marknader. Vi avser endast att studera dessa behov och krav ur beslutsfattarens synvinkel. Innehll ======== * Mnniskan - Beslutsprocessen - Perception - Lshastighet - Hur tolkas informationen - Parametermngd * Organisationen - Informationsfldet - Frndringar * Marknaden - Hur ser dagens informationssystem ut? - Effektivitet - Dagens tillvgagngsstt * Tekniken - Medium fr spridning - Statisk respektive dynamisk information - Databaser - Skerhet - Affrshemligheter - Agenter (robotar) Bakgrund ======== I dagens samhlle av allt intensivare produktion av information och ven behov av information mste beslutsfattarna allt snabbare fatta viktiga beslut. Med marknadernas utveckling mot allt snabbare faktorrrelser p det internationella planet mste ven de strategiska besluten ofta fattas mycket snabbt. Man mste trots detta skaffa sig ett adekvat beslutsunderlag, vilket naturligtvis tar en viss tid, tid som man kanske inte har! Beslutsfattare behver allts hjlp frn automatiserade verktyg. Frgor man stlls infr i detta sammanhang r bl.a. hur br beslutsunderlagen utformas och vilka krav br stllas p informationssystemen som frser beslutsfattarna med beslutsunderlagen. Tillvgagngsstt ================= Kvalitativ underskning genom intervjuer med fretags beslutsfattare p olika niver, frmst ansvariga fr internationella marknader. Kvantitativ studie genom att underska vidtagna tgrder vi olika fretags etableringar utomlands, samt frska relatera dessa till de uppndda resultaten och sedan jmfra med hemmamarknaden. txt2html-2.53/tfiles/list.txt000066400000000000000000000000371352116237600162410ustar00rootroot00000000000000 * foo ------- blah blah blah txt2html-2.53/tfiles/mixed.txt000066400000000000000000000005431352116237600163760ustar00rootroot00000000000000This is an example of mixed input, with a list with what shouldn't be bold. - The '#' character can be used to introduce comment lines. Comments and lines that are empty or contain only whitespace are ignored. - Pipe characters and newlines within fields and '#' at the begin of the first field of an entry must be escaped with a backslash ('\'). txt2html-2.53/tfiles/news.txt000066400000000000000000000275231352116237600162530ustar00rootroot00000000000000From: force10ten@some.where.com (Force10Ten) Newsgroups: alt.archery Subject: Re: Binocular Purchase - Advice Date: 14 Jan 1996 02:03:01 -0500 Reply-To: force10ten@some.where.com (Force10Ten) Because I'm looking for binoculars for use at the Olympic Games, I just spent quite a bit of time talking about this very subject with Jim Dougherty, Dave Myers, Jay Barrs and Dick Tone, all of whom have the opinion that the really good binoculars show their stuff in twilight. Myers told me this story at the Bowhunting Trade Show. He and his buddies were sheep hunting. There were 5 or 6 guys. One of them told the others "there's a sheep in this hollow" several hundred yards off. It was dusk. Nobody but this guy could see the sheep. Everybody had binoculars in the 100-300 dollar price range. Except this guy who had a set of Zeiss 10 x 50's. As he passed the glasses around every one of these guys could see the sheep perfectly clearly. Nobody could see it with the cheaper glasses. I chose a pair of Leica 10 x 42's for my task at the Olympics, which will be to do TV and venue play by play coverage of archery. I need to be able to call the arrows in the head-to-head instantly. These glasses are perfect for the job, which will really involve several weeks of looking through binoculars this year, what with test tournaments and my own shooting. My "A" list after shopping around is in the 700 to 1600 dollar price range as follows: 1. Leica 10 x 42 2. Bausch & Lomb Elite 10 x 42 3. Zeiss 10 x 42 4. Svarovski 5. Docter Optik george t. From: bowbuff@some.where.com (Bowbuff) Newsgroups: alt.archery Subject: Re: Binocular Purchase - Advice Date: 16 Jan 1996 06:37:05 -0500 Randy, just reread your question and it may be that the answers you received didn't answer your question about 8 vs 10 power in low light. Considering magnification alone the higher the power the worse it is likely to be in very low light. More important is the "exit pupil" of the binocs: The second number divided by the first. For example a 10x50 binoc has an exit pupil of 5, the same as a 7x35 or 8x40. This is the measure of light gathering ability of the unit. Ignoring power, quality of the optical elements, and lens coatings, an e.p. of 5 is the optimum. At least, I read somewhere that this is the maximum the human eye can process. All I know is that a top quality pair of 10x50, 8x40, or 7x35 glasses will pick up more light at dark than you can see with your naked eyes. Seriously, I was watching two bull elk fighting at dark in Rocky Mtn Nat'l Park and it became too dark to see them although they were in the open only 75 yards away. With my Swarovskis I could watch them for about another half hour when I got tired and gave up. The higher the e.p. the larger the binocs are physically, of course, as this means a bigger diameter exit lens and focal length as well. The lower the e.p., the worse your binocs will let you down in low light. This is why all the compacts are only useful during good light. The finest 8x24s or 10x25s will fit in your shirt pocket really neat....and you'll soon be leaving them there unless it is the middle of the day...or unless you really don't need to see very much. Optics and coatings are no less important for extended use, especially at very long ranges in the daylight. Unfortunately you cant sort this out by looking through them in a store or looking down the street in front of a store. The best way is to take them-and all the others you can beg, bum, or borrow out to the tallest mountain you know and compare them for hours, especially as it gets dark. The next best way is to follow the advice of the Rocky Mountain Bighorn Society: figure out what is the maximum you can spend on the finest optics - and then spend 25% more! Good Luck! From: abqkelly@some.where.netcom.com(John Kelly ) Newsgroups: alt.archery Subject: Re: Binocular Purchase - Warsaw Pact Binocs Date: 16 Jan 1996 16:52:11 GMT >Optics and coatings are no less important for extended use, especially at >very long ranges in the daylight. Unfortunately you cant sort this out by >looking through them in a store or looking down the street in front of a >store. I had an opportunity to compare Leica, Swarkkkovyjowskiiskiskzsky, Zeiss, and "Warsaw Pact" 8X50s last year at a Rockey Mt Elk Camp event. You CAN make certain interesting and useful appraisals in that sort of situation. For example, you can evaluate color and contrast. You can look right into backlit areas, right at objects next to bright lights in the trade show ceiling, and judge internal refraction, contrast, and glare. IMHO the Leicas "looked" prettiest overall, I'd have loved a pair, were I a successful cocaine dealer or Phil Gramm. But a bowhunting pal bought WARSAW PACT "cheapies" ($500..widely advertised in hunting magazines) there, since they were MUCH brighter (apparently the equivalent of maybe two f-stops) and more contrasty than ANY of the others (not to mention, ahem, AFFORDABLE). They were VASTLY SUPERIOR in those respects. In the woods I later found you can look into deep shadows and they are lit as if they were video amplified. You can look directly into scenes involving the setting sun and still see clearly, FAR better than with the naked eye. There IS one BIG drawback: everything is a sickly greenish orange or yellow. The damned things are color blind. Otherwise they are exceptional at picking out shapes, movement etc under extremely difficult lighting conditions. That is exactly what they were designed for, of course, being military equipment, not bird watching equipment. NOTHING looks pretty through them. Is that a sacrifice that makes sense? Hmmm. Maybe that depends on your reasons for hunting. I've got Pentax and Nikon, under $200ea, and they have to fill the bill for now. I'm waiting for money from heaven. Maybe I'll go for better Nikons. JK From: Perry Ratcliff Newsgroups: alt.archery Subject: Re: Binocular Purchase - Advice Date: Sun, 14 Jan 96 07:36:28 PDT > I plan on purchasing a new pair of binoculars next hunting season and > would like some help. Let me know what you like or dislike. Also can > anyone tell what difference I might expect between an 8X and 10X > binocular. How does light conditions affect either one? > I also have Swarovskis 10x50 but haven't used them for a couple of years because they are so heavy. I'm now using Pentax 12x42 binoculars and am extremely pleased with them. They are very light for the size and have good light gathering capabilities. They are nitrogen filled and have never fogged up on me. I believe they cost me around $300 and feel that they are an outstanding value. If you are on a more modest budget there are some very good compact binoculars in the $150 range. Make sure that they are nitrogen filled to prevent fogging in the rain. If you wear glasses make certain that the binoculars have a long eye relief or you will lose a lot of light through the binoculars. Good Luck, Perry From: ap941@some.where.ysu.edu (Mark W. Thurm) Newsgroups: alt.archery Subject: Re: Binocular Purchase - Advice Date: 16 Jan 1996 17:07:13 GMT Reply-To: ap941@some.where.ysu.edu (Mark W. Thurm) >I plan on purchasing a new pair of binoculars next hunting season and >would like some help. Let me know what you like or dislike. Also can >anyone tell what difference I might expect between an 8X and 10X >binocular. How does light conditions affect either one? I have a pair of Cabellas compacts, 8 power, nitrogen filled, long eye relief. For the money ($100) they're a good deal (IMHO). I've looked at Ziess, Swarvoski. Brunton, etc. and they were excellent but with my constrants (married with children) my wife wouldn't authorize er... I couldn't justfy the 6-10 times price diferential. A 10 power compact will not gather much light and will be harder to hold steady. I hunt in the west and the 8x has worked well fo me. MT -- It's not the bible that's filled with contradictions, It's our brains that are filled with them. J. Vernon McGee Newsgroups: alt.archery From: jwf20@some.where.ccc.amdahl.com (Jim Flenniken) Subject: Re: Binocular Purchase - Advice Date: Tue, 16 Jan 1996 18:14:09 GMT Randy Ross wrote: >I plan on purchasing a new pair of binoculars next hunting season and >would like some help. Let me know what you like or dislike. Also can >anyone tell what difference I might expect between an 8X and 10X >binocular. How does light conditions affect either one? >Thanks. >Randy Bushnell makes a pair of 'glasses on' binoculars that are _excellent_ for those of us that wear glasses. the long eye-relief is a blessing when scanning a field while wearing glasses and the price is about $125. From: Alex Hoover Newsgroups: alt.archery Subject: Re: Binocular Purchase - Advice Date: 16 Jan 1996 22:17:34 GMT I love my Pentax 10x24 UCF compact binocs. Small and lightweight, so I don't hesitate to take them everywhere. They are with me 100% of the time that I hunt. Bigger binocs are nicer, but can get in the way (especially if primary use will be while bowhunting). In the Fall 95 issue of the Gander Mountain catalog, the 10x cost $155, the 8x cost $140. There's some kind of formula about exit pupil that give guidelines on best magnification power. The gist is that unless you have a very large objective diameter (for the 10x24's, the objective is 24mm, which is relatively small), light will be transmitted bettter with a lower magnification. If I had it to do over, I would buy the Pentax compact binocs again, but I would get an 8x24 instead of 10x24. Regards, alex.hoover@some.where.com Denver, CO From: Alex Hoover Newsgroups: alt.archery Subject: Re: Binocular Purchase - Advice Date: 16 Jan 1996 22:18:10 GMT I love my Pentax 10x24 UCF compact binocs. Small and lightweight, so I don't hesitate to take them everywhere. They are with me 100% of the time that I hunt. Bigger binocs are nicer, but can get in the way (especially if primary use will be while bowhunting). In the Fall 95 issue of the Gander Mountain catalog, the 10x cost $155, the 8x cost $140. There's some kind of formula about exit pupil that give guidelines on best magnification power. The gist is that unless you have a very large objective diameter (for the 10x24's, the objective is 24mm, which is relatively small), light will be transmitted bettter with a lower magnification. If I had it to do over, I would buy the Pentax compact binocs again, but I would get an 8x24 instead of 10x24. Regards, alex.hoover@some.where.com Denver, CO From: Alex Hoover Newsgroups: alt.archery Subject: Re: Binocular Purchase - Advice Date: 16 Jan 1996 22:18:19 GMT I love my Pentax 10x24 UCF compact binocs. Small and lightweight, so I don't hesitate to take them everywhere. They are with me 100% of the time that I hunt. Bigger binocs are nicer, but can get in the way (especially if primary use will be while bowhunting). In the Fall 95 issue of the Gander Mountain catalog, the 10x cost $155, the 8x cost $140. There's some kind of formula about exit pupil that give guidelines on best magnification power. The gist is that unless you have a very large objective diameter (for the 10x24's, the objective is 24mm, which is relatively small), light will be transmitted bettter with a lower magnification. If I had it to do over, I would buy the Pentax compact binocs again, but I would get an 8x24 instead of 10x24. Regards, alex.hoover@some.where.com Denver, CO The following should be treated as mail quote, not as pre-formatted > 1 more > 2 more > 3 more > 4 more > 5 more Back to normal again. more and more, make it a long line, not a short one. > 1 more and more, make it a long line, not a short one. > 2 more and more, make it a long line, not a short one. > 3 more and more, make it a long line, not a short one. txt2html-2.53/tfiles/pre.txt000066400000000000000000000006011352116237600160510ustar00rootroot00000000000000## Test on pre-in-list txt2html.pl -p 7 -pb 1 Here is an example bad file: 1. text (should be translated as
  • ) (there should be *no* tag at this point) preformatted text.. ... and more 2. this *should* be translated as
  • ## Test on mail_quote-in-pre_explicit
    Here is the actuall file content. 
    Maybe more lines.
    > 1	 more
    > 2	 more
    
    txt2html-2.53/tfiles/pre2.txt000066400000000000000000000001711352116237600161350ustar00rootroot00000000000000This is a text file. The text file ends with a block of preformatted text. This is the end of the file. txt2html-2.53/tfiles/punct.txt000066400000000000000000000015301352116237600164160ustar00rootroot00000000000000*Why do I keep on having these bright ideas?* Miles wondered as he crawled through the service tunnel. It gave him uncomfortable flashbacks to the time he'd crawled through the ducting on Aslund station. Though at least this time he didn't have Gregor to worry about. No, just lizard things, and the Doctor. Now there was an unknown quantity. Sharp, yes, and knew too much about the wrong things, but... *You are supposed to be a good judge of character, Miles,* he thought to himself. *It's a bit late to be second-guessing now.* Miles sat up straighter in the chair and checked the settings again. The earbud in his ear had warmed to body-temperature, but it was still a hard lump. Part of him was gibbering *Aliens! You're going to be talking to aliens!* while another part of him was just getting impatient, waiting for the Doctor to return. txt2html-2.53/tfiles/robo.txt000066400000000000000000000026651352116237600162400ustar00rootroot00000000000000Type: cmu.cs.robotics Topic: Robotics Seminar, Prof. John Canny, Friday Oct 11, 3:30, Adamson Wing, Baker Hall Dates: 11-Oct-91 Time: 3:30 Place: Adamson Wing, Baker Hall PostedBy: me on 11-Oct-91 at 01:39 from H.GP.CS.CMU.EDU (Michael Erdmann) Abstract: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ***** Friendly Reminder: Robotics Seminar Today!! ***** ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Date: 11-Oct-91 Time: 3:30 (Refreshments at 3:15) Place: Adamson Wing, Baker Hall RISC-Robotics John Canny U.C. Berkeley RISC in a robotics context stands for Reduced Intricacy in Sensing and Control. But it shares the same philosophy as RISC computer design. The idea is to replace complicated manipulation and sensing steps with combinations of simple ones. Industrial robotics research has focussed on anthropomorphism in the hope that once robots become sufficiently human-like, they will be able to solve all the tasks that they are currently incapable of doing. This approach is seductive and has led researchers further and further away from the real problems that hinder the proliferation of robots in manufacturing. The enthusiasm for robotics in industry which reached a peak in the mid 80's has all but disappeared after a protracted lack of progress on these problems. txt2html-2.53/tfiles/sample.foot000066400000000000000000000001121352116237600166710ustar00rootroot00000000000000
    KatSpace
    txt2html-2.53/tfiles/sample.foot2000066400000000000000000000001131352116237600167540ustar00rootroot00000000000000
    KatSpace
    txt2html-2.53/tfiles/sample.txt000066400000000000000000000222501352116237600165500ustar00rootroot00000000000000txt2html/HTML::TextToHTML Sample Conversion This sample is based hugely on the original sample.txt produced by Seth Golub for txt2html. I used the following options to convert this document: -titlefirst -mailmode -make_tables --custom_heading_regexp '^ *--[\w\s]+-- *$' --system_link_dict txt2html.dict --append_body sample.foot --infile sample.txt --outfile sample.html This has either been done at the command line with: perl -MHTML::TextToHTML -e run_txt2html -- *options* or using the script txt2html *options* or from a (test) perl script with: use HTML::TextToHTML; my $conv = new HTML::TextToHTML(); $conv->txt2html([*options*]); ====================================================================== From bozo@clown.wustl.edu Return-Path: Message-Id: <9405102200.AA04736@clown.wustl.edu> Content-Length: 1070 From: bozo@clown.wustl.edu (Bozo the Clown) To: kitty@example.com (Kathryn Andersen) Subject: Re: HTML::TextToHTML Date: Sun, 12 May 2002 10:01:10 -0500 Bozo wrote: BtC> Can you post an example text file with its html'ed output? BtC> That would provide a much better first glance at what it does BtC> without having to look through and see what the perl code does. Good idea. I'll write something up. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- The header lines were kept separate because they looked like mail headers and I have mailmode on. The same thing applies to Bozo's quoted text. Mailmode doesn't screw things up very often, but since most people are usually converting non-mail, it's off by default. Paragraphs are handled ok. In fact, this one is here just to demonstrate that. THIS LINE IS VERY IMPORTANT! (Ok, it wasn't *that* important) EXAMPLE HEADER ============== Since this is the first header noticed (all caps, underlined with an "="), it will be a level 1 header. It gets an anchor named "section_1". Another example =============== This is the second type of header (not all caps, underlined with "="). It gets an anchor named "section_1_1". Yet another example =================== This header was in the same style, so it was assigned the same header tag. Note the anchor names in the HTML. (You probably can't see them in your current document view.) Its anchor is named "section_1_2". Get the picture? -- This is a custom header -- You can define your own custom header patterns if you know what your documents look like. Features of HTML::TextToHTML ============================ * Handles different kinds of lists 1. Bulleted 2. Numbered - You can nest them as far as you want. - It's pretty decent about figuring out which level of list it is supposed to be on. - You don't need to change bullet markers to start a new list. 3. Lettered A. Finally handles lettered lists B. Upper and lower case both work a) Here's an example b) I've been meaning to add this for some time. C. HTML without CSS can't specify how ordered lists should be indicated, so it will be a numbered list in most browsers. 4. Definition lists (see below) * Doesn't screw up mail-ish things * Spots preformated text It just needs to have enough whitespace in the line. Surrounding blank lines aren't necessary. If it sees enough whitespace in a line, it preformats it. How much is enough? Set it yourself at command line if you want. * You can append a file automatically to all converted files. This is handy for adding signatures to your documents. * Deals with paragraphs decently. Looks for short lines in the middle of paragraphs and keeps them short with the use of breaks (
    ). How short the lines need to be is configurable. Unhyphenates split words that are in the middle of para- graphs. Let me know if trailing punctuation isn't handled "prop- erly". It should be. One can also have multi-paragraph list items, like this one. * Puts anchors at all headers and, if you're using the mail header features, at the beginning of each mail message. The anchor names for headings are based on guessed section numbers. - You can turn off this option too, if you don't like it. * Groks Mosaic-style "formatted text" headers (like the one below) * Can hyperlink things according to a dictionary file. The sample dictionary handles URLs like http://www.aigeek.com/ and and also shows how to do simpler things such as linking the word txt2html the first time it appeared. * One can also use the link-dictionary to define custom tags, for example using the star character to indicate *italics*. * Recognises and parses tables of different types: o DELIM: A table determined by delimiters. o ALIGN: No need for fancy delimiters, this figures out a table by looking at the layout, the spacing of the cells. o BORDER: has a nice border around the table o PGSQL: the same format as Postgresql query results. * Also with XHTML! Turn on the --xhtml option and it will ensure that all paragraphs and list items have end-tags, all tags are in lower-case, and the doctype is for XHTML. Example of short lines ---------------------- We're the knights of the round table We dance whene'er we're able We do routines and chorus scenes With footwork impeccable. We dine well here in Camelot We eat ham and jam and spam a lot. Example of varied formatting ---------------------------- If I want to *emphasize* something, then I'd use stars to wrap around the words, *even if there were more than one*, *that's* what I'd do. But I could also _underline_ words, so long as the darn thing was not a_variable_name, in which case I wouldn't want to lose the underscores in something which thought it was underlining. Though we might want to _underline more than one word_ in a sentence. Especially if it is _The Title Of A Book_. For another kind of emphasis, let's go and #put something in bold#. But it doesn't even need to be that simple. Something which is *really exciting* is coping with italics and similar things *spread across multiple lines*. Example of Long Preformatting ----------------------------- (extract from Let It Rain by Kristen Hall) I have given, I have given and got none Still I'm driven by something I can't explain It's not a cross, it is a choice I cannot help but hear his voice I only wish that I could listen without shame Let it rain, let it rain, on me Let it rain, oh let it rain, Let it rain, on me I have been a witness to the perfect crime Wipe the grin off of my face to hide the pain It isn't worth the tears you cry To have a perfect alibi Now I'm beaten at the hands of my own game Let it rain, let it rain, on me Let it rain, oh let it rain, Let it rain, on me Definition Lists ---------------- A definition list comprises the following: Term: The term part of a DL item is a word on a line by itself, ending with a colon. Definition: The definition part of a DL item is at least one paragraph following the term. If one has more than one paragraph in the definition, the first line of the next paragraph needs to be indented two spaces from where the term starts, otherwise we don't know that it belongs to the definition. Examples of Tables ------------------ ALIGN ~~~~~ Here is a simple ALIGN table: -e File exists. -z File has zero size. -s File has nonzero size (returns size). Here are some of the conditions of ALIGN tables: #Context:# A table needs to be surrounded by blank lines. #Length:# A table must contain at least two rows. #Width:# A table must contain at least two columns. #Spacing:# There needs to be at least two spaces between the columns, otherwise there might be some random paragraph which could have inter-word spacing that lined up by accident. #Cell Size:# If you have more than one line (as just above) then you will simply get empty cells where the other column is empty. #Alignment:# Alignment of cells is attempted to be preserved. BORDER ~~~~~~ This is a table with a border. +---------+-----+ | Food | Qty | +---------+-----+ | Bread | 1 | | Milk | 1 | | Oranges | 3 | | Apples | 6 | +---------+-----+ PGSQL ~~~~~~ This is the same table like Postgresql would make it. Food | Qty ---------+----- Bread | 1 Milk | 1 Oranges | 3 Apples | 6 (4 rows) DELIM ~~~~~ A delimited table needs to have its delimiters at the start and end, just to be sure that this is a table. :Fred:Nurk:58: :George:Washington:62: :Mary:Quant:35: And one can have almost any delimiter one wishes. | Darcy, Fitzwilliam | hero | | Bennet, Elizabeth | heroine | | Wickham, George | villain | THINGS TO DO ============ There are some things which this module doesn't handle yet which I would like to implement. A. I would like to be able to preserve lettered lists, that is: a) recognise that they are letters and not numbers (which it already does) b) display the correct OL properties with CSS so as to preserve that information. ---------------------------------------- The footer is everything from the end of this sentence to the tag. txt2html-2.53/tfiles/table-align.txt000066400000000000000000000005401352116237600174440ustar00rootroot00000000000000This is for testing a table which is regognised by its alignment. Fruit Vegetable Banana Carrot Apple Celery The following is not a table because there aren't enough spaces between items. Fred Nurk ate Mary Norton slept Hugh Jackman snarled But this one is. Fred Nurk ate Mary Norton slept Hugh Jackman snarled txt2html-2.53/tfiles/table-border.txt000066400000000000000000000033711352116237600176340ustar00rootroot00000000000000+--------+-----------------------+----------+-------+ | Schema | Name | Type | Owner | +--------+-----------------------+----------+-------+ | public | actor_episodes | view | kat | | public | actors | table | kat | | public | copyable | view | kat | | public | episode_recording | view | kat | | public | episodes | table | kat | | public | episodes_title_id_seq | sequence | kat | | public | pal_recordings | view | kat | | public | recordings | table | kat | | public | sorted_eps | view | kat | | public | tapes | table | kat | | public | unrecorded | view | kat | | public | wanting | view | kat | +--------+-----------------------+----------+-------+ And the same table could be indented. +--------+-----------------------+----------+-------+ | Schema | Name | Type | Owner | +--------+-----------------------+----------+-------+ | public | actor_episodes | view | kat | | public | actors | table | kat | | public | copyable | view | kat | | public | episode_recording | view | kat | | public | episodes | table | kat | | public | episodes_title_id_seq | sequence | kat | | public | pal_recordings | view | kat | | public | recordings | table | kat | | public | sorted_eps | view | kat | | public | tapes | table | kat | | public | unrecorded | view | kat | | public | wanting | view | kat | +--------+-----------------------+----------+-------+ txt2html-2.53/tfiles/table-delim.txt000066400000000000000000000021721352116237600174470ustar00rootroot00000000000000Delimited Table =============== This one was a border table from which I removed the divider lines. | Schema | Name | Type | Owner | | public | actor_episodes | view | kat | | public | actors | table | kat | | public | copyable | view | kat | | public | episode_recording | view | kat | | public | episodes | table | kat | | public | episodes_title_id_seq | sequence | kat | | public | pal_recordings | view | kat | | public | recordings | table | kat | | public | sorted_eps | view | kat | | public | tapes | table | kat | | public | unrecorded | view | kat | | public | wanting | view | kat | And this is a homegrown one. :Fred:Nurk:lives: :Kerr:Avon:is wonderfule: ::Servalan:has no first name: And the next one has a caption, and a possibly tricky delimiter. Actors & Paul & Darrow & & Jackie & Pierce & Note that a CSV table doesn't work for delimiter stuff, because it isn't *bounded* by commas. Fred,Nurk Joe,Schmoe txt2html-2.53/tfiles/table-pgsql.txt000066400000000000000000000013421352116237600175010ustar00rootroot00000000000000 List of relations Schema | Name | Type | Owner --------+-----------------------+----------+------- public | actor_episodes | view | kat public | actors | table | kat public | copyable | view | kat public | episode_recording | view | kat public | episodes | table | kat public | episodes_title_id_seq | sequence | kat public | pal_recordings | view | kat public | recordings | table | kat public | sorted_eps | view | kat public | tapes | table | kat public | unrecorded | view | kat public | wanting | view | kat (12 rows) txt2html-2.53/tfiles/table-pgsql2.txt000066400000000000000000000653061352116237600175750ustar00rootroot00000000000000 title | sub_title | title_id | category | series_title | episode_position | season | season_position | episode_code | wanting ------------------------------------------------------------------+--------------------------------+----------+--------------+--------------------------------+------------------+--------+-----------------+--------------+--------- Gathering, The | | 687 | SERIES | Highlander | 1 | 1 | 1 | | Innocent Man | | 689 | SERIES | Highlander | 2 | 1 | 2 | | Road Not Taken | | 694 | SERIES | Highlander | 3 | 1 | 3 | | Bad Day In Building A | | 677 | SERIES | Highlander | 4 | 1 | 4 | | Free Fall | | 686 | SERIES | Highlander | 5 | 1 | 5 | | Deadly Medicine | | 680 | SERIES | Highlander | 6 | 1 | 6 | | Mountain Men | | 691 | SERIES | Highlander | 7 | 1 | 7 | | Revenge Is Sweet | | 693 | SERIES | Highlander | 8 | 1 | 8 | | Sea Witch, The | | 696 | SERIES | Highlander | 9 | 1 | 9 | | Eye Witness | | 681 | SERIES | Highlander | 10 | 1 | 10 | | Family Tree | | 683 | SERIES | Highlander | 11 | 1 | 11 | | See No Evil | | 697 | SERIES | Highlander | 12 | 1 | 12 | | Band of Brothers | | 678 | SERIES | Highlander | 13 | 1 | 13 | | For Evil's Sake | | 684 | SERIES | Highlander | 14 | 1 | 14 | | For Tomorrow We Die | | 685 | SERIES | Highlander | 15 | 1 | 15 | | Beast Below, The | | 679 | SERIES | Highlander | 16 | 1 | 16 | | Saving Grace | | 695 | SERIES | Highlander | 17 | 1 | 17 | | Lady and the Tiger, The | | 690 | SERIES | Highlander | 18 | 1 | 18 | | Avenging Angel | | 676 | SERIES | Highlander | 19 | 1 | 19 | | Eye of the Beholder | | 682 | SERIES | Highlander | 20 | 1 | 20 | | Nowhere To Run | | 692 | SERIES | Highlander | 21 | 1 | 21 | | Hunters, The | | 688 | SERIES | Highlander | 22 | 1 | 22 | | Watchers, The | | 698 | SERIES | Highlander | 23 | 2 | 1 | | Studies in Light | | 2820 | SERIES | Highlander | 24 | 2 | 2 | | Turnabout | | 2821 | SERIES | Highlander | 25 | 2 | 3 | | Darkness, The | | 2822 | SERIES | Highlander | 26 | 2 | 4 | | Eye For An Eye | | 2823 | SERIES | Highlander | 27 | 2 | 5 | | Zone, The | | 2824 | SERIES | Highlander | 28 | 2 | 6 | | Return of Amanda, The | | 2825 | SERIES | Highlander | 29 | 2 | 7 | | Revenge of The Sword | | 2826 | SERIES | Highlander | 30 | 2 | 8 | | Run For Your Life | | 2827 | SERIES | Highlander | 31 | 2 | 9 | | Epitaph For Tommy | | 2828 | SERIES | Highlander | 32 | 2 | 10 | | Bless The Child | | 2829 | SERIES | Highlander | 33 | 2 | 11 | | Fighter, The | | 2830 | SERIES | Highlander | 34 | 2 | 12 | | Under Color of Authority | | 2831 | SERIES | Highlander | 35 | 2 | 13 | | Unholy Alliance (1) | | 2832 | SERIES | Highlander | 36 | 2 | 14 | | Unholy Alliance (2) | | 2833 | SERIES | Highlander | 37 | 2 | 15 | | Vampire, The | | 2834 | SERIES | Highlander | 38 | 2 | 16 | | Warmonger | | 2835 | SERIES | Highlander | 39 | 2 | 17 | | Pharaoh's Daughter | | 2836 | SERIES | Highlander | 40 | 2 | 18 | | Legacy | | 2837 | SERIES | Highlander | 41 | 2 | 19 | | Prodigal Son | | 2838 | SERIES | Highlander | 42 | 2 | 20 | | Counterfeit (1) | | 2839 | SERIES | Highlander | 43 | 2 | 21 | | Counterfiet (2) | | 2840 | SERIES | Highlander | 44 | 2 | 22 | | Samurai, The | | 2875 | SERIES | Highlander | 45 | 3 | 1 | | Line of Fire | | 2876 | SERIES | Highlander | 46 | 3 | 2 | | Revolutionary, The | | 2877 | SERIES | Highlander | 47 | 3 | 3 | | Cross of St. Antoine | | 2878 | SERIES | Highlander | 48 | 3 | 4 | | Rite of Passage | | 2879 | SERIES | Highlander | 49 | 3 | 5 | | Courage | | 2880 | SERIES | Highlander | 50 | 3 | 6 | | Lamb, The | | 2881 | SERIES | Highlander | 51 | 3 | 7 | | Obsession | | 2882 | SERIES | Highlander | 52 | 3 | 8 | | Shadows | | 2883 | SERIES | Highlander | 53 | 3 | 9 | | Blackmail | Swords, Lies & Videotape | 2884 | SERIES | Highlander | 54 | 3 | 10 | | Vendetta | | 2885 | SERIES | Highlander | 55 | 3 | 11 | | They Also Serve | | 2886 | SERIES | Highlander | 56 | 3 | 12 | | Blind Faith | | 2887 | SERIES | Highlander | 57 | 3 | 13 | | Song of the Executioner | | 3002 | SERIES | Highlander | 58 | 3 | 14 | | Star Crossed | | 3003 | SERIES | Highlander | 59 | 3 | 15 | | Methos | | 3004 | SERIES | Highlander | 60 | 3 | 16 | | Take Back the Night | | 3005 | SERIES | Highlander | 61 | 3 | 17 | | Testimony | | 3006 | SERIES | Highlander | 62 | 3 | 18 | | Mortal Sins | | 3007 | SERIES | Highlander | 63 | 3 | 19 | | Reasonable Doubt | | 3163 | SERIES | Highlander | 0 | 3 | 20 | | Finale | | 3164 | SERIES | Highlander | 0 | 3 | 21 | | Finale II | | 3165 | SERIES | Highlander | 0 | 3 | 22 | | Homeland | | 3166 | SERIES | Highlander | 0 | 4 | 1 | | Brothers In Arms | | 3167 | SERIES | Highlander | 0 | 4 | 2 | | Innocent, The | | 3168 | SERIES | Highlander | 0 | 4 | 3 | | Leader of the Pack | | 3169 | SERIES | Highlander | 0 | 4 | 4 | | Double Eagle | | 3170 | SERIES | Highlander | 0 | 4 | 5 | | Reunion | | 3171 | SERIES | Highlander | 0 | 4 | 6 | | Colonel, The | | 3172 | SERIES | Highlander | 0 | 4 | 7 | | Reluctant Heroes | | 3173 | SERIES | Highlander | 0 | 4 | 8 | | Wrath of Kali, The | | 3174 | SERIES | Highlander | 0 | 4 | 9 | | Chivalry | | 3175 | SERIES | Highlander | 0 | 4 | 10 | | Timeless | | 3176 | SERIES | Highlander | 0 | 4 | 11 | | Blitz, The | | 3177 | SERIES | Highlander | 0 | 4 | 12 | | Something Wicked | Hakoya | 3261 | SERIES | Highlander | 0 | 4 | 13 | | Deliverance | Leap of Faith | 3262 | SERIES | Highlander | 0 | 4 | 14 | | Promises | | 3180 | SERIES | Highlander | 0 | 4 | 15 | | Methuselah's Gift | | 3426 | SERIES | Highlander | 0 | 4 | 16 | | Immortal Cimoli, The | | 3263 | SERIES | Highlander | 0 | 4 | 17 | | Through a Glass Darkly | | 3427 | SERIES | Highlander | 0 | 4 | 18 | | Double Jeopardy | | 3453 | SERIES | Highlander | 0 | 4 | 19 | | Till Death | | 3428 | SERIES | Highlander | 0 | 4 | 20 | | Judgement Day | | 3429 | SERIES | Highlander | 0 | 4 | 21 | | One Minute To Midnight | | 3430 | SERIES | Highlander | 0 | 4 | 22 | | Prophecy | | 3454 | SERIES | Highlander | 0 | 5 | 1 | | End of Innocence, The | | 3455 | SERIES | Highlander | 0 | 5 | 2 | | Manhunt | | 3456 | SERIES | Highlander | 0 | 5 | 3 | | Glory Days | | 3457 | SERIES | Highlander | 0 | 5 | 4 | | Dramatic Licence | | 3458 | SERIES | Highlander | 0 | 5 | 5 | | Money's No Object | | 3459 | SERIES | Highlander | 0 | 5 | 6 | | Haunted | | 3460 | SERIES | Highlander | 0 | 5 | 7 | | Little Tin God | | 3461 | SERIES | Highlander | 0 | 5 | 8 | | Messenger, The | | 3462 | SERIES | Highlander | 0 | 5 | 9 | | Valkyrie, The | | 3463 | SERIES | Highlander | 0 | 5 | 10 | | Comes A Horseman | | 3464 | SERIES | Highlander | 0 | 5 | 11 | | Revelations 6:8 | | 3465 | SERIES | Highlander | 0 | 5 | 12 | | Ransom of Richard Redstone, The | | 3466 | SERIES | Highlander | 0 | 5 | 13 | | Duende | | 3467 | SERIES | Highlander | 0 | 5 | 14 | | Stone of Scone, The | | 3468 | SERIES | Highlander | 0 | 5 | 15 | | Forgive Us Our Trespasses | | 3469 | SERIES | Highlander | 0 | 5 | 16 | | Modern Prometheus, The | | 3470 | SERIES | Highlander | 0 | 5 | 17 | | Archangel | | 3471 | SERIES | Highlander | 0 | 5 | 18 | | Avatar | | 3624 | SERIES | Highlander | 0 | 6 | 1 | | Armageddon | | 3625 | SERIES | Highlander | 0 | 6 | 2 | | Sins of the Father | | 3626 | SERIES | Highlander | 0 | 6 | 3 | | Diplomatic Immunity | | 3888 | SERIES | Highlander | 0 | 6 | 4 | | Patient Number 7 | | 3889 | SERIES | Highlander | 0 | 6 | 5 | | Black Tower | | 3936 | SERIES | Highlander | 0 | 6 | 6 | | Unusual Suspects | | 3904 | SERIES | Highlander | 0 | 6 | 7 | | Justice | | 3905 | SERIES | Highlander | 0 | 6 | 8 | | Deadly Exposure | | 3906 | SERIES | Highlander | 0 | 6 | 9 | | Two of Hearts | | 3937 | SERIES | Highlander | 0 | 6 | 10 | | Indiscretions | | 3938 | SERIES | Highlander | 0 | 6 | 11 | | To Be | | 3939 | SERIES | Highlander | 0 | 6 | 12 | | Not To Be | | 3940 | SERIES | Highlander | 0 | 6 | 13 | | Highlander | | 3105 | MOVIE | Highlander | 0 | | 0 | | bloopers | | 3523 | SERIES | Highlander | 0 | | 0 | | (121 rows) txt2html-2.53/tfiles/umlauttest.txt000066400000000000000000000002731352116237600174770ustar00rootroot00000000000000Es geht darum, sie zu *verndern* zu *ndern* zu *ndern*. Es geht darum, sie zu #verndern# zu #ndern# zu #ndern#. Es _geht_ darum, sie zu _verndern_ zu _ndern_ zu _ndern_. NDERN txt2html-2.53/tfiles/utf8.txt000066400000000000000000000001461352116237600161550ustar00rootroot00000000000000Some UTF-8 characters ===================== $ echo 門牌號碼規劃 Perhaps just tip of iceberg.